14511 lines
		
	
	
		
			460 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			14511 lines
		
	
	
		
			460 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- EmulateInstructionARM.cpp -----------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "EmulateInstructionARM.h"
 | |
| #include "EmulationStateARM.h"
 | |
| #include "lldb/Core/Address.h"
 | |
| #include "lldb/Core/PluginManager.h"
 | |
| #include "lldb/Host/PosixApi.h"
 | |
| #include "lldb/Interpreter/OptionValueArray.h"
 | |
| #include "lldb/Interpreter/OptionValueDictionary.h"
 | |
| #include "lldb/Symbol/UnwindPlan.h"
 | |
| #include "lldb/Utility/ArchSpec.h"
 | |
| #include "lldb/Utility/ConstString.h"
 | |
| #include "lldb/Utility/Stream.h"
 | |
| 
 | |
| #include "Plugins/Process/Utility/ARMDefines.h"
 | |
| #include "Plugins/Process/Utility/ARMUtils.h"
 | |
| #include "Utility/ARM_DWARF_Registers.h"
 | |
| 
 | |
| #include "llvm/ADT/STLExtras.h"
 | |
| #include "llvm/Support/MathExtras.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM, InstructionARM)
 | |
| 
 | |
| // Convenient macro definitions.
 | |
| #define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS)
 | |
| #define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS)
 | |
| 
 | |
| #define AlignPC(pc_val) (pc_val & 0xFFFFFFFC)
 | |
| 
 | |
| //
 | |
| // ITSession implementation
 | |
| //
 | |
| 
 | |
| static bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo ®_info) {
 | |
|   ::memset(®_info, 0, sizeof(RegisterInfo));
 | |
|   ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
 | |
| 
 | |
|   if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
 | |
|     reg_info.byte_size = 16;
 | |
|     reg_info.format = eFormatVectorOfUInt8;
 | |
|     reg_info.encoding = eEncodingVector;
 | |
|   }
 | |
| 
 | |
|   if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) {
 | |
|     reg_info.byte_size = 8;
 | |
|     reg_info.format = eFormatFloat;
 | |
|     reg_info.encoding = eEncodingIEEE754;
 | |
|   } else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) {
 | |
|     reg_info.byte_size = 4;
 | |
|     reg_info.format = eFormatFloat;
 | |
|     reg_info.encoding = eEncodingIEEE754;
 | |
|   } else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) {
 | |
|     reg_info.byte_size = 12;
 | |
|     reg_info.format = eFormatFloat;
 | |
|     reg_info.encoding = eEncodingIEEE754;
 | |
|   } else {
 | |
|     reg_info.byte_size = 4;
 | |
|     reg_info.format = eFormatHex;
 | |
|     reg_info.encoding = eEncodingUint;
 | |
|   }
 | |
| 
 | |
|   reg_info.kinds[eRegisterKindDWARF] = reg_num;
 | |
| 
 | |
|   switch (reg_num) {
 | |
|   case dwarf_r0:
 | |
|     reg_info.name = "r0";
 | |
|     break;
 | |
|   case dwarf_r1:
 | |
|     reg_info.name = "r1";
 | |
|     break;
 | |
|   case dwarf_r2:
 | |
|     reg_info.name = "r2";
 | |
|     break;
 | |
|   case dwarf_r3:
 | |
|     reg_info.name = "r3";
 | |
|     break;
 | |
|   case dwarf_r4:
 | |
|     reg_info.name = "r4";
 | |
|     break;
 | |
|   case dwarf_r5:
 | |
|     reg_info.name = "r5";
 | |
|     break;
 | |
|   case dwarf_r6:
 | |
|     reg_info.name = "r6";
 | |
|     break;
 | |
|   case dwarf_r7:
 | |
|     reg_info.name = "r7";
 | |
|     reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
 | |
|     break;
 | |
|   case dwarf_r8:
 | |
|     reg_info.name = "r8";
 | |
|     break;
 | |
|   case dwarf_r9:
 | |
|     reg_info.name = "r9";
 | |
|     break;
 | |
|   case dwarf_r10:
 | |
|     reg_info.name = "r10";
 | |
|     break;
 | |
|   case dwarf_r11:
 | |
|     reg_info.name = "r11";
 | |
|     break;
 | |
|   case dwarf_r12:
 | |
|     reg_info.name = "r12";
 | |
|     break;
 | |
|   case dwarf_sp:
 | |
|     reg_info.name = "sp";
 | |
|     reg_info.alt_name = "r13";
 | |
|     reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
 | |
|     break;
 | |
|   case dwarf_lr:
 | |
|     reg_info.name = "lr";
 | |
|     reg_info.alt_name = "r14";
 | |
|     reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
 | |
|     break;
 | |
|   case dwarf_pc:
 | |
|     reg_info.name = "pc";
 | |
|     reg_info.alt_name = "r15";
 | |
|     reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
 | |
|     break;
 | |
|   case dwarf_cpsr:
 | |
|     reg_info.name = "cpsr";
 | |
|     reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
 | |
|     break;
 | |
| 
 | |
|   case dwarf_s0:
 | |
|     reg_info.name = "s0";
 | |
|     break;
 | |
|   case dwarf_s1:
 | |
|     reg_info.name = "s1";
 | |
|     break;
 | |
|   case dwarf_s2:
 | |
|     reg_info.name = "s2";
 | |
|     break;
 | |
|   case dwarf_s3:
 | |
|     reg_info.name = "s3";
 | |
|     break;
 | |
|   case dwarf_s4:
 | |
|     reg_info.name = "s4";
 | |
|     break;
 | |
|   case dwarf_s5:
 | |
|     reg_info.name = "s5";
 | |
|     break;
 | |
|   case dwarf_s6:
 | |
|     reg_info.name = "s6";
 | |
|     break;
 | |
|   case dwarf_s7:
 | |
|     reg_info.name = "s7";
 | |
|     break;
 | |
|   case dwarf_s8:
 | |
|     reg_info.name = "s8";
 | |
|     break;
 | |
|   case dwarf_s9:
 | |
|     reg_info.name = "s9";
 | |
|     break;
 | |
|   case dwarf_s10:
 | |
|     reg_info.name = "s10";
 | |
|     break;
 | |
|   case dwarf_s11:
 | |
|     reg_info.name = "s11";
 | |
|     break;
 | |
|   case dwarf_s12:
 | |
|     reg_info.name = "s12";
 | |
|     break;
 | |
|   case dwarf_s13:
 | |
|     reg_info.name = "s13";
 | |
|     break;
 | |
|   case dwarf_s14:
 | |
|     reg_info.name = "s14";
 | |
|     break;
 | |
|   case dwarf_s15:
 | |
|     reg_info.name = "s15";
 | |
|     break;
 | |
|   case dwarf_s16:
 | |
|     reg_info.name = "s16";
 | |
|     break;
 | |
|   case dwarf_s17:
 | |
|     reg_info.name = "s17";
 | |
|     break;
 | |
|   case dwarf_s18:
 | |
|     reg_info.name = "s18";
 | |
|     break;
 | |
|   case dwarf_s19:
 | |
|     reg_info.name = "s19";
 | |
|     break;
 | |
|   case dwarf_s20:
 | |
|     reg_info.name = "s20";
 | |
|     break;
 | |
|   case dwarf_s21:
 | |
|     reg_info.name = "s21";
 | |
|     break;
 | |
|   case dwarf_s22:
 | |
|     reg_info.name = "s22";
 | |
|     break;
 | |
|   case dwarf_s23:
 | |
|     reg_info.name = "s23";
 | |
|     break;
 | |
|   case dwarf_s24:
 | |
|     reg_info.name = "s24";
 | |
|     break;
 | |
|   case dwarf_s25:
 | |
|     reg_info.name = "s25";
 | |
|     break;
 | |
|   case dwarf_s26:
 | |
|     reg_info.name = "s26";
 | |
|     break;
 | |
|   case dwarf_s27:
 | |
|     reg_info.name = "s27";
 | |
|     break;
 | |
|   case dwarf_s28:
 | |
|     reg_info.name = "s28";
 | |
|     break;
 | |
|   case dwarf_s29:
 | |
|     reg_info.name = "s29";
 | |
|     break;
 | |
|   case dwarf_s30:
 | |
|     reg_info.name = "s30";
 | |
|     break;
 | |
|   case dwarf_s31:
 | |
|     reg_info.name = "s31";
 | |
|     break;
 | |
| 
 | |
|   // FPA Registers 0-7
 | |
|   case dwarf_f0:
 | |
|     reg_info.name = "f0";
 | |
|     break;
 | |
|   case dwarf_f1:
 | |
|     reg_info.name = "f1";
 | |
|     break;
 | |
|   case dwarf_f2:
 | |
|     reg_info.name = "f2";
 | |
|     break;
 | |
|   case dwarf_f3:
 | |
|     reg_info.name = "f3";
 | |
|     break;
 | |
|   case dwarf_f4:
 | |
|     reg_info.name = "f4";
 | |
|     break;
 | |
|   case dwarf_f5:
 | |
|     reg_info.name = "f5";
 | |
|     break;
 | |
|   case dwarf_f6:
 | |
|     reg_info.name = "f6";
 | |
|     break;
 | |
|   case dwarf_f7:
 | |
|     reg_info.name = "f7";
 | |
|     break;
 | |
| 
 | |
|   // Intel wireless MMX general purpose registers 0 - 7 XScale accumulator
 | |
|   // register 0 - 7 (they do overlap with wCGR0 - wCGR7)
 | |
|   case dwarf_wCGR0:
 | |
|     reg_info.name = "wCGR0/ACC0";
 | |
|     break;
 | |
|   case dwarf_wCGR1:
 | |
|     reg_info.name = "wCGR1/ACC1";
 | |
|     break;
 | |
|   case dwarf_wCGR2:
 | |
|     reg_info.name = "wCGR2/ACC2";
 | |
|     break;
 | |
|   case dwarf_wCGR3:
 | |
|     reg_info.name = "wCGR3/ACC3";
 | |
|     break;
 | |
|   case dwarf_wCGR4:
 | |
|     reg_info.name = "wCGR4/ACC4";
 | |
|     break;
 | |
|   case dwarf_wCGR5:
 | |
|     reg_info.name = "wCGR5/ACC5";
 | |
|     break;
 | |
|   case dwarf_wCGR6:
 | |
|     reg_info.name = "wCGR6/ACC6";
 | |
|     break;
 | |
|   case dwarf_wCGR7:
 | |
|     reg_info.name = "wCGR7/ACC7";
 | |
|     break;
 | |
| 
 | |
|   // Intel wireless MMX data registers 0 - 15
 | |
|   case dwarf_wR0:
 | |
|     reg_info.name = "wR0";
 | |
|     break;
 | |
|   case dwarf_wR1:
 | |
|     reg_info.name = "wR1";
 | |
|     break;
 | |
|   case dwarf_wR2:
 | |
|     reg_info.name = "wR2";
 | |
|     break;
 | |
|   case dwarf_wR3:
 | |
|     reg_info.name = "wR3";
 | |
|     break;
 | |
|   case dwarf_wR4:
 | |
|     reg_info.name = "wR4";
 | |
|     break;
 | |
|   case dwarf_wR5:
 | |
|     reg_info.name = "wR5";
 | |
|     break;
 | |
|   case dwarf_wR6:
 | |
|     reg_info.name = "wR6";
 | |
|     break;
 | |
|   case dwarf_wR7:
 | |
|     reg_info.name = "wR7";
 | |
|     break;
 | |
|   case dwarf_wR8:
 | |
|     reg_info.name = "wR8";
 | |
|     break;
 | |
|   case dwarf_wR9:
 | |
|     reg_info.name = "wR9";
 | |
|     break;
 | |
|   case dwarf_wR10:
 | |
|     reg_info.name = "wR10";
 | |
|     break;
 | |
|   case dwarf_wR11:
 | |
|     reg_info.name = "wR11";
 | |
|     break;
 | |
|   case dwarf_wR12:
 | |
|     reg_info.name = "wR12";
 | |
|     break;
 | |
|   case dwarf_wR13:
 | |
|     reg_info.name = "wR13";
 | |
|     break;
 | |
|   case dwarf_wR14:
 | |
|     reg_info.name = "wR14";
 | |
|     break;
 | |
|   case dwarf_wR15:
 | |
|     reg_info.name = "wR15";
 | |
|     break;
 | |
| 
 | |
|   case dwarf_spsr:
 | |
|     reg_info.name = "spsr";
 | |
|     break;
 | |
|   case dwarf_spsr_fiq:
 | |
|     reg_info.name = "spsr_fiq";
 | |
|     break;
 | |
|   case dwarf_spsr_irq:
 | |
|     reg_info.name = "spsr_irq";
 | |
|     break;
 | |
|   case dwarf_spsr_abt:
 | |
|     reg_info.name = "spsr_abt";
 | |
|     break;
 | |
|   case dwarf_spsr_und:
 | |
|     reg_info.name = "spsr_und";
 | |
|     break;
 | |
|   case dwarf_spsr_svc:
 | |
|     reg_info.name = "spsr_svc";
 | |
|     break;
 | |
| 
 | |
|   case dwarf_r8_usr:
 | |
|     reg_info.name = "r8_usr";
 | |
|     break;
 | |
|   case dwarf_r9_usr:
 | |
|     reg_info.name = "r9_usr";
 | |
|     break;
 | |
|   case dwarf_r10_usr:
 | |
|     reg_info.name = "r10_usr";
 | |
|     break;
 | |
|   case dwarf_r11_usr:
 | |
|     reg_info.name = "r11_usr";
 | |
|     break;
 | |
|   case dwarf_r12_usr:
 | |
|     reg_info.name = "r12_usr";
 | |
|     break;
 | |
|   case dwarf_r13_usr:
 | |
|     reg_info.name = "r13_usr";
 | |
|     break;
 | |
|   case dwarf_r14_usr:
 | |
|     reg_info.name = "r14_usr";
 | |
|     break;
 | |
|   case dwarf_r8_fiq:
 | |
|     reg_info.name = "r8_fiq";
 | |
|     break;
 | |
|   case dwarf_r9_fiq:
 | |
|     reg_info.name = "r9_fiq";
 | |
|     break;
 | |
|   case dwarf_r10_fiq:
 | |
|     reg_info.name = "r10_fiq";
 | |
|     break;
 | |
|   case dwarf_r11_fiq:
 | |
|     reg_info.name = "r11_fiq";
 | |
|     break;
 | |
|   case dwarf_r12_fiq:
 | |
|     reg_info.name = "r12_fiq";
 | |
|     break;
 | |
|   case dwarf_r13_fiq:
 | |
|     reg_info.name = "r13_fiq";
 | |
|     break;
 | |
|   case dwarf_r14_fiq:
 | |
|     reg_info.name = "r14_fiq";
 | |
|     break;
 | |
|   case dwarf_r13_irq:
 | |
|     reg_info.name = "r13_irq";
 | |
|     break;
 | |
|   case dwarf_r14_irq:
 | |
|     reg_info.name = "r14_irq";
 | |
|     break;
 | |
|   case dwarf_r13_abt:
 | |
|     reg_info.name = "r13_abt";
 | |
|     break;
 | |
|   case dwarf_r14_abt:
 | |
|     reg_info.name = "r14_abt";
 | |
|     break;
 | |
|   case dwarf_r13_und:
 | |
|     reg_info.name = "r13_und";
 | |
|     break;
 | |
|   case dwarf_r14_und:
 | |
|     reg_info.name = "r14_und";
 | |
|     break;
 | |
|   case dwarf_r13_svc:
 | |
|     reg_info.name = "r13_svc";
 | |
|     break;
 | |
|   case dwarf_r14_svc:
 | |
|     reg_info.name = "r14_svc";
 | |
|     break;
 | |
| 
 | |
|   // Intel wireless MMX control register in co-processor 0 - 7
 | |
|   case dwarf_wC0:
 | |
|     reg_info.name = "wC0";
 | |
|     break;
 | |
|   case dwarf_wC1:
 | |
|     reg_info.name = "wC1";
 | |
|     break;
 | |
|   case dwarf_wC2:
 | |
|     reg_info.name = "wC2";
 | |
|     break;
 | |
|   case dwarf_wC3:
 | |
|     reg_info.name = "wC3";
 | |
|     break;
 | |
|   case dwarf_wC4:
 | |
|     reg_info.name = "wC4";
 | |
|     break;
 | |
|   case dwarf_wC5:
 | |
|     reg_info.name = "wC5";
 | |
|     break;
 | |
|   case dwarf_wC6:
 | |
|     reg_info.name = "wC6";
 | |
|     break;
 | |
|   case dwarf_wC7:
 | |
|     reg_info.name = "wC7";
 | |
|     break;
 | |
| 
 | |
|   // VFP-v3/Neon
 | |
|   case dwarf_d0:
 | |
|     reg_info.name = "d0";
 | |
|     break;
 | |
|   case dwarf_d1:
 | |
|     reg_info.name = "d1";
 | |
|     break;
 | |
|   case dwarf_d2:
 | |
|     reg_info.name = "d2";
 | |
|     break;
 | |
|   case dwarf_d3:
 | |
|     reg_info.name = "d3";
 | |
|     break;
 | |
|   case dwarf_d4:
 | |
|     reg_info.name = "d4";
 | |
|     break;
 | |
|   case dwarf_d5:
 | |
|     reg_info.name = "d5";
 | |
|     break;
 | |
|   case dwarf_d6:
 | |
|     reg_info.name = "d6";
 | |
|     break;
 | |
|   case dwarf_d7:
 | |
|     reg_info.name = "d7";
 | |
|     break;
 | |
|   case dwarf_d8:
 | |
|     reg_info.name = "d8";
 | |
|     break;
 | |
|   case dwarf_d9:
 | |
|     reg_info.name = "d9";
 | |
|     break;
 | |
|   case dwarf_d10:
 | |
|     reg_info.name = "d10";
 | |
|     break;
 | |
|   case dwarf_d11:
 | |
|     reg_info.name = "d11";
 | |
|     break;
 | |
|   case dwarf_d12:
 | |
|     reg_info.name = "d12";
 | |
|     break;
 | |
|   case dwarf_d13:
 | |
|     reg_info.name = "d13";
 | |
|     break;
 | |
|   case dwarf_d14:
 | |
|     reg_info.name = "d14";
 | |
|     break;
 | |
|   case dwarf_d15:
 | |
|     reg_info.name = "d15";
 | |
|     break;
 | |
|   case dwarf_d16:
 | |
|     reg_info.name = "d16";
 | |
|     break;
 | |
|   case dwarf_d17:
 | |
|     reg_info.name = "d17";
 | |
|     break;
 | |
|   case dwarf_d18:
 | |
|     reg_info.name = "d18";
 | |
|     break;
 | |
|   case dwarf_d19:
 | |
|     reg_info.name = "d19";
 | |
|     break;
 | |
|   case dwarf_d20:
 | |
|     reg_info.name = "d20";
 | |
|     break;
 | |
|   case dwarf_d21:
 | |
|     reg_info.name = "d21";
 | |
|     break;
 | |
|   case dwarf_d22:
 | |
|     reg_info.name = "d22";
 | |
|     break;
 | |
|   case dwarf_d23:
 | |
|     reg_info.name = "d23";
 | |
|     break;
 | |
|   case dwarf_d24:
 | |
|     reg_info.name = "d24";
 | |
|     break;
 | |
|   case dwarf_d25:
 | |
|     reg_info.name = "d25";
 | |
|     break;
 | |
|   case dwarf_d26:
 | |
|     reg_info.name = "d26";
 | |
|     break;
 | |
|   case dwarf_d27:
 | |
|     reg_info.name = "d27";
 | |
|     break;
 | |
|   case dwarf_d28:
 | |
|     reg_info.name = "d28";
 | |
|     break;
 | |
|   case dwarf_d29:
 | |
|     reg_info.name = "d29";
 | |
|     break;
 | |
|   case dwarf_d30:
 | |
|     reg_info.name = "d30";
 | |
|     break;
 | |
|   case dwarf_d31:
 | |
|     reg_info.name = "d31";
 | |
|     break;
 | |
| 
 | |
|   // NEON 128-bit vector registers (overlays the d registers)
 | |
|   case dwarf_q0:
 | |
|     reg_info.name = "q0";
 | |
|     break;
 | |
|   case dwarf_q1:
 | |
|     reg_info.name = "q1";
 | |
|     break;
 | |
|   case dwarf_q2:
 | |
|     reg_info.name = "q2";
 | |
|     break;
 | |
|   case dwarf_q3:
 | |
|     reg_info.name = "q3";
 | |
|     break;
 | |
|   case dwarf_q4:
 | |
|     reg_info.name = "q4";
 | |
|     break;
 | |
|   case dwarf_q5:
 | |
|     reg_info.name = "q5";
 | |
|     break;
 | |
|   case dwarf_q6:
 | |
|     reg_info.name = "q6";
 | |
|     break;
 | |
|   case dwarf_q7:
 | |
|     reg_info.name = "q7";
 | |
|     break;
 | |
|   case dwarf_q8:
 | |
|     reg_info.name = "q8";
 | |
|     break;
 | |
|   case dwarf_q9:
 | |
|     reg_info.name = "q9";
 | |
|     break;
 | |
|   case dwarf_q10:
 | |
|     reg_info.name = "q10";
 | |
|     break;
 | |
|   case dwarf_q11:
 | |
|     reg_info.name = "q11";
 | |
|     break;
 | |
|   case dwarf_q12:
 | |
|     reg_info.name = "q12";
 | |
|     break;
 | |
|   case dwarf_q13:
 | |
|     reg_info.name = "q13";
 | |
|     break;
 | |
|   case dwarf_q14:
 | |
|     reg_info.name = "q14";
 | |
|     break;
 | |
|   case dwarf_q15:
 | |
|     reg_info.name = "q15";
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.50
 | |
| // Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
 | |
| static uint32_t CountITSize(uint32_t ITMask) {
 | |
|   // First count the trailing zeros of the IT mask.
 | |
|   uint32_t TZ = llvm::countTrailingZeros(ITMask);
 | |
|   if (TZ > 3) {
 | |
|     return 0;
 | |
|   }
 | |
|   return (4 - TZ);
 | |
| }
 | |
| 
 | |
| // Init ITState.  Note that at least one bit is always 1 in mask.
 | |
| bool ITSession::InitIT(uint32_t bits7_0) {
 | |
|   ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
 | |
|   if (ITCounter == 0)
 | |
|     return false;
 | |
| 
 | |
|   // A8.6.50 IT
 | |
|   unsigned short FirstCond = Bits32(bits7_0, 7, 4);
 | |
|   if (FirstCond == 0xF) {
 | |
|     return false;
 | |
|   }
 | |
|   if (FirstCond == 0xE && ITCounter != 1) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   ITState = bits7_0;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Update ITState if necessary.
 | |
| void ITSession::ITAdvance() {
 | |
|   // assert(ITCounter);
 | |
|   --ITCounter;
 | |
|   if (ITCounter == 0)
 | |
|     ITState = 0;
 | |
|   else {
 | |
|     unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
 | |
|     SetBits32(ITState, 4, 0, NewITState4_0);
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Return true if we're inside an IT Block.
 | |
| bool ITSession::InITBlock() { return ITCounter != 0; }
 | |
| 
 | |
| // Return true if we're the last instruction inside an IT Block.
 | |
| bool ITSession::LastInITBlock() { return ITCounter == 1; }
 | |
| 
 | |
| // Get condition bits for the current thumb instruction.
 | |
| uint32_t ITSession::GetCond() {
 | |
|   if (InITBlock())
 | |
|     return Bits32(ITState, 7, 4);
 | |
|   else
 | |
|     return COND_AL;
 | |
| }
 | |
| 
 | |
| // ARM constants used during decoding
 | |
| #define REG_RD 0
 | |
| #define LDM_REGLIST 1
 | |
| #define SP_REG 13
 | |
| #define LR_REG 14
 | |
| #define PC_REG 15
 | |
| #define PC_REGLIST_BIT 0x8000
 | |
| 
 | |
| #define ARMv4 (1u << 0)
 | |
| #define ARMv4T (1u << 1)
 | |
| #define ARMv5T (1u << 2)
 | |
| #define ARMv5TE (1u << 3)
 | |
| #define ARMv5TEJ (1u << 4)
 | |
| #define ARMv6 (1u << 5)
 | |
| #define ARMv6K (1u << 6)
 | |
| #define ARMv6T2 (1u << 7)
 | |
| #define ARMv7 (1u << 8)
 | |
| #define ARMv7S (1u << 9)
 | |
| #define ARMv8 (1u << 10)
 | |
| #define ARMvAll (0xffffffffu)
 | |
| 
 | |
| #define ARMV4T_ABOVE                                                           \
 | |
|   (ARMv4T | ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 |   \
 | |
|    ARMv7S | ARMv8)
 | |
| #define ARMV5_ABOVE                                                            \
 | |
|   (ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S |   \
 | |
|    ARMv8)
 | |
| #define ARMV5TE_ABOVE                                                          \
 | |
|   (ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8)
 | |
| #define ARMV5J_ABOVE                                                           \
 | |
|   (ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8)
 | |
| #define ARMV6_ABOVE (ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8)
 | |
| #define ARMV6T2_ABOVE (ARMv6T2 | ARMv7 | ARMv7S | ARMv8)
 | |
| #define ARMV7_ABOVE (ARMv7 | ARMv7S | ARMv8)
 | |
| 
 | |
| #define No_VFP 0
 | |
| #define VFPv1 (1u << 1)
 | |
| #define VFPv2 (1u << 2)
 | |
| #define VFPv3 (1u << 3)
 | |
| #define AdvancedSIMD (1u << 4)
 | |
| 
 | |
| #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
 | |
| #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
 | |
| #define VFPv2v3 (VFPv2 | VFPv3)
 | |
| 
 | |
| //
 | |
| // EmulateInstructionARM implementation
 | |
| //
 | |
| 
 | |
| void EmulateInstructionARM::Initialize() {
 | |
|   PluginManager::RegisterPlugin(GetPluginNameStatic(),
 | |
|                                 GetPluginDescriptionStatic(), CreateInstance);
 | |
| }
 | |
| 
 | |
| void EmulateInstructionARM::Terminate() {
 | |
|   PluginManager::UnregisterPlugin(CreateInstance);
 | |
| }
 | |
| 
 | |
| ConstString EmulateInstructionARM::GetPluginNameStatic() {
 | |
|   static ConstString g_name("arm");
 | |
|   return g_name;
 | |
| }
 | |
| 
 | |
| const char *EmulateInstructionARM::GetPluginDescriptionStatic() {
 | |
|   return "Emulate instructions for the ARM architecture.";
 | |
| }
 | |
| 
 | |
| EmulateInstruction *
 | |
| EmulateInstructionARM::CreateInstance(const ArchSpec &arch,
 | |
|                                       InstructionType inst_type) {
 | |
|   if (EmulateInstructionARM::SupportsEmulatingInstructionsOfTypeStatic(
 | |
|           inst_type)) {
 | |
|     if (arch.GetTriple().getArch() == llvm::Triple::arm) {
 | |
|       std::unique_ptr<EmulateInstructionARM> emulate_insn_up(
 | |
|           new EmulateInstructionARM(arch));
 | |
| 
 | |
|       if (emulate_insn_up)
 | |
|         return emulate_insn_up.release();
 | |
|     } else if (arch.GetTriple().getArch() == llvm::Triple::thumb) {
 | |
|       std::unique_ptr<EmulateInstructionARM> emulate_insn_up(
 | |
|           new EmulateInstructionARM(arch));
 | |
| 
 | |
|       if (emulate_insn_up)
 | |
|         return emulate_insn_up.release();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::SetTargetTriple(const ArchSpec &arch) {
 | |
|   if (arch.GetTriple().getArch() == llvm::Triple::arm)
 | |
|     return true;
 | |
|   else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
 | |
|     return true;
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| // Write "bits (32) UNKNOWN" to memory address "address".  Helper function for
 | |
| // many ARM instructions.
 | |
| bool EmulateInstructionARM::WriteBits32UnknownToMemory(addr_t address) {
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextWriteMemoryRandomBits;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   uint32_t random_data = rand();
 | |
|   const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|   return MemAWrite(context, address, random_data, addr_byte_size);
 | |
| }
 | |
| 
 | |
| // Write "bits (32) UNKNOWN" to register n.  Helper function for many ARM
 | |
| // instructions.
 | |
| bool EmulateInstructionARM::WriteBits32Unknown(int n) {
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextWriteRegisterRandomBits;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   bool success;
 | |
|   uint32_t data =
 | |
|       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
| 
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, data))
 | |
|     return false;
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::GetRegisterInfo(lldb::RegisterKind reg_kind,
 | |
|                                             uint32_t reg_num,
 | |
|                                             RegisterInfo ®_info) {
 | |
|   if (reg_kind == eRegisterKindGeneric) {
 | |
|     switch (reg_num) {
 | |
|     case LLDB_REGNUM_GENERIC_PC:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_pc;
 | |
|       break;
 | |
|     case LLDB_REGNUM_GENERIC_SP:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_sp;
 | |
|       break;
 | |
|     case LLDB_REGNUM_GENERIC_FP:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_r7;
 | |
|       break;
 | |
|     case LLDB_REGNUM_GENERIC_RA:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_lr;
 | |
|       break;
 | |
|     case LLDB_REGNUM_GENERIC_FLAGS:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_cpsr;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (reg_kind == eRegisterKindDWARF)
 | |
|     return GetARMDWARFRegisterInfo(reg_num, reg_info);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const {
 | |
|   if (m_arch.GetTriple().isAndroid())
 | |
|     return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
 | |
|   bool is_apple = false;
 | |
|   if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple)
 | |
|     is_apple = true;
 | |
|   switch (m_arch.GetTriple().getOS()) {
 | |
|   case llvm::Triple::Darwin:
 | |
|   case llvm::Triple::MacOSX:
 | |
|   case llvm::Triple::IOS:
 | |
|   case llvm::Triple::TvOS:
 | |
|   case llvm::Triple::WatchOS:
 | |
|   // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS:
 | |
|     is_apple = true;
 | |
|     break;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   /* On Apple iOS et al, the frame pointer register is always r7.
 | |
|    * Typically on other ARM systems, thumb code uses r7; arm code uses r11.
 | |
|    * Windows on ARM, which is in thumb mode, uses r11 though.
 | |
|    */
 | |
| 
 | |
|   uint32_t fp_regnum = 11;
 | |
| 
 | |
|   if (is_apple)
 | |
|     fp_regnum = 7;
 | |
| 
 | |
|   if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows())
 | |
|     fp_regnum = 7;
 | |
| 
 | |
|   return fp_regnum;
 | |
| }
 | |
| 
 | |
| uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const {
 | |
|   bool is_apple = false;
 | |
|   if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple)
 | |
|     is_apple = true;
 | |
|   switch (m_arch.GetTriple().getOS()) {
 | |
|   case llvm::Triple::Darwin:
 | |
|   case llvm::Triple::MacOSX:
 | |
|   case llvm::Triple::IOS:
 | |
|     is_apple = true;
 | |
|     break;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   /* On Apple iOS et al, the frame pointer register is always r7.
 | |
|    * Typically on other ARM systems, thumb code uses r7; arm code uses r11.
 | |
|    * Windows on ARM, which is in thumb mode, uses r11 though.
 | |
|    */
 | |
| 
 | |
|   uint32_t fp_regnum = dwarf_r11;
 | |
| 
 | |
|   if (is_apple)
 | |
|     fp_regnum = dwarf_r7;
 | |
| 
 | |
|   if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows())
 | |
|     fp_regnum = dwarf_r7;
 | |
| 
 | |
|   return fp_regnum;
 | |
| }
 | |
| 
 | |
| // Push Multiple Registers stores multiple registers to the stack, storing to
 | |
| // consecutive memory locations ending just below the address in SP, and
 | |
| // updates
 | |
| // SP to point to the start of the stored data.
 | |
| bool EmulateInstructionARM::EmulatePUSH(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); 
 | |
|         NullCheckIfThumbEE(13); 
 | |
|         address = SP - 4*BitCount(registers);
 | |
| 
 | |
|         for (i = 0 to 14)
 | |
|         {
 | |
|             if (registers<i> == '1')
 | |
|             {
 | |
|                 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 
 | |
|                     MemA[address,4] = bits(32) UNKNOWN;
 | |
|                 else 
 | |
|                     MemA[address,4] = R[i];
 | |
|                 address = address + 4;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (registers<15> == '1') // Only possible for encoding A1 or A2 
 | |
|             MemA[address,4] = PCStoreValue();
 | |
|         
 | |
|         SP = SP - 4*BitCount(registers);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t registers = 0;
 | |
|     uint32_t Rt; // the source register
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       registers = Bits32(opcode, 7, 0);
 | |
|       // The M bit represents LR.
 | |
|       if (Bit32(opcode, 8))
 | |
|         registers |= (1u << 14);
 | |
|       // if BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 1)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       // Ignore bits 15 & 13.
 | |
|       registers = Bits32(opcode, 15, 0) & ~0xa000;
 | |
|       // if BitCount(registers) < 2 then UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 2)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT3:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       // if BadReg(t) then UNPREDICTABLE;
 | |
|       if (BadReg(Rt))
 | |
|         return false;
 | |
|       registers = (1u << Rt);
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       // Instead of return false, let's handle the following case as well,
 | |
|       // which amounts to pushing one reg onto the full descending stacks.
 | |
|       // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
 | |
|       break;
 | |
|     case eEncodingA2:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (Rt == dwarf_sp)
 | |
|         return false;
 | |
|       registers = (1u << Rt);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t sp_offset = addr_byte_size * BitCount(registers);
 | |
|     addr_t addr = sp - sp_offset;
 | |
|     uint32_t i;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextPushRegisterOnStack;
 | |
|     RegisterInfo reg_info;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     for (i = 0; i < 15; ++i) {
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, reg_info);
 | |
|         context.SetRegisterToRegisterPlusOffset(reg_info, sp_reg, addr - sp);
 | |
|         uint32_t reg_value = ReadCoreReg(i, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
|         if (!MemAWrite(context, addr, reg_value, addr_byte_size))
 | |
|           return false;
 | |
|         addr += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, reg_info);
 | |
|       context.SetRegisterToRegisterPlusOffset(reg_info, sp_reg, addr - sp);
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       if (!MemAWrite(context, addr, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     context.SetImmediateSigned(-sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Pop Multiple Registers loads multiple registers from the stack, loading from
 | |
| // consecutive memory locations staring at the address in SP, and updates
 | |
| // SP to point just above the loaded data.
 | |
| bool EmulateInstructionARM::EmulatePOP(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(13);
 | |
|         address = SP;
 | |
|         for i = 0 to 14
 | |
|             if registers<i> == '1' then
 | |
|                 R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
 | |
|         if registers<15> == '1' then
 | |
|             if UnalignedAllowed then
 | |
|                 LoadWritePC(MemU[address,4]);
 | |
|             else 
 | |
|                 LoadWritePC(MemA[address,4]);
 | |
|         if registers<13> == '0' then SP = SP + 4*BitCount(registers);
 | |
|         if registers<13> == '1' then SP = bits(32) UNKNOWN;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t registers = 0;
 | |
|     uint32_t Rt; // the destination register
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       registers = Bits32(opcode, 7, 0);
 | |
|       // The P bit represents PC.
 | |
|       if (Bit32(opcode, 8))
 | |
|         registers |= (1u << 15);
 | |
|       // if BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 1)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       // Ignore bit 13.
 | |
|       registers = Bits32(opcode, 15, 0) & ~0x2000;
 | |
|       // if BitCount(registers) < 2 || (P == '1' && M == '1') then
 | |
|       // UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
 | |
|         return false;
 | |
|       // if registers<15> == '1' && InITBlock() && !LastInITBlock() then
 | |
|       // UNPREDICTABLE;
 | |
|       if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT3:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then
 | |
|       // UNPREDICTABLE;
 | |
|       if (Rt == 13)
 | |
|         return false;
 | |
|       if (Rt == 15 && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       registers = (1u << Rt);
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       // Instead of return false, let's handle the following case as well,
 | |
|       // which amounts to popping one reg from the full descending stacks.
 | |
|       // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
 | |
| 
 | |
|       // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE;
 | |
|       if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA2:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (Rt == dwarf_sp)
 | |
|         return false;
 | |
|       registers = (1u << Rt);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t sp_offset = addr_byte_size * BitCount(registers);
 | |
|     addr_t addr = sp;
 | |
|     uint32_t i, data;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextPopRegisterOffStack;
 | |
| 
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
| 
 | |
|     for (i = 0; i < 15; ++i) {
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         context.SetAddress(addr);
 | |
|         data = MemARead(context, addr, 4, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                    data))
 | |
|           return false;
 | |
|         addr += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       context.SetRegisterPlusOffset(sp_reg, addr - sp);
 | |
|       data = MemARead(context, addr, 4, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // In ARMv5T and above, this is an interworking branch.
 | |
|       if (!LoadWritePC(context, data))
 | |
|         return false;
 | |
|       // addr += addr_byte_size;
 | |
|     }
 | |
| 
 | |
|     context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     context.SetImmediateSigned(sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Set r7 or ip to point to saved value residing within the stack.
 | |
| // ADD (SP plus immediate)
 | |
| bool EmulateInstructionARM::EmulateADDRdSPImm(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
 | |
|         if d == 15 then
 | |
|            ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t Rd; // the destination register
 | |
|     uint32_t imm32;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = 7;
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t sp_offset = imm32;
 | |
|     addr_t addr = sp + sp_offset; // a pointer to the stack area
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == GetFramePointerRegisterNumber())
 | |
|       context.type = eContextSetFramePointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     context.SetRegisterPlusOffset(sp_reg, sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd,
 | |
|                                addr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Set r7 or ip to the current stack pointer.
 | |
| // MOV (register)
 | |
| bool EmulateInstructionARM::EmulateMOVRdSP(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[m];
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 // APSR.C unchanged
 | |
|                 // APSR.V unchanged
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t Rd; // the destination register
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = 7;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = 12;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == GetFramePointerRegisterNumber())
 | |
|       context.type = EmulateInstruction::eContextSetFramePointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     context.SetRegisterPlusOffset(sp_reg, 0);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Move from high register (r8-r15) to low register (r0-r7).
 | |
| // MOV (register)
 | |
| bool EmulateInstructionARM::EmulateMOVLowHigh(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
|   return EmulateMOVRdRm(opcode, encoding);
 | |
| }
 | |
| 
 | |
| // Move from register to register.
 | |
| // MOV (register)
 | |
| bool EmulateInstructionARM::EmulateMOVRdRm(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[m];
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 // APSR.C unchanged
 | |
|                 // APSR.V unchanged
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rm; // the source register
 | |
|     uint32_t Rd; // the destination register
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 6, 3);
 | |
|       setflags = false;
 | |
|       if (Rd == 15 && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = true;
 | |
|       if (InITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT3:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
 | |
|       if (setflags && (BadReg(Rd) || BadReg(Rm)))
 | |
|         return false;
 | |
|       // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then
 | |
|       // UNPREDICTABLE;
 | |
|       if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13)))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t result = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // The context specifies that Rm is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == 13)
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     else if (Rd == GetFramePointerRegisterNumber() && Rm == 13)
 | |
|       context.type = EmulateInstruction::eContextSetFramePointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, 0);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Move (immediate) writes an immediate value to the destination register.  It
 | |
| // can optionally update the condition flags based on the value.
 | |
| // MOV (immediate)
 | |
| bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         result = imm32;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd;    // the destination register
 | |
|     uint32_t imm32; // the immediate value to be written to Rd
 | |
|     uint32_t carry =
 | |
|         0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C.
 | |
|            // for setflags == false, this value is a don't care initialized to
 | |
|            // 0 to silence the static analyzer
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 10, 8);
 | |
|       setflags = !InITBlock();
 | |
|       imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
 | |
|       carry = APSR_C;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
 | |
|       if (BadReg(Rd))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3: {
 | |
|       // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8,
 | |
|       // 32);
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       setflags = false;
 | |
|       uint32_t imm4 = Bits32(opcode, 19, 16);
 | |
|       uint32_t imm3 = Bits32(opcode, 14, 12);
 | |
|       uint32_t i = Bit32(opcode, 26);
 | |
|       uint32_t imm8 = Bits32(opcode, 7, 0);
 | |
|       imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
 | |
| 
 | |
|       // if BadReg(d) then UNPREDICTABLE;
 | |
|       if (BadReg(Rd))
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); setflags = (S == '1'); (imm32, carry) =
 | |
|       // ARMExpandImm_C(imm12, APSR.C);
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm_C(opcode, APSR_C, carry);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if ((Rd == 15) && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA2: {
 | |
|       // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32);
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       setflags = false;
 | |
|       uint32_t imm4 = Bits32(opcode, 19, 16);
 | |
|       uint32_t imm12 = Bits32(opcode, 11, 0);
 | |
|       imm32 = (imm4 << 12) | imm12;
 | |
| 
 | |
|       // if d == 15 then UNPREDICTABLE;
 | |
|       if (Rd == 15)
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t result = imm32;
 | |
| 
 | |
|     // The context specifies that an immediate is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // MUL multiplies two register values.  The least significant 32 bits of the
 | |
| // result are written to the destination
 | |
| // register.  These 32 bits do not depend on whether the source register values
 | |
| // are considered to be signed values or unsigned values.
 | |
| //
 | |
| // Optionally, it can update the condition flags based on the result.  In the
 | |
| // Thumb instruction set, this option is limited to only a few forms of the
 | |
| // instruction.
 | |
| bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results 
 | |
|         operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results 
 | |
|         result = operand1 * operand2; 
 | |
|         R[d] = result<31:0>; 
 | |
|         if setflags then
 | |
|             APSR.N = result<31>; 
 | |
|             APSR.Z = IsZeroBit(result); 
 | |
|             if ArchVersion() == 4 then
 | |
|                 APSR.C = bit UNKNOWN; 
 | |
|             // else APSR.C unchanged 
 | |
|             // APSR.V always unchanged
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool setflags;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock();
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 2, 0);
 | |
|       setflags = !InITBlock();
 | |
| 
 | |
|       // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
 | |
|       if ((ArchVersion() < ARMv6) && (d == n))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE;
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       setflags = false;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(n) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1');
 | |
|       d = Bits32(opcode, 19, 16);
 | |
|       n = Bits32(opcode, 3, 0);
 | |
|       m = Bits32(opcode, 11, 8);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (n == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
 | |
|       if ((ArchVersion() < ARMv6) && (d == n))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     bool success = false;
 | |
| 
 | |
|     // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final
 | |
|     // results
 | |
|     uint64_t operand1 =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final
 | |
|     // results
 | |
|     uint64_t operand2 =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // result = operand1 * operand2;
 | |
|     uint64_t result = operand1 * operand2;
 | |
| 
 | |
|     // R[d] = result<31:0>;
 | |
|     RegisterInfo op1_reg;
 | |
|     RegisterInfo op2_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, op1_reg);
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, op2_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     context.SetRegisterRegisterOperands(op1_reg, op2_reg);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                (0x0000ffff & result)))
 | |
|       return false;
 | |
| 
 | |
|     // if setflags then
 | |
|     if (setflags) {
 | |
|       // APSR.N = result<31>;
 | |
|       // APSR.Z = IsZeroBit(result);
 | |
|       m_new_inst_cpsr = m_opcode_cpsr;
 | |
|       SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, 31));
 | |
|       SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
 | |
|       if (m_new_inst_cpsr != m_opcode_cpsr) {
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                    LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
 | |
|           return false;
 | |
|       }
 | |
| 
 | |
|       // if ArchVersion() == 4 then
 | |
|       // APSR.C = bit UNKNOWN;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to
 | |
| // the destination register. It can optionally update the condition flags based
 | |
| // on the value.
 | |
| bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         result = NOT(imm32);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd;    // the destination register
 | |
|     uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C
 | |
|     uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm_C(opcode, APSR_C, carry);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t result = ~imm32;
 | |
| 
 | |
|     // The context specifies that an immediate is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise NOT (register) writes the bitwise inverse of a register value to the
 | |
| // destination register. It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateMVNReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = NOT(shifted);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rm; // the source register
 | |
|     uint32_t Rd; // the destination register
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     uint32_t carry; // the carry bit after the shift operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       if (InITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
 | |
|       if (BadReg(Rd) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     bool success = false;
 | |
|     uint32_t value = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted =
 | |
|         Shift_C(value, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = ~shifted;
 | |
| 
 | |
|     // The context specifies that an immediate is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // PC relative immediate load into register, possibly followed by ADD (SP plus
 | |
| // register).
 | |
| // LDR (literal)
 | |
| bool EmulateInstructionARM::EmulateLDRRtPCRelative(const uint32_t opcode,
 | |
|                                                    const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15);
 | |
|         base = Align(PC,4);
 | |
|         address = if add then (base + imm32) else (base - imm32);
 | |
|         data = MemU[address,4];
 | |
|         if t == 15 then
 | |
|             if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
 | |
|         elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|             R[t] = data;
 | |
|         else // Can only apply before ARMv7
 | |
|             if CurrentInstrSet() == InstrSet_ARM then
 | |
|                 R[t] = ROR(data, 8*UInt(address<1:0>));
 | |
|             else
 | |
|                 R[t] = bits(32) UNKNOWN;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool success = false;
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // PC relative immediate load context
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo pc_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg);
 | |
|     context.SetRegisterPlusOffset(pc_reg, 0);
 | |
| 
 | |
|     uint32_t Rt;    // the destination register
 | |
|     uint32_t imm32; // immediate offset from the PC
 | |
|     bool add;       // +imm32 or -imm32?
 | |
|     addr_t base;    // the base address
 | |
|     addr_t address; // the PC relative address
 | |
|     uint32_t data;  // the literal data value from the PC relative load
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rt = Bits32(opcode, 10, 8);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       add = true;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       if (Rt == 15 && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     base = Align(pc, 4);
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     context.SetRegisterPlusOffset(pc_reg, address - base);
 | |
|     data = MemURead(context, address, 4, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (Rt == 15) {
 | |
|       if (Bits32(address, 1, 0) == 0) {
 | |
|         // In ARMv5T and above, this is an interworking branch.
 | |
|         if (!LoadWritePC(context, data))
 | |
|           return false;
 | |
|       } else
 | |
|         return false;
 | |
|     } else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) {
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rt,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else // We don't handle ARM for now.
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // An add operation to adjust the SP.
 | |
| // ADD (SP plus immediate)
 | |
| bool EmulateInstructionARM::EmulateADDSPImm(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
 | |
|         if d == 15 then // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t imm32; // the immediate operand
 | |
|     uint32_t d;
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       d = Bits32(opcode, 10, 8);
 | |
|       imm32 = (Bits32(opcode, 7, 0) << 2);
 | |
|       setflags = false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
 | |
|       d = 13;
 | |
|       imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
 | |
|       setflags = false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // d = UInt(Rd); setflags = (S == "1"); imm32 =
 | |
|       // ThumbExpandImm(i:imm3:imm8);
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       imm32 = ThumbExpandImm(opcode);
 | |
|       setflags = Bit32(opcode, 20);
 | |
| 
 | |
|       // if Rd == "1111" && S == "1" then SEE CMN (immediate);
 | |
|       if (d == 15 && setflags == 1)
 | |
|         return false; // CMN (immediate) not yet supported
 | |
| 
 | |
|       // if d == 15 && S == "0" then UNPREDICTABLE;
 | |
|       if (d == 15 && setflags == 0)
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT4: {
 | |
|       // if Rn == '1111' then SEE ADR;
 | |
|       // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       setflags = false;
 | |
|       uint32_t i = Bit32(opcode, 26);
 | |
|       uint32_t imm3 = Bits32(opcode, 14, 12);
 | |
|       uint32_t imm8 = Bits32(opcode, 7, 0);
 | |
|       imm32 = (i << 11) | (imm3 << 8) | imm8;
 | |
| 
 | |
|       // if d == 15 then UNPREDICTABLE;
 | |
|       if (d == 15)
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
 | |
|     AddWithCarryResult res = AddWithCarry(sp, imm32, 0);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (d == 13)
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
| 
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     context.SetRegisterPlusOffset(sp_reg, res.result - sp);
 | |
| 
 | |
|     if (d == 15) {
 | |
|       if (!ALUWritePC(context, res.result))
 | |
|         return false;
 | |
|     } else {
 | |
|       // R[d] = result;
 | |
|       // if setflags then
 | |
|       //     APSR.N = result<31>;
 | |
|       //     APSR.Z = IsZeroBit(result);
 | |
|       //     APSR.C = carry;
 | |
|       //     APSR.V = overflow;
 | |
|       if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags,
 | |
|                                      res.carry_out, res.overflow))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // An add operation to adjust the SP.
 | |
| // ADD (SP plus register)
 | |
| bool EmulateInstructionARM::EmulateADDSPRm(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(SP, shifted, '0');
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t Rm; // the second operand
 | |
|     switch (encoding) {
 | |
|     case eEncodingT2:
 | |
|       Rm = Bits32(opcode, 6, 3);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     int32_t reg_value = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
| 
 | |
|     RegisterInfo other_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, other_reg);
 | |
|     context.SetRegisterRegisterOperands(sp_reg, other_reg);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_SP, addr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Branch with Link and Exchange Instruction Sets (immediate) calls a
 | |
| // subroutine at a PC-relative address, and changes instruction set from ARM to
 | |
| // Thumb, or from Thumb to ARM.
 | |
| // BLX (immediate)
 | |
| bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         if CurrentInstrSet() == InstrSet_ARM then
 | |
|             LR = PC - 4;
 | |
|         else
 | |
|             LR = PC<31:1> : '1';
 | |
|         if targetInstrSet == InstrSet_ARM then
 | |
|             targetAddress = Align(PC,4) + imm32;
 | |
|         else
 | |
|             targetAddress = PC + imm32;
 | |
|         SelectInstrSet(targetInstrSet);
 | |
|         BranchWritePC(targetAddress);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = true;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRelativeBranchImmediate;
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     addr_t lr;     // next instruction address
 | |
|     addr_t target; // target address
 | |
|     int32_t imm32; // PC-relative offset
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1: {
 | |
|       lr = pc | 1u; // return address
 | |
|       uint32_t S = Bit32(opcode, 26);
 | |
|       uint32_t imm10 = Bits32(opcode, 25, 16);
 | |
|       uint32_t J1 = Bit32(opcode, 13);
 | |
|       uint32_t J2 = Bit32(opcode, 11);
 | |
|       uint32_t imm11 = Bits32(opcode, 10, 0);
 | |
|       uint32_t I1 = !(J1 ^ S);
 | |
|       uint32_t I2 = !(J2 ^ S);
 | |
|       uint32_t imm25 =
 | |
|           (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
 | |
|       imm32 = llvm::SignExtend32<25>(imm25);
 | |
|       target = pc + imm32;
 | |
|       SelectInstrSet(eModeThumb);
 | |
|       context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     }
 | |
|     case eEncodingT2: {
 | |
|       lr = pc | 1u; // return address
 | |
|       uint32_t S = Bit32(opcode, 26);
 | |
|       uint32_t imm10H = Bits32(opcode, 25, 16);
 | |
|       uint32_t J1 = Bit32(opcode, 13);
 | |
|       uint32_t J2 = Bit32(opcode, 11);
 | |
|       uint32_t imm10L = Bits32(opcode, 10, 1);
 | |
|       uint32_t I1 = !(J1 ^ S);
 | |
|       uint32_t I2 = !(J2 ^ S);
 | |
|       uint32_t imm25 =
 | |
|           (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
 | |
|       imm32 = llvm::SignExtend32<25>(imm25);
 | |
|       target = Align(pc, 4) + imm32;
 | |
|       SelectInstrSet(eModeARM);
 | |
|       context.SetISAAndImmediateSigned(eModeARM, 4 + imm32);
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     }
 | |
|     case eEncodingA1:
 | |
|       lr = pc - 4; // return address
 | |
|       imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
 | |
|       target = Align(pc, 4) + imm32;
 | |
|       SelectInstrSet(eModeARM);
 | |
|       context.SetISAAndImmediateSigned(eModeARM, 8 + imm32);
 | |
|       break;
 | |
|     case eEncodingA2:
 | |
|       lr = pc - 4; // return address
 | |
|       imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 |
 | |
|                                      Bits32(opcode, 24, 24) << 1);
 | |
|       target = pc + imm32;
 | |
|       SelectInstrSet(eModeThumb);
 | |
|       context.SetISAAndImmediateSigned(eModeThumb, 8 + imm32);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_RA, lr))
 | |
|       return false;
 | |
|     if (!BranchWritePC(context, target))
 | |
|       return false;
 | |
|     if (m_opcode_cpsr != m_new_inst_cpsr)
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                  LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
 | |
|         return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Branch with Link and Exchange (register) calls a subroutine at an address
 | |
| // and instruction set specified by a register.
 | |
| // BLX (register)
 | |
| bool EmulateInstructionARM::EmulateBLXRm(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         target = R[m];
 | |
|         if CurrentInstrSet() == InstrSet_ARM then
 | |
|             next_instr_addr = PC - 4;
 | |
|             LR = next_instr_addr;
 | |
|         else
 | |
|             next_instr_addr = PC - 2;
 | |
|             LR = next_instr_addr<31:1> : '1';
 | |
|         BXWritePC(target);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     addr_t lr; // next instruction address
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t Rm; // the register with the target address
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       lr = (pc - 2) | 1u; // return address
 | |
|       Rm = Bits32(opcode, 6, 3);
 | |
|       // if m == 15 then UNPREDICTABLE;
 | |
|       if (Rm == 15)
 | |
|         return false;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       lr = pc - 4; // return address
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       // if m == 15 then UNPREDICTABLE;
 | |
|       if (Rm == 15)
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t target = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
 | |
|     context.SetRegister(dwarf_reg);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_RA, lr))
 | |
|       return false;
 | |
|     if (!BXWritePC(context, target))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Branch and Exchange causes a branch to an address and instruction set
 | |
| // specified by a register.
 | |
| bool EmulateInstructionARM::EmulateBXRm(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         BXWritePC(R[m]);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
 | |
|     uint32_t Rm; // the register with the target address
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rm = Bits32(opcode, 6, 3);
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     bool success = false;
 | |
|     addr_t target = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
 | |
|     context.SetRegister(dwarf_reg);
 | |
|     if (!BXWritePC(context, target))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Branch and Exchange Jazelle attempts to change to Jazelle state. If the
 | |
| // attempt fails, it branches to an address and instruction set specified by a
 | |
| // register as though it were a BX instruction.
 | |
| //
 | |
| // TODO: Emulate Jazelle architecture?
 | |
| //       We currently assume that switching to Jazelle state fails, thus
 | |
| //       treating BXJ as a BX operation.
 | |
| bool EmulateInstructionARM::EmulateBXJRm(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then
 | |
|             BXWritePC(R[m]);
 | |
|         else
 | |
|             if JazelleAcceptsExecution() then
 | |
|                 SwitchToJazelleExecution();
 | |
|             else
 | |
|                 SUBARCHITECTURE_DEFINED handler call;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
 | |
|     uint32_t Rm; // the register with the target address
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rm = Bits32(opcode, 19, 16);
 | |
|       if (BadReg(Rm))
 | |
|         return false;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       if (Rm == 15)
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     bool success = false;
 | |
|     addr_t target = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
 | |
|     context.SetRegister(dwarf_reg);
 | |
|     if (!BXWritePC(context, target))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Set r7 to point to some ip offset.
 | |
| // SUB (immediate)
 | |
| bool EmulateInstructionARM::EmulateSUBR7IPImm(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
 | |
|         if d == 15 then // Can only occur for ARM encoding
 | |
|            ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool success = false;
 | |
|     const addr_t ip = ReadCoreReg(12, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t imm32;
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t ip_offset = imm32;
 | |
|     addr_t addr = ip - ip_offset; // the adjusted ip value
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r12, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, -ip_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r7, addr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Set ip to point to some stack offset.
 | |
| // SUB (SP minus immediate)
 | |
| bool EmulateInstructionARM::EmulateSUBIPSPImm(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
 | |
|         if d == 15 then // Can only occur for ARM encoding
 | |
|            ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool success = false;
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t imm32;
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t sp_offset = imm32;
 | |
|     addr_t addr = sp - sp_offset; // the adjusted stack pointer value
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, -sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r12, addr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction subtracts an immediate value from the SP value, and writes
 | |
| // the result to the destination register.
 | |
| //
 | |
| // If Rd == 13 => A sub operation to adjust the SP -- allocate space for local
 | |
| // storage.
 | |
| bool EmulateInstructionARM::EmulateSUBSPImm(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
 | |
|         if d == 15 then        // Can only occur for ARM encoding
 | |
|            ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t Rd;
 | |
|     bool setflags;
 | |
|     uint32_t imm32;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = 13;
 | |
|       setflags = false;
 | |
|       imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateCMPImm(opcode, eEncodingT2);
 | |
|       if (Rd == 15 && !setflags)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT3:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       setflags = false;
 | |
|       imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
 | |
|       if (Rd == 15)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     AddWithCarryResult res = AddWithCarry(sp, ~imm32, 1);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == 13) {
 | |
|       uint64_t imm64 = imm32; // Need to expand it to 64 bits before attempting
 | |
|                               // to negate it, or the wrong
 | |
|       // value gets passed down to context.SetImmediateSigned.
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|       context.SetImmediateSigned(-imm64); // the stack pointer offset
 | |
|     } else {
 | |
|       context.type = EmulateInstruction::eContextImmediate;
 | |
|       context.SetNoArgs();
 | |
|     }
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A store operation to the stack that also updates the SP.
 | |
| bool EmulateInstructionARM::EmulateSTRRtSP(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
 | |
|         if wback then R[n] = offset_addr;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t Rt; // the source register
 | |
|     uint32_t imm12;
 | |
|     uint32_t
 | |
|         Rn; // This function assumes Rn is the SP, but we should verify that.
 | |
| 
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       imm12 = Bits32(opcode, 11, 0);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       if (Rn != 13) // 13 is the SP reg on ARM.  Verify that Rn == SP.
 | |
|         return false;
 | |
| 
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       if (wback && ((Rn == 15) || (Rn == Rt)))
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = sp + imm12;
 | |
|     else
 | |
|       offset_addr = sp - imm12;
 | |
| 
 | |
|     addr_t addr;
 | |
|     if (index)
 | |
|       addr = offset_addr;
 | |
|     else
 | |
|       addr = sp;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextPushRegisterOnStack;
 | |
|     RegisterInfo sp_reg;
 | |
|     RegisterInfo dwarf_reg;
 | |
| 
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rt, dwarf_reg);
 | |
|     context.SetRegisterToRegisterPlusOffset(dwarf_reg, sp_reg, addr - sp);
 | |
|     if (Rt != 15) {
 | |
|       uint32_t reg_value = ReadCoreReg(Rt, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       if (!MemUWrite(context, addr, reg_value, addr_byte_size))
 | |
|         return false;
 | |
|     } else {
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       if (!MemUWrite(context, addr, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (wback) {
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|       context.SetImmediateSigned(addr - sp);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                  LLDB_REGNUM_GENERIC_SP, offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Vector Push stores multiple extension registers to the stack. It also
 | |
| // updates SP to point to the start of the stored data.
 | |
| bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
 | |
|         address = SP - imm32;
 | |
|         SP = SP - imm32;
 | |
|         if single_regs then
 | |
|             for r = 0 to regs-1
 | |
|                 MemA[address,4] = S[d+r]; address = address+4;
 | |
|         else
 | |
|             for r = 0 to regs-1
 | |
|                 // Store as two word-aligned words in the correct order for
 | |
|                 // current endianness.
 | |
|                 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
 | |
|                 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
 | |
|                 address = address+8;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     bool single_regs;
 | |
|     uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register
 | |
|     uint32_t imm32; // stack offset
 | |
|     uint32_t regs;  // number of registers
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       single_regs = false;
 | |
|       d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
 | |
|       // If UInt(imm8) is odd, see "FSTMX".
 | |
|       regs = Bits32(opcode, 7, 0) / 2;
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if (regs == 0 || regs > 16 || (d + regs) > 32)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       single_regs = true;
 | |
|       d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
 | |
|       imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
 | |
|       regs = Bits32(opcode, 7, 0);
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if (regs == 0 || regs > 16 || (d + regs) > 32)
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
 | |
|     uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
 | |
|     addr_t sp_offset = imm32;
 | |
|     addr_t addr = sp - sp_offset;
 | |
|     uint32_t i;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextPushRegisterOnStack;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     for (i = 0; i < regs; ++i) {
 | |
|       GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
 | |
|       context.SetRegisterToRegisterPlusOffset(dwarf_reg, sp_reg, addr - sp);
 | |
|       // uint64_t to accommodate 64-bit registers.
 | |
|       uint64_t reg_value = ReadRegisterUnsigned(&dwarf_reg, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       if (!MemAWrite(context, addr, reg_value, reg_byte_size))
 | |
|         return false;
 | |
|       addr += reg_byte_size;
 | |
|     }
 | |
| 
 | |
|     context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     context.SetImmediateSigned(-sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Vector Pop loads multiple extension registers from the stack. It also
 | |
| // updates SP to point just above the loaded data.
 | |
| bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
 | |
|         address = SP;
 | |
|         SP = SP + imm32;
 | |
|         if single_regs then
 | |
|             for r = 0 to regs-1
 | |
|                 S[d+r] = MemA[address,4]; address = address+4;
 | |
|         else
 | |
|             for r = 0 to regs-1
 | |
|                 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
 | |
|                 // Combine the word-aligned words in the correct order for
 | |
|                 // current endianness.
 | |
|                 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     const addr_t sp = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     bool single_regs;
 | |
|     uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register
 | |
|     uint32_t imm32; // stack offset
 | |
|     uint32_t regs;  // number of registers
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       single_regs = false;
 | |
|       d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
 | |
|       // If UInt(imm8) is odd, see "FLDMX".
 | |
|       regs = Bits32(opcode, 7, 0) / 2;
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if (regs == 0 || regs > 16 || (d + regs) > 32)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       single_regs = true;
 | |
|       d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
 | |
|       imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
 | |
|       regs = Bits32(opcode, 7, 0);
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if (regs == 0 || regs > 16 || (d + regs) > 32)
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
 | |
|     uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
 | |
|     addr_t sp_offset = imm32;
 | |
|     addr_t addr = sp;
 | |
|     uint32_t i;
 | |
|     uint64_t data; // uint64_t to accommodate 64-bit registers.
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextPopRegisterOffStack;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     for (i = 0; i < regs; ++i) {
 | |
|       GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
 | |
|       context.SetAddress(addr);
 | |
|       data = MemARead(context, addr, reg_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       if (!WriteRegisterUnsigned(context, &dwarf_reg, data))
 | |
|         return false;
 | |
|       addr += reg_byte_size;
 | |
|     }
 | |
| 
 | |
|     context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     context.SetImmediateSigned(sp_offset);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // SVC (previously SWI)
 | |
| bool EmulateInstructionARM::EmulateSVC(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         CallSupervisor();
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     addr_t lr; // next instruction address
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t imm32; // the immediate constant
 | |
|     uint32_t mode;  // ARM or Thumb mode
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       lr = (pc + 2) | 1u; // return address
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
|       mode = eModeThumb;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       lr = pc + 4; // return address
 | |
|       imm32 = Bits32(opcode, 23, 0);
 | |
|       mode = eModeARM;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextSupervisorCall;
 | |
|     context.SetISAAndImmediate(mode, imm32);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_RA, lr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // If Then makes up to four following instructions (the IT block) conditional.
 | |
| bool EmulateInstructionARM::EmulateIT(const uint32_t opcode,
 | |
|                                       const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     EncodingSpecificOperations();
 | |
|     ITSTATE.IT<7:0> = firstcond:mask;
 | |
| #endif
 | |
| 
 | |
|   m_it_session.InitIT(Bits32(opcode, 7, 0));
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::EmulateNop(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
|   // NOP, nothing to do...
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Branch causes a branch to a target address.
 | |
| bool EmulateInstructionARM::EmulateB(const uint32_t opcode,
 | |
|                                      const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations();
 | |
|         BranchWritePC(PC + imm32);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRelativeBranchImmediate;
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     addr_t target; // target address
 | |
|     int32_t imm32; // PC-relative offset
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
 | |
|       imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
 | |
|       target = pc + imm32;
 | |
|       context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1);
 | |
|       target = pc + imm32;
 | |
|       context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|       break;
 | |
|     case eEncodingT3:
 | |
|       // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
 | |
|       {
 | |
|         if (Bits32(opcode, 25, 23) == 7)
 | |
|           return false; // See Branches and miscellaneous control on page
 | |
|                         // A6-235.
 | |
| 
 | |
|         uint32_t S = Bit32(opcode, 26);
 | |
|         uint32_t imm6 = Bits32(opcode, 21, 16);
 | |
|         uint32_t J1 = Bit32(opcode, 13);
 | |
|         uint32_t J2 = Bit32(opcode, 11);
 | |
|         uint32_t imm11 = Bits32(opcode, 10, 0);
 | |
|         uint32_t imm21 =
 | |
|             (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
 | |
|         imm32 = llvm::SignExtend32<21>(imm21);
 | |
|         target = pc + imm32;
 | |
|         context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|         break;
 | |
|       }
 | |
|     case eEncodingT4: {
 | |
|       uint32_t S = Bit32(opcode, 26);
 | |
|       uint32_t imm10 = Bits32(opcode, 25, 16);
 | |
|       uint32_t J1 = Bit32(opcode, 13);
 | |
|       uint32_t J2 = Bit32(opcode, 11);
 | |
|       uint32_t imm11 = Bits32(opcode, 10, 0);
 | |
|       uint32_t I1 = !(J1 ^ S);
 | |
|       uint32_t I2 = !(J2 ^ S);
 | |
|       uint32_t imm25 =
 | |
|           (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
 | |
|       imm32 = llvm::SignExtend32<25>(imm25);
 | |
|       target = pc + imm32;
 | |
|       context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|       break;
 | |
|     }
 | |
|     case eEncodingA1:
 | |
|       imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
 | |
|       target = pc + imm32;
 | |
|       context.SetISAAndImmediateSigned(eModeARM, 8 + imm32);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     if (!BranchWritePC(context, target))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Compare and Branch on Nonzero and Compare and Branch on Zero compare the
 | |
| // value in a register with zero and conditionally branch forward a constant
 | |
| // value.  They do not affect the condition flags. CBNZ, CBZ
 | |
| bool EmulateInstructionARM::EmulateCB(const uint32_t opcode,
 | |
|                                       const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     EncodingSpecificOperations();
 | |
|     if nonzero ^ IsZero(R[n]) then
 | |
|         BranchWritePC(PC + imm32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Bits32(opcode, 2, 0), &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextRelativeBranchImmediate;
 | |
|   const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   addr_t target;  // target address
 | |
|   uint32_t imm32; // PC-relative offset to branch forward
 | |
|   bool nonzero;
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
 | |
|     nonzero = BitIsSet(opcode, 11);
 | |
|     target = pc + imm32;
 | |
|     context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   if (m_ignore_conditions || (nonzero ^ (reg_val == 0)))
 | |
|     if (!BranchWritePC(context, target))
 | |
|       return false;
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Table Branch Byte causes a PC-relative forward branch using a table of
 | |
| // single byte offsets.
 | |
| // A base register provides a pointer to the table, and a second register
 | |
| // supplies an index into the table.
 | |
| // The branch length is twice the value of the byte returned from the table.
 | |
| //
 | |
| // Table Branch Halfword causes a PC-relative forward branch using a table of
 | |
| // single halfword offsets.
 | |
| // A base register provides a pointer to the table, and a second register
 | |
| // supplies an index into the table.
 | |
| // The branch length is twice the value of the halfword returned from the
 | |
| // table. TBB, TBH
 | |
| bool EmulateInstructionARM::EmulateTB(const uint32_t opcode,
 | |
|                                       const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     if is_tbh then
 | |
|         halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]);
 | |
|     else
 | |
|         halfwords = UInt(MemU[R[n]+R[m], 1]);
 | |
|     BranchWritePC(PC + 2*halfwords);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rn; // the base register which contains the address of the table of
 | |
|                  // branch lengths
 | |
|     uint32_t Rm; // the index register which contains an integer pointing to a
 | |
|                  // byte/halfword in the table
 | |
|     bool is_tbh; // true if table branch halfword
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       is_tbh = BitIsSet(opcode, 4);
 | |
|       if (Rn == 13 || BadReg(Rm))
 | |
|         return false;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the address of the table from the operand register Rn. The PC can
 | |
|     // be used, in which case the table immediately follows this instruction.
 | |
|     uint32_t base = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // the table index
 | |
|     uint32_t index = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // the offsetted table address
 | |
|     addr_t addr = base + (is_tbh ? index * 2 : index);
 | |
| 
 | |
|     // PC-relative offset to branch forward
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextTableBranchReadMemory;
 | |
|     uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // target address
 | |
|     addr_t target = pc + offset;
 | |
|     context.type = EmulateInstruction::eContextRelativeBranchImmediate;
 | |
|     context.SetISAAndImmediateSigned(eModeThumb, 4 + offset);
 | |
| 
 | |
|     if (!BranchWritePC(context, target))
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction adds an immediate value to a register value, and writes the
 | |
| // result to the destination register. It can optionally update the condition
 | |
| // flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateADDImmThumb(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); 
 | |
|         R[d] = result; 
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     bool setflags;
 | |
|     uint32_t imm32;
 | |
|     uint32_t carry_out;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 =
 | |
|       // ZeroExtend(imm3, 32);
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       imm32 = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 =
 | |
|       // ZeroExtend(imm8, 32);
 | |
|       d = Bits32(opcode, 10, 8);
 | |
|       n = Bits32(opcode, 10, 8);
 | |
|       setflags = !InITBlock();
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if Rd == '1111' && S == '1' then SEE CMN (immediate);
 | |
|       // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 =
 | |
|       // ThumbExpandImm(i:imm3:imm8);
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out);
 | |
| 
 | |
|       // if Rn == '1101' then SEE ADD (SP plus immediate);
 | |
|       if (n == 13)
 | |
|         return EmulateADDSPImm(opcode, eEncodingT3);
 | |
| 
 | |
|       // if BadReg(d) || n == 15 then UNPREDICTABLE;
 | |
|       if (BadReg(d) || (n == 15))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT4: {
 | |
|       // if Rn == '1111' then SEE ADR;
 | |
|       // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 =
 | |
|       // ZeroExtend(i:imm3:imm8, 32);
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       setflags = false;
 | |
|       uint32_t i = Bit32(opcode, 26);
 | |
|       uint32_t imm3 = Bits32(opcode, 14, 12);
 | |
|       uint32_t imm8 = Bits32(opcode, 7, 0);
 | |
|       imm32 = (i << 11) | (imm3 << 8) | imm8;
 | |
| 
 | |
|       // if Rn == '1101' then SEE ADD (SP plus immediate);
 | |
|       if (n == 13)
 | |
|         return EmulateADDSPImm(opcode, eEncodingT4);
 | |
| 
 | |
|       // if BadReg(d) then UNPREDICTABLE;
 | |
|       if (BadReg(d))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
 | |
|     AddWithCarryResult res = AddWithCarry(Rn, imm32, 0);
 | |
| 
 | |
|     RegisterInfo reg_n;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     context.SetRegisterPlusOffset(reg_n, imm32);
 | |
| 
 | |
|     // R[d] = result;
 | |
|     // if setflags then
 | |
|     // APSR.N = result<31>;
 | |
|     // APSR.Z = IsZeroBit(result);
 | |
|     // APSR.C = carry;
 | |
|     // APSR.V = overflow;
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction adds an immediate value to a register value, and writes the
 | |
| // result to the destination register.  It can optionally update the condition
 | |
| // flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode,
 | |
|                                              const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be added to the value obtained from Rn
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(val1, imm32, 0);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == 13)
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     else if (Rd == GetFramePointerRegisterNumber())
 | |
|       context.type = EmulateInstruction::eContextSetFramePointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, Rn, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, imm32);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction adds a register value and an optionally-shifted register
 | |
| // value, and writes the result to the destination register. It can optionally
 | |
| // update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateADDReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 2, 0);
 | |
|       Rn = Bits32(opcode, 5, 3);
 | |
|       Rm = Bits32(opcode, 8, 6);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 6, 3);
 | |
|       setflags = false;
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       if (Rn == 15 && Rm == 15)
 | |
|         return false;
 | |
|       if (Rd == 15 && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     RegisterInfo op1_reg;
 | |
|     RegisterInfo op2_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn, op1_reg);
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, op2_reg);
 | |
|     context.SetRegisterRegisterOperands(op1_reg, op2_reg);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Compare Negative (immediate) adds a register value and an immediate value.
 | |
| // It updates the condition flags based on the result, and discards the result.
 | |
| bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rn;    // the first operand
 | |
|   uint32_t imm32; // the immediate value to be compared with
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|     if (Rn == 15)
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(reg_val, imm32, 0);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteFlags(context, res.result, res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Compare Negative (register) adds a register value and an optionally-shifted
 | |
| // register value. It updates the condition flags based on the result, and
 | |
| // discards the result.
 | |
| bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rn; // the first operand
 | |
|   uint32_t Rm; // the second operand
 | |
|   ARM_ShifterType shift_t;
 | |
|   uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rn = Bits32(opcode, 2, 0);
 | |
|     Rm = Bits32(opcode, 5, 3);
 | |
|     shift_t = SRType_LSL;
 | |
|     shift_n = 0;
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|     // if n == 15 || BadReg(m) then UNPREDICTABLE;
 | |
|     if (Rn == 15 || BadReg(Rm))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from register Rn.
 | |
|   uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   // Read the register value from register Rm.
 | |
|   uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
|   AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteFlags(context, res.result, res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Compare (immediate) subtracts an immediate value from a register value. It
 | |
| // updates the condition flags based on the result, and discards the result.
 | |
| bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rn;    // the first operand
 | |
|   uint32_t imm32; // the immediate value to be compared with
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rn = Bits32(opcode, 10, 8);
 | |
|     imm32 = Bits32(opcode, 7, 0);
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|     if (Rn == 15)
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteFlags(context, res.result, res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Compare (register) subtracts an optionally-shifted register value from a
 | |
| // register value. It updates the condition flags based on the result, and
 | |
| // discards the result.
 | |
| bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rn; // the first operand
 | |
|   uint32_t Rm; // the second operand
 | |
|   ARM_ShifterType shift_t;
 | |
|   uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rn = Bits32(opcode, 2, 0);
 | |
|     Rm = Bits32(opcode, 5, 3);
 | |
|     shift_t = SRType_LSL;
 | |
|     shift_n = 0;
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
 | |
|     Rm = Bits32(opcode, 6, 3);
 | |
|     shift_t = SRType_LSL;
 | |
|     shift_n = 0;
 | |
|     if (Rn < 8 && Rm < 8)
 | |
|       return false;
 | |
|     if (Rn == 15 || Rm == 15)
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingT3:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|     if (Rn == 15 || BadReg(Rm))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from register Rn.
 | |
|   uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   // Read the register value from register Rm.
 | |
|   uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
|   AddWithCarryResult res = AddWithCarry(val1, ~shifted, 1);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteFlags(context, res.result, res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Arithmetic Shift Right (immediate) shifts a register value right by an
 | |
| // immediate number of bits, shifting in copies of its sign bit, and writes the
 | |
| // result to the destination register.  It can optionally update the condition
 | |
| // flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftImm(opcode, encoding, SRType_ASR);
 | |
| }
 | |
| 
 | |
| // Arithmetic Shift Right (register) shifts a register value right by a
 | |
| // variable number of bits, shifting in copies of its sign bit, and writes the
 | |
| // result to the destination register. The variable number of bits is read from
 | |
| // the bottom byte of a register. It can optionally update the condition flags
 | |
| // based on the result.
 | |
| bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shift_n = UInt(R[m]<7:0>);
 | |
|         (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftReg(opcode, encoding, SRType_ASR);
 | |
| }
 | |
| 
 | |
| // Logical Shift Left (immediate) shifts a register value left by an immediate
 | |
| // number of bits, shifting in zeros, and writes the result to the destination
 | |
| // register.  It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftImm(opcode, encoding, SRType_LSL);
 | |
| }
 | |
| 
 | |
| // Logical Shift Left (register) shifts a register value left by a variable
 | |
| // number of bits, shifting in zeros, and writes the result to the destination
 | |
| // register.  The variable number of bits is read from the bottom byte of a
 | |
| // register. It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shift_n = UInt(R[m]<7:0>);
 | |
|         (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftReg(opcode, encoding, SRType_LSL);
 | |
| }
 | |
| 
 | |
| // Logical Shift Right (immediate) shifts a register value right by an
 | |
| // immediate number of bits, shifting in zeros, and writes the result to the
 | |
| // destination register.  It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftImm(opcode, encoding, SRType_LSR);
 | |
| }
 | |
| 
 | |
| // Logical Shift Right (register) shifts a register value right by a variable
 | |
| // number of bits, shifting in zeros, and writes the result to the destination
 | |
| // register.  The variable number of bits is read from the bottom byte of a
 | |
| // register. It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shift_n = UInt(R[m]<7:0>);
 | |
|         (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftReg(opcode, encoding, SRType_LSR);
 | |
| }
 | |
| 
 | |
| // Rotate Right (immediate) provides the value of the contents of a register
 | |
| // rotated by a constant value. The bits that are rotated off the right end are
 | |
| // inserted into the vacated bit positions on the left. It can optionally
 | |
| // update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftImm(opcode, encoding, SRType_ROR);
 | |
| }
 | |
| 
 | |
| // Rotate Right (register) provides the value of the contents of a register
 | |
| // rotated by a variable number of bits. The bits that are rotated off the
 | |
| // right end are inserted into the vacated bit positions on the left. The
 | |
| // variable number of bits is read from the bottom byte of a register. It can
 | |
| // optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shift_n = UInt(R[m]<7:0>);
 | |
|         (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftReg(opcode, encoding, SRType_ROR);
 | |
| }
 | |
| 
 | |
| // Rotate Right with Extend provides the value of the contents of a register
 | |
| // shifted right by one place, with the carry flag shifted into bit [31].
 | |
| //
 | |
| // RRX can optionally update the condition flags based on the result.
 | |
| // In that case, bit [0] is shifted into the carry flag.
 | |
| bool EmulateInstructionARM::EmulateRRX(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   return EmulateShiftImm(opcode, encoding, SRType_RRX);
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::EmulateShiftImm(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding,
 | |
|                                             ARM_ShifterType shift_type) {
 | |
|   //    assert(shift_type == SRType_ASR
 | |
|   //           || shift_type == SRType_LSL
 | |
|   //           || shift_type == SRType_LSR
 | |
|   //           || shift_type == SRType_ROR
 | |
|   //           || shift_type == SRType_RRX);
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd;    // the destination register
 | |
|     uint32_t Rm;    // the first operand register
 | |
|     uint32_t imm5;  // encoding for the shift amount
 | |
|     uint32_t carry; // the carry bit after the shift operation
 | |
|     bool setflags;
 | |
| 
 | |
|     // Special case handling!
 | |
|     // A8.6.139 ROR (immediate) -- Encoding T1
 | |
|     ARMEncoding use_encoding = encoding;
 | |
|     if (shift_type == SRType_ROR && use_encoding == eEncodingT1) {
 | |
|       // Morph the T1 encoding from the ARM Architecture Manual into T2
 | |
|       // encoding to have the same decoding of bit fields as the other Thumb2
 | |
|       // shift operations.
 | |
|       use_encoding = eEncodingT2;
 | |
|     }
 | |
| 
 | |
|     switch (use_encoding) {
 | |
|     case eEncodingT1:
 | |
|       // Due to the above special case handling!
 | |
|       if (shift_type == SRType_ROR)
 | |
|         return false;
 | |
| 
 | |
|       Rd = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       imm5 = Bits32(opcode, 10, 6);
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       // A8.6.141 RRX
 | |
|       // There's no imm form of RRX instructions.
 | |
|       if (shift_type == SRType_RRX)
 | |
|         return false;
 | |
| 
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6);
 | |
|       if (BadReg(Rd) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm5 = Bits32(opcode, 11, 7);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // A8.6.139 ROR (immediate)
 | |
|     if (shift_type == SRType_ROR && imm5 == 0)
 | |
|       shift_type = SRType_RRX;
 | |
| 
 | |
|     // Get the first operand.
 | |
|     uint32_t value = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Decode the shift amount if not RRX.
 | |
|     uint32_t amt =
 | |
|         (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5));
 | |
| 
 | |
|     uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // The context specifies that an immediate is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::EmulateShiftReg(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding,
 | |
|                                             ARM_ShifterType shift_type) {
 | |
|   // assert(shift_type == SRType_ASR
 | |
|   //        || shift_type == SRType_LSL
 | |
|   //        || shift_type == SRType_LSR
 | |
|   //        || shift_type == SRType_ROR);
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd; // the destination register
 | |
|     uint32_t Rn; // the first operand register
 | |
|     uint32_t
 | |
|         Rm; // the register whose bottom byte contains the amount to shift by
 | |
|     uint32_t carry; // the carry bit after the shift operation
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 2, 0);
 | |
|       Rn = Rd;
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 3, 0);
 | |
|       Rm = Bits32(opcode, 11, 8);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       if (Rd == 15 || Rn == 15 || Rm == 15)
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Get the first operand.
 | |
|     uint32_t value = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     // Get the Rm register content.
 | |
|     uint32_t val = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Get the shift amount.
 | |
|     uint32_t amt = Bits32(val, 7, 0);
 | |
| 
 | |
|     uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // The context specifies that an immediate is to be moved into Rd.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDM loads multiple registers from consecutive memory locations, using an
 | |
| // address from a base register.  Optionally the address just above the highest
 | |
| // of those locations can be written back to the base register.
 | |
| bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed()
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE (n);
 | |
|         address = R[n];
 | |
|                   
 | |
|         for i = 0 to 14
 | |
|             if registers<i> == '1' then
 | |
|                 R[i] = MemA[address, 4]; address = address + 4;
 | |
|         if registers<15> == '1' then
 | |
|             LoadWritePC (MemA[address, 4]);
 | |
|                   
 | |
|         if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
 | |
|         if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
 | |
| 
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // n = UInt(Rn); registers = '00000000':register_list; wback =
 | |
|       // (registers<n> == '0');
 | |
|       n = Bits32(opcode, 10, 8);
 | |
|       registers = Bits32(opcode, 7, 0);
 | |
|       registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
 | |
|       wback = BitIsClear(registers, n);
 | |
|       // if BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 1)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       // if W == '1' && Rn == '1101' then SEE POP;
 | |
|       // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       registers = registers & 0xdfff; // Make sure bit 13 is zero.
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 2) ||
 | |
|           (BitIsSet(opcode, 14) && BitIsSet(opcode, 15)))
 | |
|         return false;
 | |
| 
 | |
|       // if registers<15> == '1' && InITBlock() && !LastInITBlock() then
 | |
|       // UNPREDICTABLE;
 | |
|       if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       // if wback && registers<n> == '1' then UNPREDICTABLE;
 | |
|       if (wback && BitIsSet(registers, n))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     const addr_t base_address =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
| 
 | |
|     for (int i = 0; i < 14; ++i) {
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|         context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
|         if (wback && (n == 13)) // Pop Instruction
 | |
|         {
 | |
|           context.type = EmulateInstruction::eContextPopRegisterOffStack;
 | |
|           context.SetAddress(base_address + offset);
 | |
|         }
 | |
| 
 | |
|         // R[i] = MemA [address, 4]; address = address + 4;
 | |
|         uint32_t data = MemARead(context, base_address + offset, addr_byte_size,
 | |
|                                  0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                    data))
 | |
|           return false;
 | |
| 
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       // LoadWritePC (MemA [address, 4]);
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|       context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
|       uint32_t data =
 | |
|           MemARead(context, base_address + offset, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // In ARMv5T and above, this is an interworking branch.
 | |
|       if (!LoadWritePC(context, data))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (wback && BitIsClear(registers, n)) {
 | |
|       // R[n] = R[n] + 4 * BitCount (registers)
 | |
|       int32_t offset = addr_byte_size * BitCount(registers);
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  base_address + offset))
 | |
|         return false;
 | |
|     }
 | |
|     if (wback && BitIsSet(registers, n))
 | |
|       // R[n] bits(32) UNKNOWN;
 | |
|       return WriteBits32Unknown(n);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDMDA loads multiple registers from consecutive memory locations using an
 | |
| // address from a base register.
 | |
| // The consecutive memory locations end at this address and the address just
 | |
| // below the lowest of those locations can optionally be written back to the
 | |
| // base register.
 | |
| bool EmulateInstructionARM::EmulateLDMDA(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         address = R[n] - 4*BitCount(registers) + 4;
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                   R[i] = MemA[address,4]; address = address + 4; 
 | |
|                   
 | |
|         if registers<15> == '1' then
 | |
|             LoadWritePC(MemA[address,4]);
 | |
|                   
 | |
|         if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); 
 | |
|         if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // address = R[n] - 4*BitCount(registers) + 4;
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn = ReadCoreReg(n, &success);
 | |
| 
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address =
 | |
|         Rn - (addr_byte_size * BitCount(registers)) + addr_byte_size;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
| 
 | |
|     // for i = 0 to 14
 | |
|     for (int i = 0; i < 14; ++i) {
 | |
|       // if registers<i> == '1' then
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         // R[i] = MemA[address,4]; address = address + 4;
 | |
|         context.SetRegisterPlusOffset(dwarf_reg, Rn - (address + offset));
 | |
|         uint32_t data =
 | |
|             MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                    data))
 | |
|           return false;
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then
 | |
|     //     LoadWritePC(MemA[address,4]);
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
|       uint32_t data =
 | |
|           MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // In ARMv5T and above, this is an interworking branch.
 | |
|       if (!LoadWritePC(context, data))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
 | |
|     if (wback && BitIsClear(registers, n)) {
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       offset = (addr_byte_size * BitCount(registers)) * -1;
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t addr = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
 | |
|     if (wback && BitIsSet(registers, n))
 | |
|       return WriteBits32Unknown(n);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDMDB loads multiple registers from consecutive memory locations using an
 | |
| // address from a base register.  The
 | |
| // consecutive memory locations end just below this address, and the address of
 | |
| // the lowest of those locations can be optionally written back to the base
 | |
| // register.
 | |
| bool EmulateInstructionARM::EmulateLDMDB(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         address = R[n] - 4*BitCount(registers);
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                   R[i] = MemA[address,4]; address = address + 4; 
 | |
|         if registers<15> == '1' then
 | |
|                   LoadWritePC(MemA[address,4]);
 | |
|                   
 | |
|         if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); 
 | |
|         if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       registers = registers & 0xdfff; // Make sure bit 13 is a zero.
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 2) ||
 | |
|           (BitIsSet(opcode, 14) && BitIsSet(opcode, 15)))
 | |
|         return false;
 | |
| 
 | |
|       // if registers<15> == '1' && InITBlock() && !LastInITBlock() then
 | |
|       // UNPREDICTABLE;
 | |
|       if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       // if wback && registers<n> == '1' then UNPREDICTABLE;
 | |
|       if (wback && BitIsSet(registers, n))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // address = R[n] - 4*BitCount(registers);
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
| 
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn - (addr_byte_size * BitCount(registers));
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, Rn - address);
 | |
| 
 | |
|     for (int i = 0; i < 14; ++i) {
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         // R[i] = MemA[address,4]; address = address + 4;
 | |
|         context.SetRegisterPlusOffset(dwarf_reg, Rn - (address + offset));
 | |
|         uint32_t data =
 | |
|             MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                    data))
 | |
|           return false;
 | |
| 
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then
 | |
|     //     LoadWritePC(MemA[address,4]);
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
|       uint32_t data =
 | |
|           MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // In ARMv5T and above, this is an interworking branch.
 | |
|       if (!LoadWritePC(context, data))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
 | |
|     if (wback && BitIsClear(registers, n)) {
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       offset = (addr_byte_size * BitCount(registers)) * -1;
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t addr = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only
 | |
|     // possible for encoding A1
 | |
|     if (wback && BitIsSet(registers, n))
 | |
|       return WriteBits32Unknown(n);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDMIB loads multiple registers from consecutive memory locations using an
 | |
| // address from a base register.  The
 | |
| // consecutive memory locations start just above this address, and thea ddress
 | |
| // of the last of those locations can optinoally be written back to the base
 | |
| // register.
 | |
| bool EmulateInstructionARM::EmulateLDMIB(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); 
 | |
|         address = R[n] + 4;
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                   R[i] = MemA[address,4]; address = address + 4; 
 | |
|         if registers<15> == '1' then
 | |
|             LoadWritePC(MemA[address,4]);
 | |
|                   
 | |
|         if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); 
 | |
|         if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // address = R[n] + 4;
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
| 
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn + addr_byte_size;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
| 
 | |
|     for (int i = 0; i < 14; ++i) {
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         // R[i] = MemA[address,4]; address = address + 4;
 | |
| 
 | |
|         context.SetRegisterPlusOffset(dwarf_reg, offset + addr_byte_size);
 | |
|         uint32_t data =
 | |
|             MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                    data))
 | |
|           return false;
 | |
| 
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then
 | |
|     //     LoadWritePC(MemA[address,4]);
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       context.SetRegisterPlusOffset(dwarf_reg, offset);
 | |
|       uint32_t data =
 | |
|           MemARead(context, address + offset, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // In ARMv5T and above, this is an interworking branch.
 | |
|       if (!LoadWritePC(context, data))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
 | |
|     if (wback && BitIsClear(registers, n)) {
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       offset = addr_byte_size * BitCount(registers);
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t addr = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only
 | |
|     // possible for encoding A1
 | |
|     if (wback && BitIsSet(registers, n))
 | |
|       return WriteBits32Unknown(n);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Load Register (immediate) calculates an address from a base register value
 | |
| // and an immediate offset, loads a word from memory, and writes to a register.
 | |
| // LDR (immediate, Thumb)
 | |
| bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if (ConditionPassed())
 | |
|     {
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15);
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         data = MemU[address,4];
 | |
|         if wback then R[n] = offset_addr;
 | |
|         if t == 15 then
 | |
|             if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
 | |
|         elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|             R[t] = data;
 | |
|         else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rt;        // the destination register
 | |
|     uint32_t Rn;        // the base register
 | |
|     uint32_t imm32;     // the immediate offset used to form the address
 | |
|     addr_t offset_addr; // the offset address
 | |
|     addr_t address;     // the calculated address
 | |
|     uint32_t data;      // the literal data value from memory load
 | |
|     bool add, index, wback;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rt = Bits32(opcode, 2, 0);
 | |
|       Rn = Bits32(opcode, 5, 3);
 | |
|       imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
 | |
|       // index = TRUE; add = TRUE; wback = FALSE
 | |
|       add = true;
 | |
|       index = true;
 | |
|       wback = false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       Rt = Bits32(opcode, 10, 8);
 | |
|       Rn = 13;
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if Rn == '1111' then SEE LDR (literal);
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
 | |
|       if ((Rt == 15) && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT4:
 | |
|       // if Rn == '1111' then SEE LDR (literal);
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE LDRT;
 | |
|       // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 ==
 | |
|       // '00000100' then SEE POP;
 | |
|       // if P == '0' && W == '0' then UNDEFINED;
 | |
|       if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       Rt = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock())
 | |
|       // then UNPREDICTABLE;
 | |
|       if ((wback && (Rn == Rt)) ||
 | |
|           ((Rt == 15) && InITBlock() && !LastInITBlock()))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     uint32_t base = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     if (add)
 | |
|       offset_addr = base + imm32;
 | |
|     else
 | |
|       offset_addr = base - imm32;
 | |
| 
 | |
|     address = (index ? offset_addr : base);
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn, base_reg);
 | |
|     if (wback) {
 | |
|       EmulateInstruction::Context ctx;
 | |
|       if (Rn == 13) {
 | |
|         ctx.type = eContextAdjustStackPointer;
 | |
|         ctx.SetImmediateSigned((int32_t)(offset_addr - base));
 | |
|       } else if (Rn == GetFramePointerRegisterNumber()) {
 | |
|         ctx.type = eContextSetFramePointer;
 | |
|         ctx.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base));
 | |
|       } else {
 | |
|         ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|         ctx.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base));
 | |
|       }
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(ctx, eRegisterKindDWARF, dwarf_r0 + Rn,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // Prepare to write to the Rt register.
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base));
 | |
| 
 | |
|     // Read memory from the address.
 | |
|     data = MemURead(context, address, 4, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (Rt == 15) {
 | |
|       if (Bits32(address, 1, 0) == 0) {
 | |
|         if (!LoadWritePC(context, data))
 | |
|           return false;
 | |
|       } else
 | |
|         return false;
 | |
|     } else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) {
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rt,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else
 | |
|       WriteBits32Unknown(Rt);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STM (Store Multiple Increment After) stores multiple registers to consecutive
 | |
| // memory locations using an address
 | |
| // from a base register.  The consecutive memory locations start at this
 | |
| // address, and the address just above the last of those locations can
 | |
| // optionally be written back to the base register.
 | |
| bool EmulateInstructionARM::EmulateSTM(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         address = R[n];
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                 if i == n && wback && i != LowestSetBit(registers) then 
 | |
|                     MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1
 | |
|                 else 
 | |
|                     MemA[address,4] = R[i];
 | |
|                 address = address + 4;
 | |
|                   
 | |
|         if registers<15> == '1' then // Only possible for encoding A1 
 | |
|             MemA[address,4] = PCStoreValue();
 | |
|         if wback then R[n] = R[n] + 4*BitCount(registers);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE;
 | |
|       n = Bits32(opcode, 10, 8);
 | |
|       registers = Bits32(opcode, 7, 0);
 | |
|       registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
 | |
|       wback = true;
 | |
| 
 | |
|       // if BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if (BitCount(registers) < 1)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 2))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && registers<n> == '1' then UNPREDICTABLE;
 | |
|       if (wback && BitIsSet(registers, n))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // address = R[n];
 | |
|     int32_t offset = 0;
 | |
|     const addr_t address =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterStore;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     // for i = 0 to 14
 | |
|     uint32_t lowest_set_bit = 14;
 | |
|     for (uint32_t i = 0; i < 14; ++i) {
 | |
|       // if registers<i> == '1' then
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         if (i < lowest_set_bit)
 | |
|           lowest_set_bit = i;
 | |
|         // if i == n && wback && i != LowestSetBit(registers) then
 | |
|         if ((i == n) && wback && (i != lowest_set_bit))
 | |
|           // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings
 | |
|           // T1 and A1
 | |
|           WriteBits32UnknownToMemory(address + offset);
 | |
|         else {
 | |
|           // MemA[address,4] = R[i];
 | |
|           uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                                0, &success);
 | |
|           if (!success)
 | |
|             return false;
 | |
| 
 | |
|           RegisterInfo data_reg;
 | |
|           GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg);
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, offset);
 | |
|           if (!MemAWrite(context, address + offset, data, addr_byte_size))
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // address = address + 4;
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then // Only possible for encoding A1
 | |
|     //     MemA[address,4] = PCStoreValue();
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       RegisterInfo pc_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg);
 | |
|       context.SetRegisterPlusOffset(pc_reg, 8);
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address + offset, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = R[n] + 4*BitCount(registers);
 | |
|     if (wback) {
 | |
|       offset = addr_byte_size * BitCount(registers);
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t data = address + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STMDA (Store Multiple Decrement After) stores multiple registers to
 | |
| // consecutive memory locations using an address from a base register.  The
 | |
| // consecutive memory locations end at this address, and the address just below
 | |
| // the lowest of those locations can optionally be written back to the base
 | |
| // register.
 | |
| bool EmulateInstructionARM::EmulateSTMDA(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations();                   
 | |
|         address = R[n] - 4*BitCount(registers) + 4;
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                 if i == n && wback && i != LowestSetBit(registers) then 
 | |
|                     MemA[address,4] = bits(32) UNKNOWN;
 | |
|                 else 
 | |
|                     MemA[address,4] = R[i];
 | |
|                 address = address + 4;
 | |
|                   
 | |
|         if registers<15> == '1' then 
 | |
|             MemA[address,4] = PCStoreValue();
 | |
|                   
 | |
|         if wback then R[n] = R[n] - 4*BitCount(registers);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || (BitCount(registers) < 1))
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // address = R[n] - 4*BitCount(registers) + 4;
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn - (addr_byte_size * BitCount(registers)) + 4;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterStore;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     // for i = 0 to 14
 | |
|     uint32_t lowest_bit_set = 14;
 | |
|     for (uint32_t i = 0; i < 14; ++i) {
 | |
|       // if registers<i> == '1' then
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         if (i < lowest_bit_set)
 | |
|           lowest_bit_set = i;
 | |
|         // if i == n && wback && i != LowestSetBit(registers) then
 | |
|         if ((i == n) && wback && (i != lowest_bit_set))
 | |
|           // MemA[address,4] = bits(32) UNKNOWN;
 | |
|           WriteBits32UnknownToMemory(address + offset);
 | |
|         else {
 | |
|           // MemA[address,4] = R[i];
 | |
|           uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                                0, &success);
 | |
|           if (!success)
 | |
|             return false;
 | |
| 
 | |
|           RegisterInfo data_reg;
 | |
|           GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg);
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   Rn - (address + offset));
 | |
|           if (!MemAWrite(context, address + offset, data, addr_byte_size))
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // address = address + 4;
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then
 | |
|     //    MemA[address,4] = PCStoreValue();
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       RegisterInfo pc_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg);
 | |
|       context.SetRegisterPlusOffset(pc_reg, 8);
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address + offset, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = R[n] - 4*BitCount(registers);
 | |
|     if (wback) {
 | |
|       offset = (addr_byte_size * BitCount(registers)) * -1;
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t data = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STMDB (Store Multiple Decrement Before) stores multiple registers to
 | |
| // consecutive memory locations using an address from a base register.  The
 | |
| // consecutive memory locations end just below this address, and the address of
 | |
| // the first of those locations can optionally be written back to the base
 | |
| // register.
 | |
| bool EmulateInstructionARM::EmulateSTMDB(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         address = R[n] - 4*BitCount(registers);
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                 if i == n && wback && i != LowestSetBit(registers) then 
 | |
|                     MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1
 | |
|                 else 
 | |
|                     MemA[address,4] = R[i];
 | |
|                 address = address + 4;
 | |
|                   
 | |
|         if registers<15> == '1' then // Only possible for encoding A1 
 | |
|             MemA[address,4] = PCStoreValue();
 | |
|                   
 | |
|         if wback then R[n] = R[n] - 4*BitCount(registers);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if W == '1' && Rn == '1101' then SEE PUSH;
 | |
|       if ((BitIsSet(opcode, 21)) && (Bits32(opcode, 19, 16) == 13)) {
 | |
|         // See PUSH
 | |
|       }
 | |
|       // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
 | |
|       if ((n == 15) || BitCount(registers) < 2)
 | |
|         return false;
 | |
|       // if wback && registers<n> == '1' then UNPREDICTABLE;
 | |
|       if (wback && BitIsSet(registers, n))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if W == '1' && Rn == '1101' && BitCount(register_list) >= 2 then SEE
 | |
|       // PUSH;
 | |
|       if (BitIsSet(opcode, 21) && (Bits32(opcode, 19, 16) == 13) &&
 | |
|           BitCount(Bits32(opcode, 15, 0)) >= 2) {
 | |
|         // See Push
 | |
|       }
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) || BitCount(registers) < 1)
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // address = R[n] - 4*BitCount(registers);
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn - (addr_byte_size * BitCount(registers));
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterStore;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     // for i = 0 to 14
 | |
|     uint32_t lowest_set_bit = 14;
 | |
|     for (uint32_t i = 0; i < 14; ++i) {
 | |
|       // if registers<i> == '1' then
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         if (i < lowest_set_bit)
 | |
|           lowest_set_bit = i;
 | |
|         // if i == n && wback && i != LowestSetBit(registers) then
 | |
|         if ((i == n) && wback && (i != lowest_set_bit))
 | |
|           // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding
 | |
|           // A1
 | |
|           WriteBits32UnknownToMemory(address + offset);
 | |
|         else {
 | |
|           // MemA[address,4] = R[i];
 | |
|           uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                                0, &success);
 | |
|           if (!success)
 | |
|             return false;
 | |
| 
 | |
|           RegisterInfo data_reg;
 | |
|           GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg);
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   Rn - (address + offset));
 | |
|           if (!MemAWrite(context, address + offset, data, addr_byte_size))
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // address = address + 4;
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then // Only possible for encoding A1
 | |
|     //     MemA[address,4] = PCStoreValue();
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       RegisterInfo pc_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg);
 | |
|       context.SetRegisterPlusOffset(pc_reg, 8);
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address + offset, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = R[n] - 4*BitCount(registers);
 | |
|     if (wback) {
 | |
|       offset = (addr_byte_size * BitCount(registers)) * -1;
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t data = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STMIB (Store Multiple Increment Before) stores multiple registers to
 | |
| // consecutive memory locations using an address from a base register.  The
 | |
| // consecutive memory locations start just above this address, and the address
 | |
| // of the last of those locations can optionally be written back to the base
 | |
| // register.
 | |
| bool EmulateInstructionARM::EmulateSTMIB(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         address = R[n] + 4;
 | |
|                   
 | |
|         for i = 0 to 14 
 | |
|             if registers<i> == '1' then
 | |
|                 if i == n && wback && i != LowestSetBit(registers) then
 | |
|                     MemA[address,4] = bits(32) UNKNOWN;
 | |
|                 else 
 | |
|                     MemA[address,4] = R[i];
 | |
|                 address = address + 4;
 | |
|                   
 | |
|         if registers<15> == '1' then 
 | |
|             MemA[address,4] = PCStoreValue();
 | |
|                   
 | |
|         if wback then R[n] = R[n] + 4*BitCount(registers);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t registers = 0;
 | |
|     bool wback;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); registers = register_list; wback = (W == '1');
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       registers = Bits32(opcode, 15, 0);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
 | |
|       if ((n == 15) && (BitCount(registers) < 1))
 | |
|         return false;
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // address = R[n] + 4;
 | |
| 
 | |
|     int32_t offset = 0;
 | |
|     addr_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn + addr_byte_size;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextRegisterStore;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t lowest_set_bit = 14;
 | |
|     // for i = 0 to 14
 | |
|     for (uint32_t i = 0; i < 14; ++i) {
 | |
|       // if registers<i> == '1' then
 | |
|       if (BitIsSet(registers, i)) {
 | |
|         if (i < lowest_set_bit)
 | |
|           lowest_set_bit = i;
 | |
|         // if i == n && wback && i != LowestSetBit(registers) then
 | |
|         if ((i == n) && wback && (i != lowest_set_bit))
 | |
|           // MemA[address,4] = bits(32) UNKNOWN;
 | |
|           WriteBits32UnknownToMemory(address + offset);
 | |
|         // else
 | |
|         else {
 | |
|           // MemA[address,4] = R[i];
 | |
|           uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
 | |
|                                                0, &success);
 | |
|           if (!success)
 | |
|             return false;
 | |
| 
 | |
|           RegisterInfo data_reg;
 | |
|           GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg);
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   offset + addr_byte_size);
 | |
|           if (!MemAWrite(context, address + offset, data, addr_byte_size))
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // address = address + 4;
 | |
|         offset += addr_byte_size;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // if registers<15> == '1' then
 | |
|     // MemA[address,4] = PCStoreValue();
 | |
|     if (BitIsSet(registers, 15)) {
 | |
|       RegisterInfo pc_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg);
 | |
|       context.SetRegisterPlusOffset(pc_reg, 8);
 | |
|       const uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address + offset, pc, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = R[n] + 4*BitCount(registers);
 | |
|     if (wback) {
 | |
|       offset = addr_byte_size * BitCount(registers);
 | |
|       context.type = EmulateInstruction::eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(offset);
 | |
|       addr_t data = Rn + offset;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STR (store immediate) calculates an address from a base register value and an
 | |
| // immediate offset, and stores a word
 | |
| // from a register to memory.  It can use offset, post-indexed, or pre-indexed
 | |
| // addressing.
 | |
| bool EmulateInstructionARM::EmulateSTRThumb(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         if UnalignedSupport() || address<1:0> == '00' then
 | |
|             MemU[address,4] = R[t]; 
 | |
|         else // Can only occur before ARMv7
 | |
|             MemU[address,4] = bits(32) UNKNOWN; 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       imm32 = Bits32(opcode, 10, 6) << 2;
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = false;
 | |
|       wback = false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       t = Bits32(opcode, 10, 8);
 | |
|       n = 13;
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if Rn == '1111' then UNDEFINED;
 | |
|       if (Bits32(opcode, 19, 16) == 15)
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT4:
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE STRT;
 | |
|       // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 ==
 | |
|       // '00000100' then SEE PUSH;
 | |
|       // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
 | |
|       if ((Bits32(opcode, 19, 16) == 15) ||
 | |
|           (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if t == 15 || (wback && n == t) then UNPREDICTABLE;
 | |
|       if ((t == 15) || (wback && (n == t)))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint32_t base_address = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (add)
 | |
|       offset_addr = base_address + imm32;
 | |
|     else
 | |
|       offset_addr = base_address - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = base_address;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (n == 13)
 | |
|       context.type = eContextPushRegisterOnStack;
 | |
|     else
 | |
|       context.type = eContextRegisterStore;
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     // if UnalignedSupport() || address<1:0> == '00' then
 | |
|     if (UnalignedSupport() ||
 | |
|         (BitIsClear(address, 1) && BitIsClear(address, 0))) {
 | |
|       // MemU[address,4] = R[t];
 | |
|       uint32_t data =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       RegisterInfo data_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|       int32_t offset = address - base_address;
 | |
|       context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, offset);
 | |
|       if (!MemUWrite(context, address, data, addr_byte_size))
 | |
|         return false;
 | |
|     } else {
 | |
|       // MemU[address,4] = bits(32) UNKNOWN;
 | |
|       WriteBits32UnknownToMemory(address);
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       if (n == 13)
 | |
|         context.type = eContextAdjustStackPointer;
 | |
|       else
 | |
|         context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STR (Store Register) calculates an address from a base register value and an
 | |
| // offset register value, stores a
 | |
| // word from a register to memory.   The offset register value can optionally
 | |
| // be shifted.
 | |
| bool EmulateInstructionARM::EmulateSTRRegister(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         if t == 15 then // Only possible for encoding A1
 | |
|             data = PCStoreValue(); 
 | |
|         else
 | |
|             data = R[t]; 
 | |
|         if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
 | |
|             MemU[address,4] = data; 
 | |
|         else // Can only occur before ARMv7
 | |
|             MemU[address,4] = bits(32) UNKNOWN; 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation
 | |
|       // in ThumbEE";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then UNDEFINED;
 | |
|       if (Bits32(opcode, 19, 16) == 15)
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if t == 15 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((t == 15) || (BadReg(m)))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // if P == '0' && W == '1' then SEE STRT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       uint32_t typ = Bits32(opcode, 6, 5);
 | |
|       uint32_t imm5 = Bits32(opcode, 11, 7);
 | |
|       shift_n = DecodeImmShift(typ, imm5, shift_t);
 | |
| 
 | |
|       // if m == 15 then UNPREDICTABLE;
 | |
|       if (m == 15)
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
|     int32_t offset = 0;
 | |
| 
 | |
|     addr_t base_address =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t Rm_data =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     offset = Shift(Rm_data, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     if (add)
 | |
|       offset_addr = base_address + offset;
 | |
|     else
 | |
|       offset_addr = base_address - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = base_address;
 | |
| 
 | |
|     uint32_t data;
 | |
|     // if t == 15 then // Only possible for encoding A1
 | |
|     if (t == 15)
 | |
|       // data = PCStoreValue();
 | |
|       data = ReadCoreReg(PC_REG, &success);
 | |
|     else
 | |
|       // data = R[t];
 | |
|       data =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
 | |
| 
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
| 
 | |
|     // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() ==
 | |
|     // InstrSet_ARM then
 | |
|     if (UnalignedSupport() ||
 | |
|         (BitIsClear(address, 1) && BitIsClear(address, 0)) ||
 | |
|         CurrentInstrSet() == eModeARM) {
 | |
|       // MemU[address,4] = data;
 | |
| 
 | |
|       RegisterInfo base_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|       RegisterInfo data_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
| 
 | |
|       context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                               address - base_address);
 | |
|       if (!MemUWrite(context, address, data, addr_byte_size))
 | |
|         return false;
 | |
| 
 | |
|     } else
 | |
|       // MemU[address,4] = bits(32) UNKNOWN;
 | |
|       WriteBits32UnknownToMemory(address);
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::EmulateSTRBThumb(const uint32_t opcode,
 | |
|                                              const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         MemU[address,1] = R[t]<7:0>; 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       imm32 = Bits32(opcode, 10, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then UNDEFINED;
 | |
|       if (Bits32(opcode, 19, 16) == 15)
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if BadReg(t) then UNPREDICTABLE;
 | |
|       if (BadReg(t))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE STRBT;
 | |
|       // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
 | |
|       if (Bits32(opcode, 19, 16) == 15)
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if BadReg(t) || (wback && n == t) then UNPREDICTABLE
 | |
|       if ((BadReg(t)) || (wback && (n == t)))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
|     addr_t base_address =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     if (add)
 | |
|       offset_addr = base_address + imm32;
 | |
|     else
 | |
|       offset_addr = base_address - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = base_address;
 | |
| 
 | |
|     // MemU[address,1] = R[t]<7:0>
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                             address - base_address);
 | |
| 
 | |
|     uint32_t data =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     data = Bits32(data, 7, 0);
 | |
| 
 | |
|     if (!MemUWrite(context, address, data, 1))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // STRH (register) calculates an address from a base register value and an
 | |
| // offset register value, and stores a
 | |
| // halfword from a register to memory.  The offset register value can be
 | |
| // shifted left by 0, 1, 2, or 3 bits.
 | |
| bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         if UnalignedSupport() || address<0> == '0' then
 | |
|             MemU[address,2] = R[t]<15:0>; 
 | |
|         else // Can only occur before ARMv7
 | |
|             MemU[address,2] = bits(16) UNKNOWN; 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation
 | |
|       // in ThumbEE";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then UNDEFINED;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if BadReg(t) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(t) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE STRHT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       // if t == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     uint32_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> == '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // MemU[address,2] = R[t]<15:0>;
 | |
|       uint32_t Rt = ReadCoreReg(t, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       EmulateInstruction::Context context;
 | |
|       context.type = eContextRegisterStore;
 | |
|       RegisterInfo base_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|       RegisterInfo offset_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
|       RegisterInfo data_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|       context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg,
 | |
|                                                       data_reg);
 | |
| 
 | |
|       if (!MemUWrite(context, address, Bits32(Rt, 15, 0), 2))
 | |
|         return false;
 | |
|     } else // Can only occur before ARMv7
 | |
|     {
 | |
|       // MemU[address,2] = bits(16) UNKNOWN;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Add with Carry (immediate) adds an immediate value and the carry flag value
 | |
| // to a register value, and writes the result to the destination register.  It
 | |
| // can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be added to the value obtained from Rn
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|       if (BadReg(Rd) || BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     int32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(val1, imm32, APSR_C);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Add with Carry (register) adds a register value, the carry flag value, and
 | |
| // an optionally-shifted register value, and writes the result to the
 | |
| // destination register.  It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateADCReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     int32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     int32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     AddWithCarryResult res = AddWithCarry(val1, shifted, APSR_C);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction adds an immediate value to the PC value to form a PC-
 | |
| // relative address, and writes the result to the destination register.
 | |
| bool EmulateInstructionARM::EmulateADR(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32);
 | |
|         if d == 15 then         // Can only occur for ARM encodings
 | |
|             ALUWritePC(result);
 | |
|         else
 | |
|             R[d] = result;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd;
 | |
|     uint32_t imm32; // the immediate value to be added/subtracted to/from the PC
 | |
|     bool add;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 10, 8);
 | |
|       imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32)
 | |
|       add = true;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|     case eEncodingT3:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
 | |
|       add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB
 | |
|       if (BadReg(Rd))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|     case eEncodingA2:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       imm32 = ARMExpandImm(opcode);          // imm32 = ARMExpandImm(imm12)
 | |
|       add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the PC value.
 | |
|     uint32_t pc = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreReg(context, result, Rd))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction performs a bitwise AND of a register value and an immediate
 | |
| // value, and writes the result to the destination register.  It can optionally
 | |
| // update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] AND imm32;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be ANDed to the value obtained from Rn
 | |
|     bool setflags;
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       // if Rd == '1111' && S == '1' then SEE TST (immediate);
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateTSTImm(opcode, eEncodingT1);
 | |
|       if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 & imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This instruction performs a bitwise AND of a register value and an
 | |
| // optionally-shifted register value, and writes the result to the destination
 | |
| // register.  It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] AND shifted;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       // if Rd == '1111' && S == '1' then SEE TST (register);
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateTSTReg(opcode, eEncodingT2);
 | |
|       if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 & shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and
 | |
| // the complement of an immediate value, and writes the result to the
 | |
| // destination register.  It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] AND NOT(imm32);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to
 | |
|                     // the value obtained from Rn
 | |
|     bool setflags;
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       if (BadReg(Rd) || BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 & ~imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise Bit Clear (register) performs a bitwise AND of a register value and
 | |
| // the complement of an optionally-shifted register value, and writes the
 | |
| // result to the destination register. It can optionally update the condition
 | |
| // flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateBICReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] AND NOT(shifted);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 & ~shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDR (immediate, ARM) calculates an address from a base register value and an
 | |
| // immediate offset, loads a word
 | |
| // from memory, and writes it to a register.  It can use offset, post-indexed,
 | |
| // or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRImmediateARM(const uint32_t opcode,
 | |
|                                                    const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,4]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if t == 15 then
 | |
|             if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; 
 | |
|         elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|             R[t] = data; 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = ROR(data, 8*UInt(address<1:0>));
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // if Rn == '1111' then SEE LDR (literal);
 | |
|       // if P == '0' && W == '1' then SEE LDRT;
 | |
|       // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 ==
 | |
|       // '000000000100' then SEE POP;
 | |
|       // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // if wback && n == t then UNPREDICTABLE;
 | |
|       if (wback && (n == t))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     addr_t address;
 | |
|     addr_t offset_addr;
 | |
|     addr_t base_address = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     if (add)
 | |
|       offset_addr = base_address + imm32;
 | |
|     else
 | |
|       offset_addr = base_address - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = base_address;
 | |
| 
 | |
|     // data = MemU[address,4];
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - base_address);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if t == 15 then
 | |
|     if (t == 15) {
 | |
|       // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
 | |
|       if (BitIsClear(address, 1) && BitIsClear(address, 0)) {
 | |
|         // LoadWritePC (data);
 | |
|         context.type = eContextRegisterLoad;
 | |
|         context.SetRegisterPlusOffset(base_reg, address - base_address);
 | |
|         LoadWritePC(context, data);
 | |
|       } else
 | |
|         return false;
 | |
|     }
 | |
|     // elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|     else if (UnalignedSupport() ||
 | |
|              (BitIsClear(address, 1) && BitIsClear(address, 0))) {
 | |
|       // R[t] = data;
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - base_address);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|     // else // Can only apply before ARMv7
 | |
|     else {
 | |
|       // R[t] = ROR(data, 8*UInt(address<1:0>));
 | |
|       data = ROR(data, Bits32(address, 1, 0), &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetImmediate(data);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDR (register) calculates an address from a base register value and an offset
 | |
| // register value, loads a word
 | |
| // from memory, and writes it to a register.  The offset register value can
 | |
| // optionally be shifted.
 | |
| bool EmulateInstructionARM::EmulateLDRRegister(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,4]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if t == 15 then
 | |
|             if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; 
 | |
|         elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|             R[t] = data; 
 | |
|         else // Can only apply before ARMv7
 | |
|             if CurrentInstrSet() == InstrSet_ARM then 
 | |
|                 R[t] = ROR(data, 8*UInt(address<1:0>));
 | |
|             else 
 | |
|                 R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation
 | |
|       // in ThumbEE";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then SEE LDR (literal);
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
 | |
|       if ((t == 15) && InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // if P == '0' && W == '1' then SEE LDRT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       uint32_t type = Bits32(opcode, 6, 5);
 | |
|       uint32_t imm5 = Bits32(opcode, 11, 7);
 | |
|       shift_n = DecodeImmShift(type, imm5, shift_t);
 | |
| 
 | |
|       // if m == 15 then UNPREDICTABLE;
 | |
|       if (m == 15)
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint32_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);   -- Note "The APSR is
 | |
|     // an application level alias for the CPSR".
 | |
|     addr_t offset =
 | |
|         Shift(Rm, shift_t, shift_n, Bit32(m_opcode_cpsr, APSR_C), &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // data = MemU[address,4];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if t == 15 then
 | |
|     if (t == 15) {
 | |
|       // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
 | |
|       if (BitIsClear(address, 1) && BitIsClear(address, 0)) {
 | |
|         context.type = eContextRegisterLoad;
 | |
|         context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|         LoadWritePC(context, data);
 | |
|       } else
 | |
|         return false;
 | |
|     }
 | |
|     // elsif UnalignedSupport() || address<1:0> = '00' then
 | |
|     else if (UnalignedSupport() ||
 | |
|              (BitIsClear(address, 1) && BitIsClear(address, 0))) {
 | |
|       // R[t] = data;
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // if CurrentInstrSet() == InstrSet_ARM then
 | |
|       if (CurrentInstrSet() == eModeARM) {
 | |
|         // R[t] = ROR(data, 8*UInt(address<1:0>));
 | |
|         data = ROR(data, Bits32(address, 1, 0), &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
|         context.type = eContextRegisterLoad;
 | |
|         context.SetImmediate(data);
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                    data))
 | |
|           return false;
 | |
|       } else {
 | |
|         // R[t] = bits(32) UNKNOWN;
 | |
|         WriteBits32Unknown(t);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRB (immediate, Thumb)
 | |
| bool EmulateInstructionARM::EmulateLDRBImmediate(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         R[t] = ZeroExtend(MemU[address,1], 32); 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       imm32 = Bits32(opcode, 10, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if Rt == '1111' then SEE PLD;
 | |
|       if (t == 15)
 | |
|         return false; // PLD is not implemented yet
 | |
| 
 | |
|       // if Rn == '1111' then SEE LDRB (literal);
 | |
|       if (n == 15)
 | |
|         return EmulateLDRBLiteral(opcode, eEncodingT1);
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE LDRBT;
 | |
|       // if P == '0' && W == '0' then UNDEFINED;
 | |
|       if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
 | |
|       if (t == 15)
 | |
|         return false; // PLD is not implemented yet
 | |
| 
 | |
|       // if Rn == '1111' then SEE LDRB (literal);
 | |
|       if (n == 15)
 | |
|         return EmulateLDRBLiteral(opcode, eEncodingT1);
 | |
| 
 | |
|       // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
 | |
|       if (BadReg(t) || (wback && (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint32_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address;
 | |
|     addr_t offset_addr;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // R[t] = ZeroExtend(MemU[address,1], 32);
 | |
|     RegisterInfo base_reg;
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRB (literal) calculates an address from the PC value and an immediate
 | |
| // offset, loads a byte from memory,
 | |
| // zero-extends it to form a 32-bit word and writes it to a register.
 | |
| bool EmulateInstructionARM::EmulateLDRBLiteral(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15); 
 | |
|         base = Align(PC,4); 
 | |
|         address = if add then (base + imm32) else (base - imm32); 
 | |
|         R[t] = ZeroExtend(MemU[address,1], 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t imm32;
 | |
|     bool add;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if Rt == '1111' then SEE PLD;
 | |
|       if (t == 15)
 | |
|         return false; // PLD is not implemented yet
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // base = Align(PC,4);
 | |
|     uint32_t pc_val = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t base = AlignPC(pc_val);
 | |
| 
 | |
|     addr_t address;
 | |
|     // address = if add then (base + imm32) else (base - imm32);
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     // R[t] = ZeroExtend(MemU[address,1], 32);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRelativeBranchImmediate;
 | |
|     context.SetImmediate(address - base);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRB (register) calculates an address from a base register value and an
 | |
| // offset rigister value, loads a byte from memory, zero-extends it to form a
 | |
| // 32-bit word, and writes it to a register. The offset register value can
 | |
| // optionally be shifted.
 | |
| bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         R[t] = ZeroExtend(MemU[address,1],32); 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if Rt == '1111' then SEE PLD;
 | |
|       if (t == 15)
 | |
|         return false; // PLD is not implemented yet
 | |
| 
 | |
|       // if Rn == '1111' then SEE LDRB (literal);
 | |
|       if (n == 15)
 | |
|         return EmulateLDRBLiteral(opcode, eEncodingT1);
 | |
| 
 | |
|       // if t == 13 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((t == 13) || BadReg(m))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // if P == '0' && W == '1' then SEE LDRBT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       uint32_t type = Bits32(opcode, 6, 5);
 | |
|       uint32_t imm5 = Bits32(opcode, 11, 7);
 | |
|       shift_n = DecodeImmShift(type, imm5, shift_t);
 | |
| 
 | |
|       // if t == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     uint32_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     uint32_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // R[t] = ZeroExtend(MemU[address,1],32);
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRH (immediate, Thumb) calculates an address from a base register value and
 | |
| // an immediate offset, loads a
 | |
| // halfword from memory, zero-extends it to form a 32-bit word, and writes it
 | |
| // to a register.  It can use offset, post-indexed, or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRHImmediate(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,2]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = ZeroExtend(data, 32); 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       imm32 = Bits32(opcode, 10, 6) << 1;
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // if Rn == '1111' then SEE LDRH (literal);
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT3:
 | |
|       // if Rn == '1111' then SEE LDRH (literal);
 | |
|       // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE
 | |
|       // "Unallocated memory hints";
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE LDRHT;
 | |
|       // if P == '0' && W == '0' then UNDEFINED;
 | |
|       if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
 | |
|       if (BadReg(t) || (wback && (n == t)))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint32_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = ZeroExtend(data, 32);
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRH (literal) calculates an address from the PC value and an immediate
 | |
| // offset, loads a halfword from memory,
 | |
| // zero-extends it to form a 32-bit word, and writes it to a register.
 | |
| bool EmulateInstructionARM::EmulateLDRHLiteral(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15); 
 | |
|         base = Align(PC,4); 
 | |
|         address = if add then (base + imm32) else (base - imm32); 
 | |
|         data = MemU[address,2]; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = ZeroExtend(data, 32); 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t imm32;
 | |
|     bool add;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       uint32_t imm4H = Bits32(opcode, 11, 8);
 | |
|       uint32_t imm4L = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = (imm4H << 4) | imm4L;
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // base = Align(PC,4);
 | |
|     uint64_t pc_value = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t base = AlignPC(pc_value);
 | |
|     addr_t address;
 | |
| 
 | |
|     // address = if add then (base + imm32) else (base - imm32);
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - base);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = ZeroExtend(data, 32);
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - base);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
| 
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRH (literal) calculates an address from a base register value and an offset
 | |
| // register value, loads a halfword
 | |
| // from memory, zero-extends it to form a 32-bit word, and writes it to a
 | |
| // register.  The offset register value can be shifted left by 0, 1, 2, or 3
 | |
| // bits.
 | |
| bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,2]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = ZeroExtend(data, 32); 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation
 | |
|       // in ThumbEE";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then SEE LDRH (literal);
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if t == 13 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((t == 13) || BadReg(m))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE LDRHT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       // if t == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     uint64_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusIndirectOffset(base_reg, offset_reg);
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = ZeroExtend(data, 32);
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusIndirectOffset(base_reg, offset_reg);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSB (immediate) calculates an address from a base register value and an
 | |
| // immediate offset, loads a byte from
 | |
| // memory, sign-extends it to form a 32-bit word, and writes it to a register.
 | |
| // It can use offset, post-indexed, or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRSBImmediate(const uint32_t opcode,
 | |
|                                                   const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         R[t] = SignExtend(MemU[address,1], 32); 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if Rt == '1111' then SEE PLI;
 | |
|       // if Rn == '1111' then SEE LDRSB (literal);
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI;
 | |
|       // if Rn == '1111' then SEE LDRSB (literal);
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE LDRSBT;
 | |
|       // if P == '0' && W == '0' then UNDEFINED;
 | |
|       if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
 | |
|       if (((t == 13) ||
 | |
|            ((t == 15) && (BitIsClear(opcode, 10) || BitIsSet(opcode, 9) ||
 | |
|                           BitIsSet(opcode, 8)))) ||
 | |
|           (wback && (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // if Rn == '1111' then SEE LDRSB (literal);
 | |
|       // if P == '0' && W == '1' then SEE LDRSBT;
 | |
|       // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       uint32_t imm4H = Bits32(opcode, 11, 8);
 | |
|       uint32_t imm4L = Bits32(opcode, 3, 0);
 | |
|       imm32 = (imm4H << 4) | imm4L;
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
 | |
| 
 | |
|       // if t == 15 || (wback && n == t) then UNPREDICTABLE;
 | |
|       if ((t == 15) || (wback && (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // R[t] = SignExtend(MemU[address,1], 32);
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t unsigned_data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                (uint64_t)signed_data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSB (literal) calculates an address from the PC value and an immediate
 | |
| // offset, loads a byte from memory,
 | |
| // sign-extends it to form a 32-bit word, and writes tit to a register.
 | |
| bool EmulateInstructionARM::EmulateLDRSBLiteral(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15); 
 | |
|         base = Align(PC,4); 
 | |
|         address = if add then (base + imm32) else (base - imm32); 
 | |
|         R[t] = SignExtend(MemU[address,1], 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t imm32;
 | |
|     bool add;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if Rt == '1111' then SEE PLI;
 | |
|       // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       uint32_t imm4H = Bits32(opcode, 11, 8);
 | |
|       uint32_t imm4L = Bits32(opcode, 3, 0);
 | |
|       imm32 = (imm4H << 4) | imm4L;
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // base = Align(PC,4);
 | |
|     uint64_t pc_value = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint64_t base = AlignPC(pc_value);
 | |
| 
 | |
|     // address = if add then (base + imm32) else (base - imm32);
 | |
|     addr_t address;
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     // R[t] = SignExtend(MemU[address,1], 32);
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - base);
 | |
| 
 | |
|     uint64_t unsigned_data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                (uint64_t)signed_data))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSB (register) calculates an address from a base register value and an
 | |
| // offset register value, loadsa byte from
 | |
| // memory, sign-extends it to form a 32-bit word, and writes it to a register.
 | |
| // The offset register value can be shifted left by 0, 1, 2, or 3 bits.
 | |
| bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         R[t] = SignExtend(MemU[address,1], 32); 
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rt == '1111' then SEE PLI;
 | |
|       // if Rn == '1111' then SEE LDRSB (literal);
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if t == 13 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((t == 13) || BadReg(m))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE LDRSBT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       // if t == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     uint64_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // R[t] = SignExtend(MemU[address,1], 32);
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusIndirectOffset(base_reg, offset_reg);
 | |
| 
 | |
|     uint64_t unsigned_data = MemURead(context, address, 1, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                (uint64_t)signed_data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSH (immediate) calculates an address from a base register value and an
 | |
| // immediate offset, loads a halfword from
 | |
| // memory, sign-extends it to form a 32-bit word, and writes it to a register.
 | |
| // It can use offset, post-indexed, or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRSHImmediate(const uint32_t opcode,
 | |
|                                                   const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,2]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = SignExtend(data, 32); 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if Rn == '1111' then SEE LDRSH (literal);
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then SEE LDRSH (literal);
 | |
|       // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE
 | |
|       // "Unallocated memory hints";
 | |
|       // if P == '1' && U == '1' && W == '0' then SEE LDRSHT;
 | |
|       // if P == '0' && W == '0' then UNDEFINED;
 | |
|       if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
 | |
|         return false;
 | |
| 
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 10);
 | |
|       add = BitIsSet(opcode, 9);
 | |
|       wback = BitIsSet(opcode, 8);
 | |
| 
 | |
|       // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
 | |
|       if (BadReg(t) || (wback && (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // if Rn == '1111' then SEE LDRSH (literal);
 | |
|       // if P == '0' && W == '1' then SEE LDRSHT;
 | |
|       // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       uint32_t imm4H = Bits32(opcode, 11, 8);
 | |
|       uint32_t imm4L = Bits32(opcode, 3, 0);
 | |
|       imm32 = (imm4H << 4) | imm4L;
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if t == 15 || (wback && n == t) then UNPREDICTABLE;
 | |
|       if ((t == 15) || (wback && (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint64_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = SignExtend(data, 32);
 | |
|       int64_t signed_data = llvm::SignExtend64<16>(data);
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  (uint64_t)signed_data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSH (literal) calculates an address from the PC value and an immediate
 | |
| // offset, loads a halfword from memory,
 | |
| // sign-extends it to from a 32-bit word, and writes it to a register.
 | |
| bool EmulateInstructionARM::EmulateLDRSHLiteral(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(15); 
 | |
|         base = Align(PC,4); 
 | |
|         address = if add then (base + imm32) else (base - imm32); 
 | |
|         data = MemU[address,2]; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = SignExtend(data, 32);
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t imm32;
 | |
|     bool add;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 13 then UNPREDICTABLE;
 | |
|       if (t == 13)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1: {
 | |
|       // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       uint32_t imm4H = Bits32(opcode, 11, 8);
 | |
|       uint32_t imm4L = Bits32(opcode, 3, 0);
 | |
|       imm32 = (imm4H << 4) | imm4L;
 | |
|       add = BitIsSet(opcode, 23);
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
|     }
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // base = Align(PC,4);
 | |
|     uint64_t pc_value = ReadCoreReg(PC_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint64_t base = AlignPC(pc_value);
 | |
| 
 | |
|     addr_t address;
 | |
|     // address = if add then (base + imm32) else (base - imm32);
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, imm32);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = SignExtend(data, 32);
 | |
|       int64_t signed_data = llvm::SignExtend64<16>(data);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  (uint64_t)signed_data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // LDRSH (register) calculates an address from a base register value and an
 | |
| // offset register value, loads a halfword
 | |
| // from memory, sign-extends it to form a 32-bit word, and writes it to a
 | |
| // register.  The offset register value can be shifted left by 0, 1, 2, or 3
 | |
| // bits.
 | |
| bool EmulateInstructionARM::EmulateLDRSHRegister(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n); 
 | |
|         offset = Shift(R[m], shift_t, shift_n, APSR.C); 
 | |
|         offset_addr = if add then (R[n] + offset) else (R[n] - offset); 
 | |
|         address = if index then offset_addr else R[n]; 
 | |
|         data = MemU[address,2]; 
 | |
|         if wback then R[n] = offset_addr; 
 | |
|         if UnalignedSupport() || address<0> = '0' then
 | |
|             R[t] = SignExtend(data, 32); 
 | |
|         else // Can only apply before ARMv7
 | |
|             R[t] = bits(32) UNKNOWN;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation
 | |
|       // in ThumbEE";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // if Rn == '1111' then SEE LDRSH (literal);
 | |
|       // if Rt == '1111' then SEE "Unallocated memory hints";
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = TRUE; add = TRUE; wback = FALSE;
 | |
|       index = true;
 | |
|       add = true;
 | |
|       wback = false;
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // if t == 13 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((t == 13) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE LDRSHT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1');     add = (U == '1');       wback = (P == '0') ||
 | |
|       // (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       // if t == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint64_t Rn =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     addr_t address;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
 | |
|     if (add)
 | |
|       offset_addr = Rn + offset;
 | |
|     else
 | |
|       offset_addr = Rn - offset;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // data = MemU[address,2];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusIndirectOffset(base_reg, offset_reg);
 | |
| 
 | |
|     uint64_t data = MemURead(context, address, 2, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if UnalignedSupport() || address<0> = '0' then
 | |
|     if (UnalignedSupport() || BitIsClear(address, 0)) {
 | |
|       // R[t] = SignExtend(data, 32);
 | |
|       context.type = eContextRegisterLoad;
 | |
|       context.SetRegisterPlusIndirectOffset(base_reg, offset_reg);
 | |
| 
 | |
|       int64_t signed_data = llvm::SignExtend64<16>(data);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
 | |
|                                  (uint64_t)signed_data))
 | |
|         return false;
 | |
|     } else // Can only apply before ARMv7
 | |
|     {
 | |
|       // R[t] = bits(32) UNKNOWN;
 | |
|       WriteBits32Unknown(t);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and
 | |
| // writes the result to the destination
 | |
| // register.  You can specifiy a rotation by 0, 8, 16, or 24 bits before
 | |
| // extracting the 8-bit value.
 | |
| bool EmulateInstructionARM::EmulateSXTB(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations();
 | |
|         rotated = ROR(R[m], rotation); 
 | |
|         R[d] = SignExtend(rotated<7:0>, 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t m;
 | |
|     uint32_t rotation;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = 0;
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       m = Bits32(opcode, 5, 3);
 | |
|       rotation = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 5, 4) << 3;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 11, 10) << 3;
 | |
| 
 | |
|       // if d == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // rotated = ROR(R[m], rotation);
 | |
|     uint64_t rotated = ROR(Rm, rotation, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // R[d] = SignExtend(rotated<7:0>, 32);
 | |
|     int64_t data = llvm::SignExtend64<8>(rotated);
 | |
| 
 | |
|     RegisterInfo source_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegister(source_reg);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                (uint64_t)data))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and
 | |
| // writes the result to the destination
 | |
| // register.  You can specify a rotation by 0, 8, 16, or 24 bits before
 | |
| // extracting the 16-bit value.
 | |
| bool EmulateInstructionARM::EmulateSXTH(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         rotated = ROR(R[m], rotation); 
 | |
|         R[d] = SignExtend(rotated<15:0>, 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t m;
 | |
|     uint32_t rotation;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = 0;
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       m = Bits32(opcode, 5, 3);
 | |
|       rotation = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 5, 4) << 3;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 11, 10) << 3;
 | |
| 
 | |
|       // if d == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // rotated = ROR(R[m], rotation);
 | |
|     uint64_t rotated = ROR(Rm, rotation, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // R[d] = SignExtend(rotated<15:0>, 32);
 | |
|     RegisterInfo source_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegister(source_reg);
 | |
| 
 | |
|     int64_t data = llvm::SignExtend64<16>(rotated);
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                (uint64_t)data))
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // UXTB extracts an 8-bit value from a register, zero-extends it to 32 bits, and
 | |
| // writes the result to the destination
 | |
| // register.  You can specify a rotation by 0, 8, 16, or 24 bits before
 | |
| // extracting the 8-bit value.
 | |
| bool EmulateInstructionARM::EmulateUXTB(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         rotated = ROR(R[m], rotation); 
 | |
|         R[d] = ZeroExtend(rotated<7:0>, 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t m;
 | |
|     uint32_t rotation;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = 0;
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       m = Bits32(opcode, 5, 3);
 | |
|       rotation = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 5, 4) << 3;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 11, 10) << 3;
 | |
| 
 | |
|       // if d == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // rotated = ROR(R[m], rotation);
 | |
|     uint64_t rotated = ROR(Rm, rotation, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // R[d] = ZeroExtend(rotated<7:0>, 32);
 | |
|     RegisterInfo source_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegister(source_reg);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                Bits32(rotated, 7, 0)))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and
 | |
| // writes the result to the destination
 | |
| // register.  You can specify a rotation by 0, 8, 16, or 24 bits before
 | |
| // extracting the 16-bit value.
 | |
| bool EmulateInstructionARM::EmulateUXTH(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         rotated = ROR(R[m], rotation); 
 | |
|         R[d] = ZeroExtend(rotated<15:0>, 32);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t m;
 | |
|     uint32_t rotation;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = 0;
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       m = Bits32(opcode, 5, 3);
 | |
|       rotation = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 5, 4) << 3;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       rotation = Bits32(opcode, 11, 10) << 3;
 | |
| 
 | |
|       // if d == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint64_t Rm =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // rotated = ROR(R[m], rotation);
 | |
|     uint64_t rotated = ROR(Rm, rotation, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // R[d] = ZeroExtend(rotated<15:0>, 32);
 | |
|     RegisterInfo source_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegister(source_reg);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                Bits32(rotated, 15, 0)))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // RFE (Return From Exception) loads the PC and the CPSR from the word at the
 | |
| // specified address and the following
 | |
| // word respectively.
 | |
| bool EmulateInstructionARM::EmulateRFE(const uint32_t opcode,
 | |
|                                        const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then 
 | |
|         EncodingSpecificOperations(); 
 | |
|         if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
 | |
|             UNPREDICTABLE; 
 | |
|         else
 | |
|             address = if increment then R[n] else R[n]-8; 
 | |
|             if wordhigher then address = address+4; 
 | |
|             CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); 
 | |
|             BranchWritePC(MemA[address,4]);
 | |
|             if wback then R[n] = if increment then R[n]+8 else R[n]-8;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     bool wback;
 | |
|     bool increment;
 | |
|     bool wordhigher;
 | |
| 
 | |
|     // EncodingSpecificOperations();
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher =
 | |
|       // FALSE;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       increment = false;
 | |
|       wordhigher = false;
 | |
| 
 | |
|       // if n == 15 then UNPREDICTABLE;
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|       // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       increment = true;
 | |
|       wordhigher = false;
 | |
| 
 | |
|       // if n == 15 then UNPREDICTABLE;
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|       // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       increment = BitIsSet(opcode, 23);
 | |
|       wordhigher = (Bit32(opcode, 24) == Bit32(opcode, 23));
 | |
| 
 | |
|       // if n == 15 then UNPREDICTABLE;
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE
 | |
|     // then
 | |
|     if (!CurrentModeIsPrivileged())
 | |
|       // UNPREDICTABLE;
 | |
|       return false;
 | |
|     else {
 | |
|       uint64_t Rn =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       addr_t address;
 | |
|       // address = if increment then R[n] else R[n]-8;
 | |
|       if (increment)
 | |
|         address = Rn;
 | |
|       else
 | |
|         address = Rn - 8;
 | |
| 
 | |
|       // if wordhigher then address = address+4;
 | |
|       if (wordhigher)
 | |
|         address = address + 4;
 | |
| 
 | |
|       // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE);
 | |
|       RegisterInfo base_reg;
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|       EmulateInstruction::Context context;
 | |
|       context.type = eContextReturnFromException;
 | |
|       context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|       uint64_t data = MemARead(context, address + 4, 4, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       CPSRWriteByInstr(data, 15, true);
 | |
| 
 | |
|       // BranchWritePC(MemA[address,4]);
 | |
|       uint64_t data2 = MemARead(context, address, 4, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       BranchWritePC(context, data2);
 | |
| 
 | |
|       // if wback then R[n] = if increment then R[n]+8 else R[n]-8;
 | |
|       if (wback) {
 | |
|         context.type = eContextAdjustBaseRegister;
 | |
|         if (increment) {
 | |
|           context.SetOffset(8);
 | |
|           if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                      Rn + 8))
 | |
|             return false;
 | |
|         } else {
 | |
|           context.SetOffset(-8);
 | |
|           if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                      Rn - 8))
 | |
|             return false;
 | |
|         }
 | |
|       } // if wback
 | |
|     }
 | |
|   } // if ConditionPassed()
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a
 | |
| // register value and an immediate value, and writes the result to the
 | |
| // destination register.  It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] EOR imm32;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be ORed to the value obtained from Rn
 | |
|     bool setflags;
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       // if Rd == '1111' && S == '1' then SEE TEQ (immediate);
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateTEQImm(opcode, eEncodingT1);
 | |
|       if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 ^ imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a
 | |
| // register value and an optionally-shifted register value, and writes the
 | |
| // result to the destination register. It can optionally update the condition
 | |
| // flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] EOR shifted;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       // if Rd == '1111' && S == '1' then SEE TEQ (register);
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateTEQReg(opcode, eEncodingT1);
 | |
|       if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 ^ shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value
 | |
| // and an immediate value, and writes the result to the destination register.
 | |
| // It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] OR imm32;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be ORed to the value obtained from Rn
 | |
|     bool setflags;
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       // if Rn == '1111' then SEE MOV (immediate);
 | |
|       if (Rn == 15)
 | |
|         return EmulateMOVRdImm(opcode, eEncodingT2);
 | |
|       if (BadReg(Rd) || Rn == 13)
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 | imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Bitwise OR (register) performs a bitwise (inclusive) OR of a register value
 | |
| // and an optionally-shifted register value, and writes the result to the
 | |
| // destination register.  It can optionally update the condition flags based on
 | |
| // the result.
 | |
| bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] OR shifted;
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd, Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     bool setflags;
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rd = Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       setflags = !InITBlock();
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rd = Bits32(opcode, 11, 8);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       // if Rn == '1111' then SEE MOV (register);
 | |
|       if (Rn == 15)
 | |
|         return EmulateMOVRdRm(opcode, eEncodingT3);
 | |
|       if (BadReg(Rd) || Rn == 13 || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 | shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Reverse Subtract (immediate) subtracts a register value from an immediate
 | |
| // value, and writes the result to the destination register. It can optionally
 | |
| // update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1');
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   bool setflags;
 | |
|   uint32_t
 | |
|       imm32; // the immediate value to be added to the value obtained from Rn
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rd = Bits32(opcode, 2, 0);
 | |
|     Rn = Bits32(opcode, 5, 3);
 | |
|     setflags = !InITBlock();
 | |
|     imm32 = 0;
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|     if (BadReg(Rd) || BadReg(Rn))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(~reg_val, imm32, 1);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Reverse Subtract (register) subtracts a register value from an optionally-
 | |
| // shifted register value, and writes the result to the destination register.
 | |
| // It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1');
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   uint32_t Rm; // the second operand
 | |
|   bool setflags;
 | |
|   ARM_ShifterType shift_t;
 | |
|   uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|     // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
 | |
|     if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from register Rn.
 | |
|   uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   // Read the register value from register Rm.
 | |
|   uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
|   AddWithCarryResult res = AddWithCarry(~val1, shifted, 1);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Reverse Subtract with Carry (immediate) subtracts a register value and the
 | |
| // value of NOT (Carry flag) from an immediate value, and writes the result to
 | |
| // the destination register. It can optionally update the condition flags based
 | |
| // on the result.
 | |
| bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C);
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   bool setflags;
 | |
|   uint32_t
 | |
|       imm32; // the immediate value to be added to the value obtained from Rn
 | |
|   switch (encoding) {
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(~reg_val, imm32, APSR_C);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Reverse Subtract with Carry (register) subtracts a register value and the
 | |
| // value of NOT (Carry flag) from an optionally-shifted register value, and
 | |
| // writes the result to the destination register. It can optionally update the
 | |
| // condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C);
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   uint32_t Rm; // the second operand
 | |
|   bool setflags;
 | |
|   ARM_ShifterType shift_t;
 | |
|   uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|   switch (encoding) {
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from register Rn.
 | |
|   uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   // Read the register value from register Rm.
 | |
|   uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
|   AddWithCarryResult res = AddWithCarry(~val1, shifted, APSR_C);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Subtract with Carry (immediate) subtracts an immediate value and the value
 | |
| // of
 | |
| // NOT (Carry flag) from a register value, and writes the result to the
 | |
| // destination register.
 | |
| // It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   bool setflags;
 | |
|   uint32_t
 | |
|       imm32; // the immediate value to be added to the value obtained from Rn
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
|     if (BadReg(Rd) || BadReg(Rn))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, APSR_C);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // Subtract with Carry (register) subtracts an optionally-shifted register
 | |
| // value and the value of
 | |
| // NOT (Carry flag) from a register value, and writes the result to the
 | |
| // destination register.
 | |
| // It can optionally update the condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateSBCReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C);
 | |
|         if d == 15 then         // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   uint32_t Rm; // the second operand
 | |
|   bool setflags;
 | |
|   ARM_ShifterType shift_t;
 | |
|   uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rd = Rn = Bits32(opcode, 2, 0);
 | |
|     Rm = Bits32(opcode, 5, 3);
 | |
|     setflags = !InITBlock();
 | |
|     shift_t = SRType_LSL;
 | |
|     shift_n = 0;
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|     if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingA1:
 | |
|     Rd = Bits32(opcode, 15, 12);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     Rm = Bits32(opcode, 3, 0);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|     // instructions;
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from register Rn.
 | |
|   uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   // Read the register value from register Rm.
 | |
|   uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
|   AddWithCarryResult res = AddWithCarry(val1, ~shifted, APSR_C);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // This instruction subtracts an immediate value from a register value, and
 | |
| // writes the result to the destination register.  It can optionally update the
 | |
| // condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   uint32_t Rd; // the destination register
 | |
|   uint32_t Rn; // the first operand
 | |
|   bool setflags;
 | |
|   uint32_t imm32; // the immediate value to be subtracted from the value
 | |
|                   // obtained from Rn
 | |
|   switch (encoding) {
 | |
|   case eEncodingT1:
 | |
|     Rd = Bits32(opcode, 2, 0);
 | |
|     Rn = Bits32(opcode, 5, 3);
 | |
|     setflags = !InITBlock();
 | |
|     imm32 = Bits32(opcode, 8, 6); // imm32 = ZeroExtend(imm3, 32)
 | |
|     break;
 | |
|   case eEncodingT2:
 | |
|     Rd = Rn = Bits32(opcode, 10, 8);
 | |
|     setflags = !InITBlock();
 | |
|     imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
 | |
|     break;
 | |
|   case eEncodingT3:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
 | |
| 
 | |
|     // if Rd == '1111' && S == '1' then SEE CMP (immediate);
 | |
|     if (Rd == 15 && setflags)
 | |
|       return EmulateCMPImm(opcode, eEncodingT2);
 | |
| 
 | |
|     // if Rn == '1101' then SEE SUB (SP minus immediate);
 | |
|     if (Rn == 13)
 | |
|       return EmulateSUBSPImm(opcode, eEncodingT2);
 | |
| 
 | |
|     // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE;
 | |
|     if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15)
 | |
|       return false;
 | |
|     break;
 | |
|   case eEncodingT4:
 | |
|     Rd = Bits32(opcode, 11, 8);
 | |
|     Rn = Bits32(opcode, 19, 16);
 | |
|     setflags = BitIsSet(opcode, 20);
 | |
|     imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
 | |
| 
 | |
|     // if Rn == '1111' then SEE ADR;
 | |
|     if (Rn == 15)
 | |
|       return EmulateADR(opcode, eEncodingT2);
 | |
| 
 | |
|     // if Rn == '1101' then SEE SUB (SP minus immediate);
 | |
|     if (Rn == 13)
 | |
|       return EmulateSUBSPImm(opcode, eEncodingT3);
 | |
| 
 | |
|     if (BadReg(Rd))
 | |
|       return false;
 | |
|     break;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
|   // Read the register value from the operand register Rn.
 | |
|   uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|   if (!success)
 | |
|     return false;
 | |
| 
 | |
|   AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
 | |
| 
 | |
|   EmulateInstruction::Context context;
 | |
|   context.type = EmulateInstruction::eContextImmediate;
 | |
|   context.SetNoArgs();
 | |
| 
 | |
|   return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow);
 | |
| }
 | |
| 
 | |
| // This instruction subtracts an immediate value from a register value, and
 | |
| // writes the result to the destination register.  It can optionally update the
 | |
| // condition flags based on the result.
 | |
| bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode,
 | |
|                                              const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
 | |
|         if d == 15 then
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rd; // the destination register
 | |
|     uint32_t Rn; // the first operand
 | |
|     bool setflags;
 | |
|     uint32_t imm32; // the immediate value to be subtracted from the value
 | |
|                     // obtained from Rn
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       Rd = Bits32(opcode, 15, 12);
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
 | |
| 
 | |
|       // if Rn == '1111' && S == '0' then SEE ADR;
 | |
|       if (Rn == 15 && !setflags)
 | |
|         return EmulateADR(opcode, eEncodingA2);
 | |
| 
 | |
|       // if Rn == '1101' then SEE SUB (SP minus immediate);
 | |
|       if (Rn == 13)
 | |
|         return EmulateSUBSPImm(opcode, eEncodingA1);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (Rd == 15 && setflags)
 | |
|         return EmulateSUBSPcLrEtc(opcode, encoding);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // Read the register value from the operand register Rn.
 | |
|     uint32_t reg_val = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (Rd == 13)
 | |
|       context.type = EmulateInstruction::eContextAdjustStackPointer;
 | |
|     else
 | |
|       context.type = EmulateInstruction::eContextRegisterPlusOffset;
 | |
| 
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, Rn, dwarf_reg);
 | |
|     int64_t imm32_signed = imm32;
 | |
|     context.SetRegisterPlusOffset(dwarf_reg, -imm32_signed);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Test Equivalence (immediate) performs a bitwise exclusive OR operation on a
 | |
| // register value and an immediate value.  It updates the condition flags based
 | |
| // on the result, and discards the result.
 | |
| bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] EOR imm32;
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be ANDed to the value obtained from Rn
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       if (BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 ^ imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteFlags(context, result, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Test Equivalence (register) performs a bitwise exclusive OR operation on a
 | |
| // register value and an optionally-shifted register value.  It updates the
 | |
| // condition flags based on the result, and discards the result.
 | |
| bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] EOR shifted;
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       if (BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 ^ shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteFlags(context, result, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Test (immediate) performs a bitwise AND operation on a register value and an
 | |
| // immediate value. It updates the condition flags based on the result, and
 | |
| // discards the result.
 | |
| bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         result = R[n] AND imm32;
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rn;
 | |
|     uint32_t
 | |
|         imm32; // the immediate value to be ANDed to the value obtained from Rn
 | |
|     uint32_t carry; // the carry bit after ARM/Thumb Expand operation
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 = ThumbExpandImm_C(
 | |
|           opcode, APSR_C,
 | |
|           carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
 | |
|       if (BadReg(Rn))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       imm32 =
 | |
|           ARMExpandImm_C(opcode, APSR_C,
 | |
|                          carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t result = val1 & imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteFlags(context, result, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Test (register) performs a bitwise AND operation on a register value and an
 | |
| // optionally-shifted register value. It updates the condition flags based on
 | |
| // the result, and discards the result.
 | |
| bool EmulateInstructionARM::EmulateTSTReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     // ARM pseudo code...
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
 | |
|         result = R[n] AND shifted;
 | |
|         APSR.N = result<31>;
 | |
|         APSR.Z = IsZeroBit(result);
 | |
|         APSR.C = carry;
 | |
|         // APSR.V unchanged
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t Rn, Rm;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n; // the shift applied to the value read from Rm
 | |
|     uint32_t carry;
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       Rn = Bits32(opcode, 2, 0);
 | |
|       Rm = Bits32(opcode, 5, 3);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
|       break;
 | |
|     case eEncodingT2:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
|       if (BadReg(Rn) || BadReg(Rm))
 | |
|         return false;
 | |
|       break;
 | |
|     case eEncodingA1:
 | |
|       Rn = Bits32(opcode, 19, 16);
 | |
|       Rm = Bits32(opcode, 3, 0);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|       break;
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Read the first operand.
 | |
|     uint32_t val1 = ReadCoreReg(Rn, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // Read the second operand.
 | |
|     uint32_t val2 = ReadCoreReg(Rm, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     uint32_t result = val1 & shifted;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = EmulateInstruction::eContextImmediate;
 | |
|     context.SetNoArgs();
 | |
| 
 | |
|     if (!WriteFlags(context, result, carry))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.216 SUB (SP minus register)
 | |
| bool EmulateInstructionARM::EmulateSUBSPReg(const uint32_t opcode,
 | |
|                                             const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1');
 | |
|         if d == 15 then // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t m;
 | |
|     bool setflags;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1');
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
| 
 | |
|       // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3)))
 | |
|         return false;
 | |
| 
 | |
|       // if d == 15 || BadReg(m) then UNPREDICTABLE;
 | |
|       if ((d == 15) || BadReg(m))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if (d == 15 && setflags)
 | |
|         EmulateSUBSPcLrEtc(opcode, encoding);
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1');
 | |
|     uint32_t sp_val = ReadCoreReg(SP_REG, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(sp_val, ~shifted, 1);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     RegisterInfo sp_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg);
 | |
|     RegisterInfo dwarf_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, dwarf_reg);
 | |
|     context.SetRegisterRegisterOperands(sp_reg, dwarf_reg);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.7 ADD (register-shifted register)
 | |
| bool EmulateInstructionARM::EmulateADDRegShift(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shift_n = UInt(R[s]<7:0>);
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
 | |
|         R[d] = result;
 | |
|         if setflags then
 | |
|             APSR.N = result<31>;
 | |
|             APSR.Z = IsZeroBit(result);
 | |
|             APSR.C = carry;
 | |
|             APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     uint32_t s;
 | |
|     bool setflags;
 | |
|     ARM_ShifterType shift_t;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs);
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       s = Bits32(opcode, 11, 8);
 | |
| 
 | |
|       // setflags = (S == '1'); shift_t = DecodeRegShift(type);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
|       shift_t = DecodeRegShift(Bits32(opcode, 6, 5));
 | |
| 
 | |
|       // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (n == 15) || (m == 15) || (s == 15))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // shift_n = UInt(R[s]<7:0>);
 | |
|     uint32_t Rs = ReadCoreReg(s, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shift_n = Bits32(Rs, 7, 0);
 | |
| 
 | |
|     // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(Rn, shifted, 0);
 | |
| 
 | |
|     // R[d] = result;
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     RegisterInfo reg_n;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n);
 | |
|     RegisterInfo reg_m;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, reg_m);
 | |
| 
 | |
|     context.SetRegisterRegisterOperands(reg_n, reg_m);
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                res.result))
 | |
|       return false;
 | |
| 
 | |
|     // if setflags then
 | |
|     // APSR.N = result<31>;
 | |
|     // APSR.Z = IsZeroBit(result);
 | |
|     // APSR.C = carry;
 | |
|     // APSR.V = overflow;
 | |
|     if (setflags)
 | |
|       return WriteFlags(context, res.result, res.carry_out, res.overflow);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.213 SUB (register)
 | |
| bool EmulateInstructionARM::EmulateSUBReg(const uint32_t opcode,
 | |
|                                           const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|         (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
 | |
|         if d == 15 then // Can only occur for ARM encoding
 | |
|             ALUWritePC(result); // setflags is always FALSE here
 | |
|         else
 | |
|             R[d] = result;
 | |
|             if setflags then
 | |
|                 APSR.N = result<31>;
 | |
|                 APSR.Z = IsZeroBit(result);
 | |
|                 APSR.C = carry;
 | |
|                 APSR.V = overflow;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool setflags;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock();
 | |
|       d = Bits32(opcode, 2, 0);
 | |
|       n = Bits32(opcode, 5, 3);
 | |
|       m = Bits32(opcode, 8, 6);
 | |
|       setflags = !InITBlock();
 | |
| 
 | |
|       // (shift_t, shift_n) = (SRType_LSL, 0);
 | |
|       shift_t = SRType_LSL;
 | |
|       shift_n = 0;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1");
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // if Rd == "1111" && S == "1" then SEE CMP (register);
 | |
|       if (d == 15 && setflags == 1)
 | |
|         return EmulateCMPImm(opcode, eEncodingT3);
 | |
| 
 | |
|       // if Rn == "1101" then SEE SUB (SP minus register);
 | |
|       if (n == 13)
 | |
|         return EmulateSUBSPReg(opcode, eEncodingT1);
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
 | |
|       shift_n = DecodeImmShiftThumb(opcode, shift_t);
 | |
| 
 | |
|       // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((d == 13) || ((d == 15) && BitIsClear(opcode, 20)) || (n == 15) ||
 | |
|           BadReg(m))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if Rn == '1101' then SEE SUB (SP minus register);
 | |
|       // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1');
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       setflags = BitIsSet(opcode, 20);
 | |
| 
 | |
|       // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related
 | |
|       // instructions;
 | |
|       if ((d == 15) && setflags)
 | |
|         EmulateSUBSPcLrEtc(opcode, encoding);
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult res = AddWithCarry(Rn, ~shifted, 1);
 | |
| 
 | |
|     // if d == 15 then // Can only occur for ARM encoding ALUWritePC(result);
 | |
|     // // setflags is always FALSE here else
 | |
|     // R[d] = result;
 | |
|     // if setflags then
 | |
|     // APSR.N = result<31>;
 | |
|     // APSR.Z = IsZeroBit(result);
 | |
|     // APSR.C = carry;
 | |
|     // APSR.V = overflow;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextArithmetic;
 | |
|     RegisterInfo reg_n;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n);
 | |
|     RegisterInfo reg_m;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, reg_m);
 | |
|     context.SetRegisterRegisterOperands(reg_n, reg_m);
 | |
| 
 | |
|     if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags,
 | |
|                                    res.carry_out, res.overflow))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.202 STREX
 | |
| // Store Register Exclusive calculates an address from a base register value
 | |
| // and an immediate offset, and stores a word from a register to memory if the
 | |
| // executing processor has exclusive access to the memory addressed.
 | |
| bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode,
 | |
|                                          const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|         address = R[n] + imm32;
 | |
|         if ExclusiveMonitorsPass(address,4) then
 | |
|             MemA[address,4] = R[t];
 | |
|             R[d] = 0;
 | |
|         else
 | |
|             R[d] = 1;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t d;
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 =
 | |
|       // ZeroExtend(imm8:'00',
 | |
|       // 32);
 | |
|       d = Bits32(opcode, 11, 8);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE;
 | |
|       if (BadReg(d) || BadReg(t) || (n == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if d == n || d == t then UNPREDICTABLE;
 | |
|       if ((d == n) || (d == t))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero
 | |
|       // offset
 | |
|       d = Bits32(opcode, 15, 12);
 | |
|       t = Bits32(opcode, 3, 0);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = 0;
 | |
| 
 | |
|       // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE;
 | |
|       if ((d == 15) || (t == 15) || (n == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if d == n || d == t then UNPREDICTABLE;
 | |
|       if ((d == n) || (d == t))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // address = R[n] + imm32;
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t address = Rn + imm32;
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, imm32);
 | |
| 
 | |
|     // if ExclusiveMonitorsPass(address,4) then if (ExclusiveMonitorsPass
 | |
|     // (address, addr_byte_size)) -- For now, for the sake of emulation, we
 | |
|     // will say this
 | |
|     //                                                         always return
 | |
|     //                                                         true.
 | |
|     if (true) {
 | |
|       // MemA[address,4] = R[t];
 | |
|       uint32_t Rt =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address, Rt, addr_byte_size))
 | |
|         return false;
 | |
| 
 | |
|       // R[d] = 0;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, 0))
 | |
|         return false;
 | |
|     }
 | |
| #if 0  // unreachable because if true
 | |
|         else
 | |
|         {
 | |
|             // R[d] = 1;
 | |
|             if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1))
 | |
|                 return false;
 | |
|         }
 | |
| #endif // unreachable because if true
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.197 STRB (immediate, ARM)
 | |
| bool EmulateInstructionARM::EmulateSTRBImmARM(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         MemU[address,1] = R[t]<7:0>;
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE STRBT;
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if t == 15 then UNPREDICTABLE;
 | |
|       if (t == 15)
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // MemU[address,1] = R[t]<7:0>;
 | |
|     uint32_t Rt = ReadCoreReg(t, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     if (!MemUWrite(context, address, Bits32(Rt, 7, 0), 1))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.194 STR (immediate, ARM)
 | |
| bool EmulateInstructionARM::EmulateSTRImmARM(const uint32_t opcode,
 | |
|                                              const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && W == '1' then SEE STRT;
 | |
|       // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm12 ==
 | |
|       // '000000000100' then SEE PUSH;
 | |
|       // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 11, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if wback && (n == 15 || n == t) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t)))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     // MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
 | |
|     uint32_t Rt = ReadCoreReg(t, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (t == 15) {
 | |
|       uint32_t pc_value = ReadCoreReg(PC_REG, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemUWrite(context, address, pc_value, addr_byte_size))
 | |
|         return false;
 | |
|     } else {
 | |
|       if (!MemUWrite(context, address, Rt, addr_byte_size))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetImmediate(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.66 LDRD (immediate)
 | |
| // Load Register Dual (immediate) calculates an address from a base register
 | |
| // value and an immediate offset, loads two words from memory, and writes them
 | |
| // to two registers.  It can use offset, post-indexed, or pre-indexed
 | |
| // addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRDImmediate(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         R[t] = MemA[address,4];
 | |
|         R[t2] = MemA[address+4,4];
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t t2;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if P == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // if Rn == '1111' then SEE LDRD (literal);
 | |
|       // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 =
 | |
|       // ZeroExtend(imm8:'00', 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       t2 = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if wback && (n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE;
 | |
|       if (BadReg(t) || BadReg(t2) || (t == t2))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if Rn == '1111' then SEE LDRD (literal);
 | |
|       // if Rt<0> == '1' then UNPREDICTABLE;
 | |
|       // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L,
 | |
|       // 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       if (BitIsSet(t, 0))
 | |
|         return false;
 | |
|       t2 = t + 1;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = (Bits32(opcode, 11, 8) << 4) | Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if P == '0' && W == '1' then UNPREDICTABLE;
 | |
|       if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if t2 == 15 then UNPREDICTABLE;
 | |
|       if (t2 == 15)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // R[t] = MemA[address,4];
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (n == 13)
 | |
|       context.type = eContextPopRegisterOffStack;
 | |
|     else
 | |
|       context.type = eContextRegisterLoad;
 | |
|     context.SetAddress(address);
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t data = MemARead(context, address, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data))
 | |
|       return false;
 | |
| 
 | |
|     // R[t2] = MemA[address+4,4];
 | |
|     context.SetAddress(address + 4);
 | |
|     data = MemARead(context, address + 4, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t2,
 | |
|                                data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.68 LDRD (register)
 | |
| // Load Register Dual (register) calculates an address from a base register
 | |
| // value and a register offset, loads two words from memory, and writes them to
 | |
| // two registers.  It can use offset, post-indexed or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateLDRDRegister(const uint32_t opcode,
 | |
|                                                 const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         R[t] = MemA[address,4];
 | |
|         R[t2] = MemA[address+4,4];
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t t2;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // if Rt<0> == '1' then UNPREDICTABLE;
 | |
|       // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       if (BitIsSet(t, 0))
 | |
|         return false;
 | |
|       t2 = t + 1;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if P == '0' && W == '1' then UNPREDICTABLE;
 | |
|       if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE;
 | |
|       if ((t2 == 15) || (m == 15) || (m == t) || (m == t2))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
 | |
|       if ((ArchVersion() < 6) && wback && (m == n))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + Rm;
 | |
|     else
 | |
|       offset_addr = Rn - Rm;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (n == 13)
 | |
|       context.type = eContextPopRegisterOffStack;
 | |
|     else
 | |
|       context.type = eContextRegisterLoad;
 | |
|     context.SetAddress(address);
 | |
| 
 | |
|     // R[t] = MemA[address,4];
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t data = MemARead(context, address, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data))
 | |
|       return false;
 | |
| 
 | |
|     // R[t2] = MemA[address+4,4];
 | |
| 
 | |
|     data = MemARead(context, address + 4, addr_byte_size, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t2,
 | |
|                                data))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.200 STRD (immediate)
 | |
| // Store Register Dual (immediate) calculates an address from a base register
 | |
| // value and an immediate offset, and stores two words from two registers to
 | |
| // memory.  It can use offset, post-indexed, or pre-indexed addressing.
 | |
| bool EmulateInstructionARM::EmulateSTRDImm(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); NullCheckIfThumbEE(n);
 | |
|         offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         MemA[address,4] = R[t];
 | |
|         MemA[address+4,4] = R[t2];
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t t2;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if P == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 =
 | |
|       // ZeroExtend(imm8:'00', 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       t2 = Bits32(opcode, 11, 8);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if wback && (n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE;
 | |
|       if ((n == 15) || BadReg(t) || BadReg(t2))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // if Rt<0> == '1' then UNPREDICTABLE;
 | |
|       // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L,
 | |
|       // 32);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       if (BitIsSet(t, 0))
 | |
|         return false;
 | |
| 
 | |
|       t2 = t + 1;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = (Bits32(opcode, 11, 8) << 4) | Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if P == '0' && W == '1' then UNPREDICTABLE;
 | |
|       if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if t2 == 15 then UNPREDICTABLE;
 | |
|       if (t2 == 15)
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + imm32;
 | |
|     else
 | |
|       offset_addr = Rn - imm32;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
| 
 | |
|     // MemA[address,4] = R[t];
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
| 
 | |
|     uint32_t data = ReadCoreReg(t, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (n == 13)
 | |
|       context.type = eContextPushRegisterOnStack;
 | |
|     else
 | |
|       context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     if (!MemAWrite(context, address, data, addr_byte_size))
 | |
|       return false;
 | |
| 
 | |
|     // MemA[address+4,4] = R[t2];
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                             (address + 4) - Rn);
 | |
| 
 | |
|     data = ReadCoreReg(t2, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (!MemAWrite(context, address + 4, data, addr_byte_size))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       if (n == 13)
 | |
|         context.type = eContextAdjustStackPointer;
 | |
|       else
 | |
|         context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.201 STRD (register)
 | |
| bool EmulateInstructionARM::EmulateSTRDReg(const uint32_t opcode,
 | |
|                                            const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
 | |
|         address = if index then offset_addr else R[n];
 | |
|         MemA[address,4] = R[t];
 | |
|         MemA[address+4,4] = R[t2];
 | |
|         if wback then R[n] = offset_addr;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t t;
 | |
|     uint32_t t2;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool index;
 | |
|     bool add;
 | |
|     bool wback;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingA1:
 | |
|       // if Rt<0> == '1' then UNPREDICTABLE;
 | |
|       // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
 | |
|       t = Bits32(opcode, 15, 12);
 | |
|       if (BitIsSet(t, 0))
 | |
|         return false;
 | |
| 
 | |
|       t2 = t + 1;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
 | |
|       index = BitIsSet(opcode, 24);
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
 | |
| 
 | |
|       // if P == '0' && W == '1' then UNPREDICTABLE;
 | |
|       if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // if t2 == 15 || m == 15 then UNPREDICTABLE;
 | |
|       if ((t2 == 15) || (m == 15))
 | |
|         return false;
 | |
| 
 | |
|       // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
 | |
|       if (wback && ((n == 15) || (n == t) || (n == t2)))
 | |
|         return false;
 | |
| 
 | |
|       // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
 | |
|       if ((ArchVersion() < 6) && wback && (m == n))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
|     RegisterInfo offset_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
 | |
|     RegisterInfo data_reg;
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint32_t Rm = ReadCoreReg(m, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
 | |
|     addr_t offset_addr;
 | |
|     if (add)
 | |
|       offset_addr = Rn + Rm;
 | |
|     else
 | |
|       offset_addr = Rn - Rm;
 | |
| 
 | |
|     // address = if index then offset_addr else R[n];
 | |
|     addr_t address;
 | |
|     if (index)
 | |
|       address = offset_addr;
 | |
|     else
 | |
|       address = Rn;
 | |
|     // MemA[address,4] = R[t];
 | |
|     uint32_t Rt = ReadCoreReg(t, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     if (t == 13)
 | |
|       context.type = eContextPushRegisterOnStack;
 | |
|     else
 | |
|       context.type = eContextRegisterStore;
 | |
| 
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg);
 | |
|     context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg,
 | |
|                                                     data_reg);
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
| 
 | |
|     if (!MemAWrite(context, address, Rt, addr_byte_size))
 | |
|       return false;
 | |
| 
 | |
|     // MemA[address+4,4] = R[t2];
 | |
|     uint32_t Rt2 = ReadCoreReg(t2, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
 | |
| 
 | |
|     context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg,
 | |
|                                                     data_reg);
 | |
| 
 | |
|     if (!MemAWrite(context, address + 4, Rt2, addr_byte_size))
 | |
|       return false;
 | |
| 
 | |
|     // if wback then R[n] = offset_addr;
 | |
|     if (wback) {
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetAddress(offset_addr);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  offset_addr))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.319 VLDM
 | |
| // Vector Load Multiple loads multiple extension registers from consecutive
 | |
| // memory locations using an address from an ARM core register.
 | |
| bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
 | |
|         address = if add then R[n] else R[n]-imm32;
 | |
|         if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
 | |
|         for r = 0 to regs-1
 | |
|             if single_regs then
 | |
|                 S[d+r] = MemA[address,4]; address = address+4;
 | |
|             else
 | |
|                 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
 | |
|                 // Combine the word-aligned words in the correct order for
 | |
|                 // current endianness.
 | |
|                 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool single_regs;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     uint32_t regs;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP;
 | |
|       // if P == '1' && W == '0' then SEE VLDR;
 | |
|       // if P == U && W == '1' then UNDEFINED;
 | |
|       if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with
 | |
|       // !), 101 (DB with !)
 | |
|       // single_regs = FALSE; add = (U == '1'); wback = (W == '1');
 | |
|       single_regs = false;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FLDMX'.
 | |
|       regs = Bits32(opcode, 7, 0) / 2;
 | |
| 
 | |
|       // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then
 | |
|       // UNPREDICTABLE;
 | |
|       if (n == 15 && (wback || CurrentInstrSet() != eModeARM))
 | |
|         return false;
 | |
| 
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP;
 | |
|       // if P == '1' && W == '0' then SEE VLDR;
 | |
|       // if P == U && W == '1' then UNDEFINED;
 | |
|       if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with
 | |
|       // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W
 | |
|       // == '1'); d =
 | |
|       // UInt(Vd:D); n = UInt(Rn);
 | |
|       single_regs = true;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
|       regs = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
 | |
|         return false;
 | |
| 
 | |
|       // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if ((regs == 0) || ((d + regs) > 32))
 | |
|         return false;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = if add then R[n] else R[n]-imm32;
 | |
|     addr_t address;
 | |
|     if (add)
 | |
|       address = Rn;
 | |
|     else
 | |
|       address = Rn - imm32;
 | |
| 
 | |
|     // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
 | |
|     EmulateInstruction::Context context;
 | |
| 
 | |
|     if (wback) {
 | |
|       uint32_t value;
 | |
|       if (add)
 | |
|         value = Rn + imm32;
 | |
|       else
 | |
|         value = Rn - imm32;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetImmediateSigned(value - Rn);
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  value))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
 | |
| 
 | |
|     context.type = eContextRegisterLoad;
 | |
| 
 | |
|     // for r = 0 to regs-1
 | |
|     for (uint32_t r = 0; r < regs; ++r) {
 | |
|       if (single_regs) {
 | |
|         // S[d+r] = MemA[address,4]; address = address+4;
 | |
|         context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
| 
 | |
|         uint32_t data = MemARead(context, address, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
 | |
|                                    start_reg + d + r, data))
 | |
|           return false;
 | |
| 
 | |
|         address = address + 4;
 | |
|       } else {
 | |
|         // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address =
 | |
|         // address+8;
 | |
|         context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|         uint32_t word1 =
 | |
|             MemARead(context, address, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         context.SetRegisterPlusOffset(base_reg, (address + 4) - Rn);
 | |
|         uint32_t word2 =
 | |
|             MemARead(context, address + 4, addr_byte_size, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         address = address + 8;
 | |
|         // // Combine the word-aligned words in the correct order for current
 | |
|         // endianness.
 | |
|         // D[d+r] = if BigEndian() then word1:word2 else word2:word1;
 | |
|         uint64_t data;
 | |
|         if (GetByteOrder() == eByteOrderBig) {
 | |
|           data = word1;
 | |
|           data = (data << 32) | word2;
 | |
|         } else {
 | |
|           data = word2;
 | |
|           data = (data << 32) | word1;
 | |
|         }
 | |
| 
 | |
|         if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
 | |
|                                    start_reg + d + r, data))
 | |
|           return false;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.399 VSTM
 | |
| // Vector Store Multiple stores multiple extension registers to consecutive
 | |
| // memory locations using an address from an
 | |
| // ARM core register.
 | |
| bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode,
 | |
|                                         const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
 | |
|         address = if add then R[n] else R[n]-imm32;
 | |
|         if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
 | |
|         for r = 0 to regs-1
 | |
|             if single_regs then
 | |
|                 MemA[address,4] = S[d+r]; address = address+4;
 | |
|             else
 | |
|                 // Store as two word-aligned words in the correct order for
 | |
|                 // current endianness.
 | |
|                 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
 | |
|                 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
 | |
|                 address = address+8;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool single_regs;
 | |
|     bool add;
 | |
|     bool wback;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t imm32;
 | |
|     uint32_t regs;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH;
 | |
|       // if P == '1' && W == '0' then SEE VSTR;
 | |
|       // if P == U && W == '1' then UNDEFINED;
 | |
|       if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with
 | |
|       // !), 101 (DB with !)
 | |
|       // single_regs = FALSE; add = (U == '1'); wback = (W == '1');
 | |
|       single_regs = false;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FSTMX'.
 | |
|       regs = Bits32(opcode, 7, 0) / 2;
 | |
| 
 | |
|       // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
 | |
|         return false;
 | |
| 
 | |
|       // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings';
 | |
|       // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH;
 | |
|       // if P == '1' && W == '0' then SEE VSTR;
 | |
|       // if P == U && W == '1' then UNDEFINED;
 | |
|       if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
 | |
|         return false;
 | |
| 
 | |
|       // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with
 | |
|       // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W
 | |
|       // == '1'); d =
 | |
|       // UInt(Vd:D); n = UInt(Rn);
 | |
|       single_regs = true;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       wback = BitIsSet(opcode, 21);
 | |
|       d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
|       regs = Bits32(opcode, 7, 0);
 | |
| 
 | |
|       // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then
 | |
|       // UNPREDICTABLE;
 | |
|       if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
 | |
|         return false;
 | |
| 
 | |
|       // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
 | |
|       if ((regs == 0) || ((d + regs) > 32))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = if add then R[n] else R[n]-imm32;
 | |
|     addr_t address;
 | |
|     if (add)
 | |
|       address = Rn;
 | |
|     else
 | |
|       address = Rn - imm32;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
 | |
|     if (wback) {
 | |
|       uint32_t value;
 | |
|       if (add)
 | |
|         value = Rn + imm32;
 | |
|       else
 | |
|         value = Rn - imm32;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, value - Rn);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  value))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
 | |
| 
 | |
|     context.type = eContextRegisterStore;
 | |
|     // for r = 0 to regs-1
 | |
|     for (uint32_t r = 0; r < regs; ++r) {
 | |
| 
 | |
|       if (single_regs) {
 | |
|         // MemA[address,4] = S[d+r]; address = address+4;
 | |
|         uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF,
 | |
|                                              start_reg + d + r, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         RegisterInfo data_reg;
 | |
|         GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r, data_reg);
 | |
|         context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                 address - Rn);
 | |
|         if (!MemAWrite(context, address, data, addr_byte_size))
 | |
|           return false;
 | |
| 
 | |
|         address = address + 4;
 | |
|       } else {
 | |
|         // // Store as two word-aligned words in the correct order for current
 | |
|         // endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else
 | |
|         // D[d+r]<31:0>;
 | |
|         // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else
 | |
|         // D[d+r]<63:32>;
 | |
|         uint64_t data = ReadRegisterUnsigned(eRegisterKindDWARF,
 | |
|                                              start_reg + d + r, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         RegisterInfo data_reg;
 | |
|         GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r, data_reg);
 | |
| 
 | |
|         if (GetByteOrder() == eByteOrderBig) {
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   address - Rn);
 | |
|           if (!MemAWrite(context, address, Bits64(data, 63, 32),
 | |
|                          addr_byte_size))
 | |
|             return false;
 | |
| 
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   (address + 4) - Rn);
 | |
|           if (!MemAWrite(context, address + 4, Bits64(data, 31, 0),
 | |
|                          addr_byte_size))
 | |
|             return false;
 | |
|         } else {
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   address - Rn);
 | |
|           if (!MemAWrite(context, address, Bits64(data, 31, 0), addr_byte_size))
 | |
|             return false;
 | |
| 
 | |
|           context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                   (address + 4) - Rn);
 | |
|           if (!MemAWrite(context, address + 4, Bits64(data, 63, 32),
 | |
|                          addr_byte_size))
 | |
|             return false;
 | |
|         }
 | |
|         // address = address+8;
 | |
|         address = address + 8;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.320
 | |
| // This instruction loads a single extension register from memory, using an
 | |
| // address from an ARM core register, with an optional offset.
 | |
| bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode,
 | |
|                                         ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
 | |
|         base = if n == 15 then Align(PC,4) else R[n];
 | |
|         address = if add then (base + imm32) else (base - imm32);
 | |
|         if single_reg then
 | |
|             S[d] = MemA[address,4];
 | |
|         else
 | |
|             word1 = MemA[address,4]; word2 = MemA[address+4,4];
 | |
|             // Combine the word-aligned words in the correct order for current
 | |
|             // endianness.
 | |
|             D[d] = if BigEndian() then word1:word2 else word2:word1;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool single_reg;
 | |
|     bool add;
 | |
|     uint32_t imm32;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00',
 | |
|       // 32);
 | |
|       single_reg = false;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       single_reg = true;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // d = UInt(Vd:D); n = UInt(Rn);
 | |
|       d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // base = if n == 15 then Align(PC,4) else R[n];
 | |
|     uint32_t base;
 | |
|     if (n == 15)
 | |
|       base = AlignPC(Rn);
 | |
|     else
 | |
|       base = Rn;
 | |
| 
 | |
|     // address = if add then (base + imm32) else (base - imm32);
 | |
|     addr_t address;
 | |
|     if (add)
 | |
|       address = base + imm32;
 | |
|     else
 | |
|       address = base - imm32;
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterLoad;
 | |
|     context.SetRegisterPlusOffset(base_reg, address - base);
 | |
| 
 | |
|     if (single_reg) {
 | |
|       // S[d] = MemA[address,4];
 | |
|       uint32_t data = MemARead(context, address, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, start_reg + d,
 | |
|                                  data))
 | |
|         return false;
 | |
|     } else {
 | |
|       // word1 = MemA[address,4]; word2 = MemA[address+4,4];
 | |
|       uint32_t word1 = MemARead(context, address, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       context.SetRegisterPlusOffset(base_reg, (address + 4) - base);
 | |
|       uint32_t word2 =
 | |
|           MemARead(context, address + 4, addr_byte_size, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|       // // Combine the word-aligned words in the correct order for current
 | |
|       // endianness.
 | |
|       // D[d] = if BigEndian() then word1:word2 else word2:word1;
 | |
|       uint64_t data64;
 | |
|       if (GetByteOrder() == eByteOrderBig) {
 | |
|         data64 = word1;
 | |
|         data64 = (data64 << 32) | word2;
 | |
|       } else {
 | |
|         data64 = word2;
 | |
|         data64 = (data64 << 32) | word1;
 | |
|       }
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, start_reg + d,
 | |
|                                  data64))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.400 VSTR
 | |
| // This instruction stores a signle extension register to memory, using an
 | |
| // address from an ARM core register, with an optional offset.
 | |
| bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode,
 | |
|                                         ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
 | |
|         address = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|         if single_reg then
 | |
|             MemA[address,4] = S[d];
 | |
|         else
 | |
|             // Store as two word-aligned words in the correct order for current
 | |
|             // endianness.
 | |
|             MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
 | |
|             MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     bool single_reg;
 | |
|     bool add;
 | |
|     uint32_t imm32;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1:
 | |
|       // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00',
 | |
|       // 32);
 | |
|       single_reg = false;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
 | |
|       if ((n == 15) && (CurrentInstrSet() != eModeARM))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingT2:
 | |
|     case eEncodingA2:
 | |
|       // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32);
 | |
|       single_reg = true;
 | |
|       add = BitIsSet(opcode, 23);
 | |
|       imm32 = Bits32(opcode, 7, 0) << 2;
 | |
| 
 | |
|       // d = UInt(Vd:D); n = UInt(Rn);
 | |
|       d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
| 
 | |
|       // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
 | |
|       if ((n == 15) && (CurrentInstrSet() != eModeARM))
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = if add then (R[n] + imm32) else (R[n] - imm32);
 | |
|     addr_t address;
 | |
|     if (add)
 | |
|       address = Rn + imm32;
 | |
|     else
 | |
|       address = Rn - imm32;
 | |
| 
 | |
|     const uint32_t addr_byte_size = GetAddressByteSize();
 | |
|     uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
 | |
| 
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, start_reg + d, data_reg);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     if (single_reg) {
 | |
|       // MemA[address,4] = S[d];
 | |
|       uint32_t data =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, start_reg + d, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (!MemAWrite(context, address, data, addr_byte_size))
 | |
|         return false;
 | |
|     } else {
 | |
|       // // Store as two word-aligned words in the correct order for current
 | |
|       // endianness.
 | |
|       // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
 | |
|       // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
 | |
|       uint64_t data =
 | |
|           ReadRegisterUnsigned(eRegisterKindDWARF, start_reg + d, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       if (GetByteOrder() == eByteOrderBig) {
 | |
|         if (!MemAWrite(context, address, Bits64(data, 63, 32), addr_byte_size))
 | |
|           return false;
 | |
| 
 | |
|         context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                 (address + 4) - Rn);
 | |
|         if (!MemAWrite(context, address + 4, Bits64(data, 31, 0),
 | |
|                        addr_byte_size))
 | |
|           return false;
 | |
|       } else {
 | |
|         if (!MemAWrite(context, address, Bits64(data, 31, 0), addr_byte_size))
 | |
|           return false;
 | |
| 
 | |
|         context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                 (address + 4) - Rn);
 | |
|         if (!MemAWrite(context, address + 4, Bits64(data, 63, 32),
 | |
|                        addr_byte_size))
 | |
|           return false;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.307 VLDI1 (multiple single elements) This instruction loads elements
 | |
| // from memory into one, two, three or four registers, without de-interleaving.
 | |
| // Every element of each register is loaded.
 | |
| bool EmulateInstructionARM::EmulateVLD1Multiple(const uint32_t opcode,
 | |
|                                                 ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
 | |
|         address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
 | |
|         if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
 | |
|         for r = 0 to regs-1
 | |
|             for e = 0 to elements-1
 | |
|                 Elem[D[d+r],e,esize] = MemU[address,ebytes];
 | |
|                 address = address + ebytes;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t regs;
 | |
|     uint32_t alignment;
 | |
|     uint32_t ebytes;
 | |
|     uint32_t esize;
 | |
|     uint32_t elements;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool wback;
 | |
|     bool register_index;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1: {
 | |
|       // case type of
 | |
|       // when '0111'
 | |
|       // regs = 1; if align<1> == '1' then UNDEFINED;
 | |
|       // when '1010'
 | |
|       // regs = 2; if align == '11' then UNDEFINED;
 | |
|       // when '0110'
 | |
|       // regs = 3; if align<1> == '1' then UNDEFINED;
 | |
|       // when '0010'
 | |
|       // regs = 4;
 | |
|       // otherwise
 | |
|       // SEE 'Related encodings';
 | |
|       uint32_t type = Bits32(opcode, 11, 8);
 | |
|       uint32_t align = Bits32(opcode, 5, 4);
 | |
|       if (type == 7) // '0111'
 | |
|       {
 | |
|         regs = 1;
 | |
|         if (BitIsSet(align, 1))
 | |
|           return false;
 | |
|       } else if (type == 10) // '1010'
 | |
|       {
 | |
|         regs = 2;
 | |
|         if (align == 3)
 | |
|           return false;
 | |
| 
 | |
|       } else if (type == 6) // '0110'
 | |
|       {
 | |
|         regs = 3;
 | |
|         if (BitIsSet(align, 1))
 | |
|           return false;
 | |
|       } else if (type == 2) // '0010'
 | |
|       {
 | |
|         regs = 4;
 | |
|       } else
 | |
|         return false;
 | |
| 
 | |
|       // alignment = if align == '00' then 1 else 4 << UInt(align);
 | |
|       if (align == 0)
 | |
|         alignment = 1;
 | |
|       else
 | |
|         alignment = 4 << align;
 | |
| 
 | |
|       // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
 | |
|       ebytes = 1 << Bits32(opcode, 7, 6);
 | |
|       esize = 8 * ebytes;
 | |
|       elements = 8 / ebytes;
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 15);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // wback = (m != 15); register_index = (m != 15 && m != 13);
 | |
|       wback = (m != 15);
 | |
|       register_index = ((m != 15) && (m != 13));
 | |
| 
 | |
|       // if d+regs > 32 then UNPREDICTABLE;
 | |
|       if ((d + regs) > 32)
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = R[n]; if (address MOD alignment) != 0 then
 | |
|     // GenerateAlignmentException();
 | |
|     addr_t address = Rn;
 | |
|     if ((address % alignment) != 0)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
 | |
|     if (wback) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       uint32_t offset;
 | |
|       if (register_index)
 | |
|         offset = Rm;
 | |
|       else
 | |
|         offset = 8 * regs;
 | |
| 
 | |
|       uint32_t value = Rn + offset;
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  value))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // for r = 0 to regs-1
 | |
|     for (uint32_t r = 0; r < regs; ++r) {
 | |
|       // for e = 0 to elements-1
 | |
|       uint64_t assembled_data = 0;
 | |
|       for (uint32_t e = 0; e < elements; ++e) {
 | |
|         // Elem[D[d+r],e,esize] = MemU[address,ebytes];
 | |
|         context.type = eContextRegisterLoad;
 | |
|         context.SetRegisterPlusOffset(base_reg, address - Rn);
 | |
|         uint64_t data = MemURead(context, address, ebytes, 0, &success);
 | |
|         if (!success)
 | |
|           return false;
 | |
| 
 | |
|         assembled_data =
 | |
|             (data << (e * esize)) |
 | |
|             assembled_data; // New data goes to the left of existing data
 | |
| 
 | |
|         // address = address + ebytes;
 | |
|         address = address + ebytes;
 | |
|       }
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r,
 | |
|                                  assembled_data))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.308 VLD1 (single element to one lane)
 | |
| //
 | |
| bool EmulateInstructionARM::EmulateVLD1Single(const uint32_t opcode,
 | |
|                                               const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
 | |
|         address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
 | |
|         if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|         Elem[D[d],index,esize] = MemU[address,ebytes];
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t ebytes;
 | |
|     uint32_t esize;
 | |
|     uint32_t index;
 | |
|     uint32_t alignment;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool wback;
 | |
|     bool register_index;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1: {
 | |
|       uint32_t size = Bits32(opcode, 11, 10);
 | |
|       uint32_t index_align = Bits32(opcode, 7, 4);
 | |
|       // if size == '11' then SEE VLD1 (single element to all lanes);
 | |
|       if (size == 3)
 | |
|         return EmulateVLD1SingleAll(opcode, encoding);
 | |
|       // case size of
 | |
|       if (size == 0) // when '00'
 | |
|       {
 | |
|         // if index_align<0> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 0))
 | |
|           return false;
 | |
| 
 | |
|         // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
 | |
|         ebytes = 1;
 | |
|         esize = 8;
 | |
|         index = Bits32(index_align, 3, 1);
 | |
|         alignment = 1;
 | |
|       } else if (size == 1) // when '01'
 | |
|       {
 | |
|         // if index_align<1> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 1))
 | |
|           return false;
 | |
| 
 | |
|         // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
 | |
|         ebytes = 2;
 | |
|         esize = 16;
 | |
|         index = Bits32(index_align, 3, 2);
 | |
| 
 | |
|         // alignment = if index_align<0> == '0' then 1 else 2;
 | |
|         if (BitIsClear(index_align, 0))
 | |
|           alignment = 1;
 | |
|         else
 | |
|           alignment = 2;
 | |
|       } else if (size == 2) // when '10'
 | |
|       {
 | |
|         // if index_align<2> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 2))
 | |
|           return false;
 | |
| 
 | |
|         // if index_align<1:0> != '00' && index_align<1:0> != '11' then
 | |
|         // UNDEFINED;
 | |
|         if ((Bits32(index_align, 1, 0) != 0) &&
 | |
|             (Bits32(index_align, 1, 0) != 3))
 | |
|           return false;
 | |
| 
 | |
|         // ebytes = 4; esize = 32; index = UInt(index_align<3>);
 | |
|         ebytes = 4;
 | |
|         esize = 32;
 | |
|         index = Bit32(index_align, 3);
 | |
| 
 | |
|         // alignment = if index_align<1:0> == '00' then 1 else 4;
 | |
|         if (Bits32(index_align, 1, 0) == 0)
 | |
|           alignment = 1;
 | |
|         else
 | |
|           alignment = 4;
 | |
|       } else {
 | |
|         return false;
 | |
|       }
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15
 | |
|       // then UNPREDICTABLE;
 | |
|       wback = (m != 15);
 | |
|       register_index = ((m != 15) && (m != 13));
 | |
| 
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = R[n]; if (address MOD alignment) != 0 then
 | |
|     // GenerateAlignmentException();
 | |
|     addr_t address = Rn;
 | |
|     if ((address % alignment) != 0)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|     if (wback) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       uint32_t offset;
 | |
|       if (register_index)
 | |
|         offset = Rm;
 | |
|       else
 | |
|         offset = ebytes;
 | |
| 
 | |
|       uint32_t value = Rn + offset;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  value))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // Elem[D[d],index,esize] = MemU[address,ebytes];
 | |
|     uint32_t element = MemURead(context, address, esize, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     element = element << (index * esize);
 | |
| 
 | |
|     uint64_t reg_data =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint64_t all_ones = -1;
 | |
|     uint64_t mask = all_ones
 | |
|                     << ((index + 1) * esize); // mask is all 1's to left of
 | |
|                                               // where 'element' goes, & all 0's
 | |
|     // at element & to the right of element.
 | |
|     if (index > 0)
 | |
|       mask = mask | Bits64(all_ones, (index * esize) - 1,
 | |
|                            0); // add 1's to the right of where 'element' goes.
 | |
|     // now mask should be 0's where element goes & 1's everywhere else.
 | |
| 
 | |
|     uint64_t masked_reg =
 | |
|         reg_data & mask; // Take original reg value & zero out 'element' bits
 | |
|     reg_data =
 | |
|         masked_reg & element; // Put 'element' into those bits in reg_data.
 | |
| 
 | |
|     context.type = eContextRegisterLoad;
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
 | |
|                                reg_data))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.391 VST1 (multiple single elements) Vector Store (multiple single
 | |
| // elements) stores elements to memory from one, two, three, or four registers,
 | |
| // without interleaving.  Every element of each register is stored.
 | |
| bool EmulateInstructionARM::EmulateVST1Multiple(const uint32_t opcode,
 | |
|                                                 ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
 | |
|         address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
 | |
|         if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
 | |
|         for r = 0 to regs-1
 | |
|             for e = 0 to elements-1
 | |
|                 MemU[address,ebytes] = Elem[D[d+r],e,esize];
 | |
|                 address = address + ebytes;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t regs;
 | |
|     uint32_t alignment;
 | |
|     uint32_t ebytes;
 | |
|     uint32_t esize;
 | |
|     uint32_t elements;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool wback;
 | |
|     bool register_index;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1: {
 | |
|       uint32_t type = Bits32(opcode, 11, 8);
 | |
|       uint32_t align = Bits32(opcode, 5, 4);
 | |
| 
 | |
|       // case type of
 | |
|       if (type == 7) // when '0111'
 | |
|       {
 | |
|         // regs = 1; if align<1> == '1' then UNDEFINED;
 | |
|         regs = 1;
 | |
|         if (BitIsSet(align, 1))
 | |
|           return false;
 | |
|       } else if (type == 10) // when '1010'
 | |
|       {
 | |
|         // regs = 2; if align == '11' then UNDEFINED;
 | |
|         regs = 2;
 | |
|         if (align == 3)
 | |
|           return false;
 | |
|       } else if (type == 6) // when '0110'
 | |
|       {
 | |
|         // regs = 3; if align<1> == '1' then UNDEFINED;
 | |
|         regs = 3;
 | |
|         if (BitIsSet(align, 1))
 | |
|           return false;
 | |
|       } else if (type == 2) // when '0010'
 | |
|         // regs = 4;
 | |
|         regs = 4;
 | |
|       else // otherwise
 | |
|         // SEE 'Related encodings';
 | |
|         return false;
 | |
| 
 | |
|       // alignment = if align == '00' then 1 else 4 << UInt(align);
 | |
|       if (align == 0)
 | |
|         alignment = 1;
 | |
|       else
 | |
|         alignment = 4 << align;
 | |
| 
 | |
|       // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
 | |
|       ebytes = 1 << Bits32(opcode, 7, 6);
 | |
|       esize = 8 * ebytes;
 | |
|       elements = 8 / ebytes;
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // wback = (m != 15); register_index = (m != 15 && m != 13);
 | |
|       wback = (m != 15);
 | |
|       register_index = ((m != 15) && (m != 13));
 | |
| 
 | |
|       // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
 | |
|       if ((d + regs) > 32)
 | |
|         return false;
 | |
| 
 | |
|       if (n == 15)
 | |
|         return false;
 | |
| 
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = R[n]; if (address MOD alignment) != 0 then
 | |
|     // GenerateAlignmentException();
 | |
|     addr_t address = Rn;
 | |
|     if ((address % alignment) != 0)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
 | |
|     if (wback) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       uint32_t offset;
 | |
|       if (register_index)
 | |
|         offset = Rm;
 | |
|       else
 | |
|         offset = 8 * regs;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  Rn + offset))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo data_reg;
 | |
|     context.type = eContextRegisterStore;
 | |
|     // for r = 0 to regs-1
 | |
|     for (uint32_t r = 0; r < regs; ++r) {
 | |
|       GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d + r, data_reg);
 | |
|       uint64_t register_data = ReadRegisterUnsigned(
 | |
|           eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       // for e = 0 to elements-1
 | |
|       for (uint32_t e = 0; e < elements; ++e) {
 | |
|         // MemU[address,ebytes] = Elem[D[d+r],e,esize];
 | |
|         uint64_t word = Bits64(register_data, ((e + 1) * esize) - 1, e * esize);
 | |
| 
 | |
|         context.SetRegisterToRegisterPlusOffset(data_reg, base_reg,
 | |
|                                                 address - Rn);
 | |
|         if (!MemUWrite(context, address, word, ebytes))
 | |
|           return false;
 | |
| 
 | |
|         // address = address + ebytes;
 | |
|         address = address + ebytes;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.392 VST1 (single element from one lane) This instruction stores one
 | |
| // element to memory from one element of a register.
 | |
| bool EmulateInstructionARM::EmulateVST1Single(const uint32_t opcode,
 | |
|                                               ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
 | |
|         address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
 | |
|         if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|         MemU[address,ebytes] = Elem[D[d],index,esize];
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t ebytes;
 | |
|     uint32_t esize;
 | |
|     uint32_t index;
 | |
|     uint32_t alignment;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool wback;
 | |
|     bool register_index;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1: {
 | |
|       uint32_t size = Bits32(opcode, 11, 10);
 | |
|       uint32_t index_align = Bits32(opcode, 7, 4);
 | |
| 
 | |
|       // if size == '11' then UNDEFINED;
 | |
|       if (size == 3)
 | |
|         return false;
 | |
| 
 | |
|       // case size of
 | |
|       if (size == 0) // when '00'
 | |
|       {
 | |
|         // if index_align<0> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 0))
 | |
|           return false;
 | |
|         // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
 | |
|         ebytes = 1;
 | |
|         esize = 8;
 | |
|         index = Bits32(index_align, 3, 1);
 | |
|         alignment = 1;
 | |
|       } else if (size == 1) // when '01'
 | |
|       {
 | |
|         // if index_align<1> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 1))
 | |
|           return false;
 | |
| 
 | |
|         // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
 | |
|         ebytes = 2;
 | |
|         esize = 16;
 | |
|         index = Bits32(index_align, 3, 2);
 | |
| 
 | |
|         // alignment = if index_align<0> == '0' then 1 else 2;
 | |
|         if (BitIsClear(index_align, 0))
 | |
|           alignment = 1;
 | |
|         else
 | |
|           alignment = 2;
 | |
|       } else if (size == 2) // when '10'
 | |
|       {
 | |
|         // if index_align<2> != '0' then UNDEFINED;
 | |
|         if (BitIsClear(index_align, 2))
 | |
|           return false;
 | |
| 
 | |
|         // if index_align<1:0> != '00' && index_align<1:0> != '11' then
 | |
|         // UNDEFINED;
 | |
|         if ((Bits32(index_align, 1, 0) != 0) &&
 | |
|             (Bits32(index_align, 1, 0) != 3))
 | |
|           return false;
 | |
| 
 | |
|         // ebytes = 4; esize = 32; index = UInt(index_align<3>);
 | |
|         ebytes = 4;
 | |
|         esize = 32;
 | |
|         index = Bit32(index_align, 3);
 | |
| 
 | |
|         // alignment = if index_align<1:0> == '00' then 1 else 4;
 | |
|         if (Bits32(index_align, 1, 0) == 0)
 | |
|           alignment = 1;
 | |
|         else
 | |
|           alignment = 4;
 | |
|       } else {
 | |
|         return false;
 | |
|       }
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // wback = (m != 15); register_index = (m != 15 && m != 13);  if n == 15
 | |
|       // then UNPREDICTABLE;
 | |
|       wback = (m != 15);
 | |
|       register_index = ((m != 15) && (m != 13));
 | |
| 
 | |
|       if (n == 15)
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = R[n]; if (address MOD alignment) != 0 then
 | |
|     // GenerateAlignmentException();
 | |
|     addr_t address = Rn;
 | |
|     if ((address % alignment) != 0)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|     if (wback) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       uint32_t offset;
 | |
|       if (register_index)
 | |
|         offset = Rm;
 | |
|       else
 | |
|         offset = ebytes;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  Rn + offset))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // MemU[address,ebytes] = Elem[D[d],index,esize];
 | |
|     uint64_t register_data =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint64_t word =
 | |
|         Bits64(register_data, ((index + 1) * esize) - 1, index * esize);
 | |
| 
 | |
|     RegisterInfo data_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d, data_reg);
 | |
|     context.type = eContextRegisterStore;
 | |
|     context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn);
 | |
| 
 | |
|     if (!MemUWrite(context, address, word, ebytes))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // A8.6.309 VLD1 (single element to all lanes) This instruction loads one
 | |
| // element from memory into every element of one or two vectors.
 | |
| bool EmulateInstructionARM::EmulateVLD1SingleAll(const uint32_t opcode,
 | |
|                                                  const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
 | |
|         address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
 | |
|         if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|         replicated_element = Replicate(MemU[address,ebytes], elements);
 | |
|         for r = 0 to regs-1
 | |
|             D[d+r] = replicated_element;
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t ebytes;
 | |
|     uint32_t elements;
 | |
|     uint32_t regs;
 | |
|     uint32_t alignment;
 | |
|     uint32_t d;
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     bool wback;
 | |
|     bool register_index;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|     case eEncodingA1: {
 | |
|       // if size == '11' || (size == '00' && a == '1') then UNDEFINED;
 | |
|       uint32_t size = Bits32(opcode, 7, 6);
 | |
|       if ((size == 3) || ((size == 0) && BitIsSet(opcode, 4)))
 | |
|         return false;
 | |
| 
 | |
|       // ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == '0'
 | |
|       // then 1 else 2;
 | |
|       ebytes = 1 << size;
 | |
|       elements = 8 / ebytes;
 | |
|       if (BitIsClear(opcode, 5))
 | |
|         regs = 1;
 | |
|       else
 | |
|         regs = 2;
 | |
| 
 | |
|       // alignment = if a == '0' then 1 else ebytes;
 | |
|       if (BitIsClear(opcode, 4))
 | |
|         alignment = 1;
 | |
|       else
 | |
|         alignment = ebytes;
 | |
| 
 | |
|       // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
 | |
|       d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
| 
 | |
|       // wback = (m != 15); register_index = (m != 15 && m != 13);
 | |
|       wback = (m != 15);
 | |
|       register_index = ((m != 15) && (m != 13));
 | |
| 
 | |
|       // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
 | |
|       if ((d + regs) > 32)
 | |
|         return false;
 | |
| 
 | |
|       if (n == 15)
 | |
|         return false;
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     RegisterInfo base_reg;
 | |
|     GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg);
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     // address = R[n]; if (address MOD alignment) != 0 then
 | |
|     // GenerateAlignmentException();
 | |
|     addr_t address = Rn;
 | |
|     if ((address % alignment) != 0)
 | |
|       return false;
 | |
| 
 | |
|     EmulateInstruction::Context context;
 | |
|     // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
 | |
|     if (wback) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       uint32_t offset;
 | |
|       if (register_index)
 | |
|         offset = Rm;
 | |
|       else
 | |
|         offset = ebytes;
 | |
| 
 | |
|       context.type = eContextAdjustBaseRegister;
 | |
|       context.SetRegisterPlusOffset(base_reg, offset);
 | |
| 
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
 | |
|                                  Rn + offset))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // replicated_element = Replicate(MemU[address,ebytes], elements);
 | |
| 
 | |
|     context.type = eContextRegisterLoad;
 | |
|     uint64_t word = MemURead(context, address, ebytes, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     uint64_t replicated_element = 0;
 | |
|     uint32_t esize = ebytes * 8;
 | |
|     for (uint32_t e = 0; e < elements; ++e)
 | |
|       replicated_element =
 | |
|           (replicated_element << esize) | Bits64(word, esize - 1, 0);
 | |
| 
 | |
|     // for r = 0 to regs-1
 | |
|     for (uint32_t r = 0; r < regs; ++r) {
 | |
|       // D[d+r] = replicated_element;
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r,
 | |
|                                  replicated_element))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // B6.2.13 SUBS PC, LR and related instructions The SUBS PC, LR, #<const?
 | |
| // instruction provides an exception return without the use of the stack.  It
 | |
| // subtracts the immediate constant from the LR, branches to the resulting
 | |
| // address, and also copies the SPSR to the CPSR.
 | |
| bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode,
 | |
|                                                const ARMEncoding encoding) {
 | |
| #if 0
 | |
|     if ConditionPassed() then
 | |
|         EncodingSpecificOperations();
 | |
|         if CurrentInstrSet() == InstrSet_ThumbEE then
 | |
|             UNPREDICTABLE;
 | |
|         operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32;
 | |
|         case opcode of
 | |
|             when '0000' result = R[n] AND operand2; // AND
 | |
|             when '0001' result = R[n] EOR operand2; // EOR
 | |
|             when '0010' (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB
 | |
|             when '0011' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB
 | |
|             when '0100' (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD
 | |
|             when '0101' (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
 | |
|             when '0110' (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
 | |
|             when '0111' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
 | |
|             when '1100' result = R[n] OR operand2; // ORR
 | |
|             when '1101' result = operand2; // MOV
 | |
|             when '1110' result = R[n] AND NOT(operand2); // BIC
 | |
|             when '1111' result = NOT(operand2); // MVN
 | |
|         CPSRWriteByInstr(SPSR[], '1111', TRUE);
 | |
|         BranchWritePC(result);
 | |
| #endif
 | |
| 
 | |
|   bool success = false;
 | |
| 
 | |
|   if (ConditionPassed(opcode)) {
 | |
|     uint32_t n;
 | |
|     uint32_t m;
 | |
|     uint32_t imm32;
 | |
|     bool register_form;
 | |
|     ARM_ShifterType shift_t;
 | |
|     uint32_t shift_n;
 | |
|     uint32_t code;
 | |
| 
 | |
|     switch (encoding) {
 | |
|     case eEncodingT1:
 | |
|       // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE n = 14;
 | |
|       // imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = '0010';
 | |
|       // // = SUB
 | |
|       n = 14;
 | |
|       imm32 = Bits32(opcode, 7, 0);
 | |
|       register_form = false;
 | |
|       code = 2;
 | |
| 
 | |
|       // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
 | |
|       if (InITBlock() && !LastInITBlock())
 | |
|         return false;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA1:
 | |
|       // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       imm32 = ARMExpandImm(opcode);
 | |
|       register_form = false;
 | |
|       code = Bits32(opcode, 24, 21);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case eEncodingA2:
 | |
|       // n = UInt(Rn); m = UInt(Rm); register_form = TRUE;
 | |
|       n = Bits32(opcode, 19, 16);
 | |
|       m = Bits32(opcode, 3, 0);
 | |
|       register_form = true;
 | |
| 
 | |
|       // (shift_t, shift_n) = DecodeImmShift(type, imm5);
 | |
|       shift_n = DecodeImmShiftARM(opcode, shift_t);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C)
 | |
|     // else imm32;
 | |
|     uint32_t operand2;
 | |
|     if (register_form) {
 | |
|       uint32_t Rm = ReadCoreReg(m, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
| 
 | |
|       operand2 = Shift(Rm, shift_t, shift_n, APSR_C, &success);
 | |
|       if (!success)
 | |
|         return false;
 | |
|     } else {
 | |
|       operand2 = imm32;
 | |
|     }
 | |
| 
 | |
|     uint32_t Rn = ReadCoreReg(n, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     AddWithCarryResult result;
 | |
| 
 | |
|     // case opcode of
 | |
|     switch (code) {
 | |
|     case 0: // when '0000'
 | |
|       // result = R[n] AND operand2; // AND
 | |
|       result.result = Rn & operand2;
 | |
|       break;
 | |
| 
 | |
|     case 1: // when '0001'
 | |
|       // result = R[n] EOR operand2; // EOR
 | |
|       result.result = Rn ^ operand2;
 | |
|       break;
 | |
| 
 | |
|     case 2: // when '0010'
 | |
|       // (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB
 | |
|       result = AddWithCarry(Rn, ~(operand2), 1);
 | |
|       break;
 | |
| 
 | |
|     case 3: // when '0011'
 | |
|       // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB
 | |
|       result = AddWithCarry(~(Rn), operand2, 1);
 | |
|       break;
 | |
| 
 | |
|     case 4: // when '0100'
 | |
|       // (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD
 | |
|       result = AddWithCarry(Rn, operand2, 0);
 | |
|       break;
 | |
| 
 | |
|     case 5: // when '0101'
 | |
|       // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
 | |
|       result = AddWithCarry(Rn, operand2, APSR_C);
 | |
|       break;
 | |
| 
 | |
|     case 6: // when '0110'
 | |
|       // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
 | |
|       result = AddWithCarry(Rn, ~(operand2), APSR_C);
 | |
|       break;
 | |
| 
 | |
|     case 7: // when '0111'
 | |
|       // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
 | |
|       result = AddWithCarry(~(Rn), operand2, APSR_C);
 | |
|       break;
 | |
| 
 | |
|     case 10: // when '1100'
 | |
|       // result = R[n] OR operand2; // ORR
 | |
|       result.result = Rn | operand2;
 | |
|       break;
 | |
| 
 | |
|     case 11: // when '1101'
 | |
|       // result = operand2; // MOV
 | |
|       result.result = operand2;
 | |
|       break;
 | |
| 
 | |
|     case 12: // when '1110'
 | |
|       // result = R[n] AND NOT(operand2); // BIC
 | |
|       result.result = Rn & ~(operand2);
 | |
|       break;
 | |
| 
 | |
|     case 15: // when '1111'
 | |
|       // result = NOT(operand2); // MVN
 | |
|       result.result = ~(operand2);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|     // CPSRWriteByInstr(SPSR[], '1111', TRUE);
 | |
| 
 | |
|     // For now, in emulation mode, we don't have access to the SPSR, so we will
 | |
|     // use the CPSR instead, and hope for the best.
 | |
|     uint32_t spsr =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     CPSRWriteByInstr(spsr, 15, true);
 | |
| 
 | |
|     // BranchWritePC(result);
 | |
|     EmulateInstruction::Context context;
 | |
|     context.type = eContextAdjustPC;
 | |
|     context.SetImmediate(result.result);
 | |
| 
 | |
|     BranchWritePC(context, result.result);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| EmulateInstructionARM::ARMOpcode *
 | |
| EmulateInstructionARM::GetARMOpcodeForInstruction(const uint32_t opcode,
 | |
|                                                   uint32_t arm_isa) {
 | |
|   static ARMOpcode g_arm_opcodes[] = {
 | |
|       // Prologue instructions
 | |
| 
 | |
|       // push register(s)
 | |
|       {0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePUSH, "push <registers>"},
 | |
|       {0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePUSH, "push <register>"},
 | |
| 
 | |
|       // set r7 to point to a stack offset
 | |
|       {0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #<const>"},
 | |
|       {0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #<const>"},
 | |
|       // copy the stack pointer to ip
 | |
|       {0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp"},
 | |
|       {0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #<const>"},
 | |
|       {0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #<const>"},
 | |
| 
 | |
|       // adjust the stack pointer
 | |
|       {0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #<const>"},
 | |
|       {0x0fef0010, 0x004d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPReg,
 | |
|        "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}"},
 | |
| 
 | |
|       // push one register
 | |
|       // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
 | |
|       {0x0e5f0000, 0x040d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!"},
 | |
| 
 | |
|       // vector push consecutive extension register(s)
 | |
|       {0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
 | |
|       {0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
 | |
| 
 | |
|       // Epilogue instructions
 | |
| 
 | |
|       {0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
 | |
|       {0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePOP, "pop <register>"},
 | |
|       {0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
 | |
|       {0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
 | |
| 
 | |
|       // Supervisor Call (previously Software Interrupt)
 | |
|       {0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
 | |
| 
 | |
|       // Branch instructions
 | |
|       // To resolve ambiguity, "blx <label>" should come before "b #imm24" and
 | |
|       // "bl <label>".
 | |
|       {0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
 | |
|       {0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateB, "b #imm24"},
 | |
|       {0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
 | |
|       {0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
 | |
|       // for example, "bx lr"
 | |
|       {0x0ffffff0, 0x012fff10, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
 | |
|       // bxj
 | |
|       {0x0ffffff0, 0x012fff20, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
 | |
| 
 | |
|       // Data-processing instructions
 | |
|       // adc (immediate)
 | |
|       {0x0fe00000, 0x02a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // adc (register)
 | |
|       {0x0fe00010, 0x00a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADCReg,
 | |
|        "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // add (immediate)
 | |
|       {0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDImmARM,
 | |
|        "add{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // add (register)
 | |
|       {0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDReg,
 | |
|        "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // add (register-shifted register)
 | |
|       {0x0fe00090, 0x00800010, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDRegShift,
 | |
|        "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"},
 | |
|       // adr
 | |
|       {0x0fff0000, 0x028f0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
 | |
|       {0x0fff0000, 0x024f0000, ARMvAll, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
 | |
|       // and (immediate)
 | |
|       {0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // and (register)
 | |
|       {0x0fe00010, 0x00000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateANDReg,
 | |
|        "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // bic (immediate)
 | |
|       {0x0fe00000, 0x03c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // bic (register)
 | |
|       {0x0fe00010, 0x01c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBICReg,
 | |
|        "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // eor (immediate)
 | |
|       {0x0fe00000, 0x02200000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // eor (register)
 | |
|       {0x0fe00010, 0x00200000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateEORReg,
 | |
|        "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // orr (immediate)
 | |
|       {0x0fe00000, 0x03800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"},
 | |
|       // orr (register)
 | |
|       {0x0fe00010, 0x01800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateORRReg,
 | |
|        "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // rsb (immediate)
 | |
|       {0x0fe00000, 0x02600000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // rsb (register)
 | |
|       {0x0fe00010, 0x00600000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSBReg,
 | |
|        "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // rsc (immediate)
 | |
|       {0x0fe00000, 0x02e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // rsc (register)
 | |
|       {0x0fe00010, 0x00e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSCReg,
 | |
|        "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // sbc (immediate)
 | |
|       {0x0fe00000, 0x02c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // sbc (register)
 | |
|       {0x0fe00010, 0x00c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSBCReg,
 | |
|        "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // sub (immediate, ARM)
 | |
|       {0x0fe00000, 0x02400000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBImmARM,
 | |
|        "sub{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // sub (sp minus immediate)
 | |
|       {0x0fef0000, 0x024d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"},
 | |
|       // sub (register)
 | |
|       {0x0fe00010, 0x00400000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBReg,
 | |
|        "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"},
 | |
|       // teq (immediate)
 | |
|       {0x0ff0f000, 0x03300000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"},
 | |
|       // teq (register)
 | |
|       {0x0ff0f010, 0x01300000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
 | |
|       // tst (immediate)
 | |
|       {0x0ff0f000, 0x03100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"},
 | |
|       // tst (register)
 | |
|       {0x0ff0f010, 0x01100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"},
 | |
| 
 | |
|       // mov (immediate)
 | |
|       {0x0fef0000, 0x03a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c> <Rd>, #<const>"},
 | |
|       {0x0ff00000, 0x03000000, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>, #<imm16>"},
 | |
|       // mov (register)
 | |
|       {0x0fef0ff0, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"},
 | |
|       // mvn (immediate)
 | |
|       {0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"},
 | |
|       // mvn (register)
 | |
|       {0x0fef0010, 0x01e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMVNReg,
 | |
|        "mvn{s}<c> <Rd>, <Rm> {,<shift>}"},
 | |
|       // cmn (immediate)
 | |
|       {0x0ff0f000, 0x03700000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
 | |
|       // cmn (register)
 | |
|       {0x0ff0f010, 0x01700000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
 | |
|       // cmp (immediate)
 | |
|       {0x0ff0f000, 0x03500000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"},
 | |
|       // cmp (register)
 | |
|       {0x0ff0f010, 0x01500000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"},
 | |
|       // asr (immediate)
 | |
|       {0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"},
 | |
|       // asr (register)
 | |
|       {0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"},
 | |
|       // lsl (immediate)
 | |
|       {0x0fef0070, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"},
 | |
|       // lsl (register)
 | |
|       {0x0fef00f0, 0x01a00010, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"},
 | |
|       // lsr (immediate)
 | |
|       {0x0fef0070, 0x01a00020, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"},
 | |
|       // lsr (register)
 | |
|       {0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"},
 | |
|       // rrx is a special case encoding of ror (immediate)
 | |
|       {0x0fef0ff0, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"},
 | |
|       // ror (immediate)
 | |
|       {0x0fef0070, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"},
 | |
|       // ror (register)
 | |
|       {0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"},
 | |
|       // mul
 | |
|       {0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>"},
 | |
| 
 | |
|       // subs pc, lr and related instructions
 | |
|       {0x0e10f000, 0x0210f000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPcLrEtc,
 | |
|        "<opc>S<c> PC,#<const> | <Rn>,#<const>"},
 | |
|       {0x0e10f010, 0x0010f000, ARMvAll, eEncodingA2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPcLrEtc,
 | |
|        "<opc>S<c> PC,<Rn>,<Rm{,<shift>}"},
 | |
| 
 | |
|       // Load instructions
 | |
|       {0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>"},
 | |
|       {0x0e500000, 0x04100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRImmediateARM,
 | |
|        "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]"},
 | |
|       {0x0e500010, 0x06100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRRegister,
 | |
|        "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}"},
 | |
|       {0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>, [...]"},
 | |
|       {0xfe500010, 0x06500000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBRegister,
 | |
|        "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}"},
 | |
|       {0x0e5f00f0, 0x005f00b0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>"},
 | |
|       {0x0e5000f0, 0x001000b0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHRegister,
 | |
|        "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}"},
 | |
|       {0x0e5000f0, 0x005000d0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBImmediate,
 | |
|        "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]"},
 | |
|       {0x0e5f00f0, 0x005f00d0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt> <label>"},
 | |
|       {0x0e5000f0, 0x001000d0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBRegister,
 | |
|        "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}"},
 | |
|       {0x0e5000f0, 0x005000f0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHImmediate,
 | |
|        "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]"},
 | |
|       {0x0e5f00f0, 0x005f00f0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>"},
 | |
|       {0x0e5000f0, 0x001000f0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHRegister,
 | |
|        "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}"},
 | |
|       {0x0e5000f0, 0x004000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRDImmediate,
 | |
|        "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!"},
 | |
|       {0x0e500ff0, 0x000000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRDRegister,
 | |
|        "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
 | |
|       {0x0e100f00, 0x0c100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0x0e100f00, 0x0c100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0x0f300f00, 0x0d100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
 | |
|       {0x0f300f00, 0x0d100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
 | |
|       {0xffb00000, 0xf4200000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1Multiple,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
|       {0xffb00300, 0xf4a00000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1Single,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
|       {0xffb00f00, 0xf4a00c00, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1SingleAll,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
| 
 | |
|       // Store instructions
 | |
|       {0x0fd00000, 0x08800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x08000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTMDA, "stmda<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x09000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>"},
 | |
|       {0x0fd00000, 0x09800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTMIB, "stmib<c> <Rn>{!} <registers>"},
 | |
|       {0x0e500010, 0x06000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRRegister,
 | |
|        "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}"},
 | |
|       {0x0e5000f0, 0x000000b0, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRHRegister,
 | |
|        "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}"},
 | |
|       {0x0ff00ff0, 0x01800f90, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn>]"},
 | |
|       {0x0e500000, 0x04400000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRBImmARM,
 | |
|        "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
 | |
|       {0x0e500000, 0x04000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRImmARM,
 | |
|        "str<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
 | |
|       {0x0e5000f0, 0x004000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRDImm,
 | |
|        "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!"},
 | |
|       {0x0e500ff0, 0x000000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRDReg,
 | |
|        "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
 | |
|       {0x0e100f00, 0x0c000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
 | |
|       {0x0e100f00, 0x0c000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
 | |
|       {0x0f300f00, 0x0d000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]"},
 | |
|       {0x0f300f00, 0x0d000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]"},
 | |
|       {0xffb00000, 0xf4000000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVST1Multiple,
 | |
|        "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
|       {0xffb00300, 0xf4800000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVST1Single,
 | |
|        "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
| 
 | |
|       // Other instructions
 | |
|       {0x0fff00f0, 0x06af00f0, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0x0fff00f0, 0x06bf0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0x0fff00f0, 0x06ef0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}"}
 | |
| 
 | |
|   };
 | |
|   static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_arm_opcodes);
 | |
| 
 | |
|   for (size_t i = 0; i < k_num_arm_opcodes; ++i) {
 | |
|     if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value &&
 | |
|         (g_arm_opcodes[i].variants & arm_isa) != 0)
 | |
|       return &g_arm_opcodes[i];
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| EmulateInstructionARM::ARMOpcode *
 | |
| EmulateInstructionARM::GetThumbOpcodeForInstruction(const uint32_t opcode,
 | |
|                                                     uint32_t arm_isa) {
 | |
| 
 | |
|   static ARMOpcode g_thumb_opcodes[] = {
 | |
|       // Prologue instructions
 | |
| 
 | |
|       // push register(s)
 | |
|       {0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulatePUSH, "push <registers>"},
 | |
|       {0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePUSH, "push.w <registers>"},
 | |
|       {0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePUSH, "push.w <register>"},
 | |
| 
 | |
|       // set r7 to point to a stack offset
 | |
|       {0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm"},
 | |
|       // copy the stack pointer to r7
 | |
|       {0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp"},
 | |
|       // move from high register to low register (comes after "mov r7, sp" to
 | |
|       // resolve ambiguity)
 | |
|       {0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15"},
 | |
| 
 | |
|       // PC-relative load into register (see also EmulateADDSPRm)
 | |
|       {0xfffff800, 0x00004800, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"},
 | |
| 
 | |
|       // adjust the stack pointer
 | |
|       {0xffffff87, 0x00004485, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDSPRm, "add sp, <Rm>"},
 | |
|       {0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #imm"},
 | |
|       {0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "sub.w sp, sp, #<const>"},
 | |
|       {0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "subw sp, sp, #imm12"},
 | |
|       {0xffef8000, 0xebad0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPReg,
 | |
|        "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}"},
 | |
| 
 | |
|       // vector push consecutive extension register(s)
 | |
|       {0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
 | |
|       {0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
 | |
| 
 | |
|       // Epilogue instructions
 | |
| 
 | |
|       {0xfffff800, 0x0000a800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDSPImm, "add<c> <Rd>, sp, #imm"},
 | |
|       {0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDSPImm, "add sp, #imm"},
 | |
|       {0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
 | |
|       {0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePOP, "pop.w <registers>"},
 | |
|       {0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulatePOP, "pop.w <register>"},
 | |
|       {0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
 | |
|       {0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
 | |
| 
 | |
|       // Supervisor Call (previously Software Interrupt)
 | |
|       {0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
 | |
| 
 | |
|       // If Then makes up to four following instructions conditional.
 | |
|       // The next 5 opcode _must_ come before the if then instruction
 | |
|       {0xffffffff, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateNop, "nop"},
 | |
|       {0xffffffff, 0x0000bf10, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateNop, "nop YIELD (yield hint)"},
 | |
|       {0xffffffff, 0x0000bf20, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateNop, "nop WFE (wait for event hint)"},
 | |
|       {0xffffffff, 0x0000bf30, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateNop, "nop WFI (wait for interrupt hint)"},
 | |
|       {0xffffffff, 0x0000bf40, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateNop, "nop SEV (send event hint)"},
 | |
|       {0xffffff00, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
 | |
| 
 | |
|       // Branch instructions
 | |
|       // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
 | |
|       {0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
 | |
|       {0xfffff800, 0x0000e000, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateB, "b<c> #imm11 (outside or last in IT)"},
 | |
|       {0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
 | |
|       {0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateB,
 | |
|        "b<c>.w #imm8 (outside or last in IT)"},
 | |
|       // J1 == J2 == 1
 | |
|       {0xf800d000, 0xf000d000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
 | |
|       // J1 == J2 == 1
 | |
|       {0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
 | |
|       {0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
 | |
|       // for example, "bx lr"
 | |
|       {0xffffff87, 0x00004700, ARMvAll, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
 | |
|       // bxj
 | |
|       {0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
 | |
|       // compare and branch
 | |
|       {0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
 | |
|       // table branch byte
 | |
|       {0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"},
 | |
|       // table branch halfword
 | |
|       {0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"},
 | |
| 
 | |
|       // Data-processing instructions
 | |
|       // adc (immediate)
 | |
|       {0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // adc (register)
 | |
|       {0xffffffc0, 0x00004140, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADCReg, "adcs|adc<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xeb400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADCReg,
 | |
|        "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // add (register)
 | |
|       {0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"},
 | |
|       // Make sure "add sp, <Rm>" comes before this instruction, so there's no
 | |
|       // ambiguity decoding the two.
 | |
|       {0xffffff00, 0x00004400, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"},
 | |
|       // adr
 | |
|       {0xfffff800, 0x0000a000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
 | |
|       {0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
 | |
|       {0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
 | |
|       // and (immediate)
 | |
|       {0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // and (register)
 | |
|       {0xffffffc0, 0x00004000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateANDReg, "ands|and<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xea000000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateANDReg,
 | |
|        "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // bic (immediate)
 | |
|       {0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // bic (register)
 | |
|       {0xffffffc0, 0x00004380, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateBICReg, "bics|bic<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xea200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateBICReg,
 | |
|        "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // eor (immediate)
 | |
|       {0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // eor (register)
 | |
|       {0xffffffc0, 0x00004040, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateEORReg, "eors|eor<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xea800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateEORReg,
 | |
|        "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // orr (immediate)
 | |
|       {0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // orr (register)
 | |
|       {0xffffffc0, 0x00004300, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateORRReg, "orrs|orr<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateORRReg,
 | |
|        "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // rsb (immediate)
 | |
|       {0xffffffc0, 0x00004240, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateRSBImm, "rsbs|rsb<c> <Rd>, <Rn>, #0"},
 | |
|       {0xfbe08000, 0xf1c00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSBImm,
 | |
|        "rsb{s}<c>.w <Rd>, <Rn>, #<const>"},
 | |
|       // rsb (register)
 | |
|       {0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRSBReg,
 | |
|        "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // sbc (immediate)
 | |
|       {0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
 | |
|       // sbc (register)
 | |
|       {0xffffffc0, 0x00004180, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSBCReg, "sbcs|sbc<c> <Rdn>, <Rm>"},
 | |
|       {0xffe08000, 0xeb600000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSBCReg,
 | |
|        "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
 | |
|       // add (immediate, Thumb)
 | |
|       {0xfffffe00, 0x00001c00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDImmThumb,
 | |
|        "adds|add<c> <Rd>,<Rn>,#<imm3>"},
 | |
|       {0xfffff800, 0x00003000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rdn>,#<imm8>"},
 | |
|       {0xfbe08000, 0xf1000000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDImmThumb,
 | |
|        "add{s}<c>.w <Rd>,<Rn>,#<const>"},
 | |
|       {0xfbf08000, 0xf2000000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateADDImmThumb,
 | |
|        "addw<c> <Rd>,<Rn>,#<imm12>"},
 | |
|       // sub (immediate, Thumb)
 | |
|       {0xfffffe00, 0x00001e00, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSUBImmThumb,
 | |
|        "subs|sub<c> <Rd>, <Rn> #imm3"},
 | |
|       {0xfffff800, 0x00003800, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rdn>, #imm8"},
 | |
|       {0xfbe08000, 0xf1a00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBImmThumb,
 | |
|        "sub{s}<c>.w <Rd>, <Rn>, #<const>"},
 | |
|       {0xfbf08000, 0xf2a00000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBImmThumb,
 | |
|        "subw<c> <Rd>, <Rn>, #imm12"},
 | |
|       // sub (sp minus immediate)
 | |
|       {0xfbef8000, 0xf1ad0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}.w <Rd>, sp, #<const>"},
 | |
|       {0xfbff8000, 0xf2ad0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPImm, "subw<c> <Rd>, sp, #imm12"},
 | |
|       // sub (register)
 | |
|       {0xfffffe00, 0x00001a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSUBReg, "subs|sub<c> <Rd>, <Rn>, <Rm>"},
 | |
|       {0xffe08000, 0xeba00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBReg,
 | |
|        "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}"},
 | |
|       // teq (immediate)
 | |
|       {0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"},
 | |
|       // teq (register)
 | |
|       {0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
 | |
|       // tst (immediate)
 | |
|       {0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"},
 | |
|       // tst (register)
 | |
|       {0xffffffc0, 0x00004200, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rdn>, <Rm>"},
 | |
|       {0xfff08f00, 0xea100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateTSTReg, "tst<c>.w <Rn>, <Rm> {,<shift>}"},
 | |
| 
 | |
|       // move from high register to high register
 | |
|       {0xffffff00, 0x00004600, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"},
 | |
|       // move from low register to low register
 | |
|       {0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"},
 | |
|       // mov{s}<c>.w <Rd>, <Rm>
 | |
|       {0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"},
 | |
|       // move immediate
 | |
|       {0xfffff800, 0x00002000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMOVRdImm, "movs|mov<c> <Rd>, #imm8"},
 | |
|       {0xfbef8000, 0xf04f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c>.w <Rd>, #<const>"},
 | |
|       {0xfbf08000, 0xf2400000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>,#<imm16>"},
 | |
|       // mvn (immediate)
 | |
|       {0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"},
 | |
|       // mvn (register)
 | |
|       {0xffffffc0, 0x000043c0, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMVNReg, "mvns|mvn<c> <Rd>, <Rm>"},
 | |
|       {0xffef8000, 0xea6f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMVNReg,
 | |
|        "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}"},
 | |
|       // cmn (immediate)
 | |
|       {0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
 | |
|       // cmn (register)
 | |
|       {0xffffffc0, 0x000042c0, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm>"},
 | |
|       {0xfff08f00, 0xeb100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
 | |
|       // cmp (immediate)
 | |
|       {0xfffff800, 0x00002800, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #imm8"},
 | |
|       {0xfbf08f00, 0xf1b00f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateCMPImm, "cmp<c>.w <Rn>, #<const>"},
 | |
|       // cmp (register) (Rn and Rm both from r0-r7)
 | |
|       {0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
 | |
|       // cmp (register) (Rn and Rm not both from r0-r7)
 | |
|       {0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
 | |
|       {0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateCMPReg,
 | |
|        "cmp<c>.w <Rn>, <Rm> {, <shift>}"},
 | |
|       // asr (immediate)
 | |
|       {0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"},
 | |
|       {0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"},
 | |
|       // asr (register)
 | |
|       {0xffffffc0, 0x00004100, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"},
 | |
|       {0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"},
 | |
|       // lsl (immediate)
 | |
|       {0xfffff800, 0x00000000, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLSLImm, "lsls|lsl<c> <Rd>, <Rm>, #imm"},
 | |
|       {0xffef8030, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c>.w <Rd>, <Rm>, #imm"},
 | |
|       // lsl (register)
 | |
|       {0xffffffc0, 0x00004080, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLSLReg, "lsls|lsl<c> <Rdn>, <Rm>"},
 | |
|       {0xffe0f0f0, 0xfa00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c>.w <Rd>, <Rn>, <Rm>"},
 | |
|       // lsr (immediate)
 | |
|       {0xfffff800, 0x00000800, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLSRImm, "lsrs|lsr<c> <Rd>, <Rm>, #imm"},
 | |
|       {0xffef8030, 0xea4f0010, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c>.w <Rd>, <Rm>, #imm"},
 | |
|       // lsr (register)
 | |
|       {0xffffffc0, 0x000040c0, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLSRReg, "lsrs|lsr<c> <Rdn>, <Rm>"},
 | |
|       {0xffe0f0f0, 0xfa20f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c>.w <Rd>, <Rn>, <Rm>"},
 | |
|       // rrx is a special case encoding of ror (immediate)
 | |
|       {0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"},
 | |
|       // ror (immediate)
 | |
|       {0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"},
 | |
|       // ror (register)
 | |
|       {0xffffffc0, 0x000041c0, ARMvAll, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateRORReg, "rors|ror<c> <Rdn>, <Rm>"},
 | |
|       {0xffe0f0f0, 0xfa60f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRORReg, "ror{s}<c>.w <Rd>, <Rn>, <Rm>"},
 | |
|       // mul
 | |
|       {0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>"},
 | |
|       // mul
 | |
|       {0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>"},
 | |
| 
 | |
|       // subs pc, lr and related instructions
 | |
|       {0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>"},
 | |
| 
 | |
|       // RFE instructions  *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE
 | |
|       // LDM.. Instructions in this table;
 | |
|       // otherwise the wrong instructions will be selected.
 | |
| 
 | |
|       {0xffd0ffff, 0xe810c000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}"},
 | |
|       {0xffd0ffff, 0xe990c000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}"},
 | |
| 
 | |
|       // Load instructions
 | |
|       {0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>"},
 | |
|       {0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>"},
 | |
|       {0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>"},
 | |
|       {0xfffff800, 0x00006800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"},
 | |
|       {0xfffff800, 0x00009800, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [SP{,#imm}]"},
 | |
|       {0xfff00000, 0xf8d00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRRtRnImm,
 | |
|        "ldr<c>.w <Rt>, [<Rn>{,#imm12}]"},
 | |
|       {0xfff00800, 0xf8500800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRRtRnImm,
 | |
|        "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}"},
 | |
|       // Thumb2 PC-relative load into register
 | |
|       {0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRRtPCRelative,
 | |
|        "ldr<c>.w <Rt>, [PC, +/-#imm}]"},
 | |
|       {0xfffffe00, 0x00005800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt>, [<Rn>, <Rm>]"},
 | |
|       {0xfff00fc0, 0xf8500000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRRegister,
 | |
|        "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]"},
 | |
|       {0xfffff800, 0x00007800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRBImmediate,
 | |
|        "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]"},
 | |
|       {0xfff00000, 0xf8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBImmediate,
 | |
|        "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]"},
 | |
|       {0xfff00800, 0xf8100800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBImmediate,
 | |
|        "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}"},
 | |
|       {0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>,[...]"},
 | |
|       {0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>,[<Rn>,<Rm>]"},
 | |
|       {0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRBRegister,
 | |
|        "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]"},
 | |
|       {0xfffff800, 0x00008800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRHImmediate,
 | |
|        "ldrh<c> <Rt>, [<Rn>{,#<imm>}]"},
 | |
|       {0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHImmediate,
 | |
|        "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]"},
 | |
|       {0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHImmediate,
 | |
|        "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}"},
 | |
|       {0xff7f0000, 0xf83f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>"},
 | |
|       {0xfffffe00, 0x00005a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRHRegister,
 | |
|        "ldrh<c> <Rt>, [<Rn>,<Rm>]"},
 | |
|       {0xfff00fc0, 0xf8300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRHRegister,
 | |
|        "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"},
 | |
|       {0xfff00000, 0xf9900000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBImmediate,
 | |
|        "ldrsb<c> <Rt>,[<Rn>,#<imm12>]"},
 | |
|       {0xfff00800, 0xf9100800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBImmediate,
 | |
|        "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]"},
 | |
|       {0xff7f0000, 0xf91f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt>, <label>"},
 | |
|       {0xfffffe00, 0x00005600, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRSBRegister,
 | |
|        "ldrsb<c> <Rt>,[<Rn>,<Rm>]"},
 | |
|       {0xfff00fc0, 0xf9100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSBRegister,
 | |
|        "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]"},
 | |
|       {0xfff00000, 0xf9b00000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHImmediate,
 | |
|        "ldrsh<c> <Rt>,[<Rn>,#<imm12>]"},
 | |
|       {0xfff00800, 0xf9300800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHImmediate,
 | |
|        "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]"},
 | |
|       {0xff7f0000, 0xf93f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>"},
 | |
|       {0xfffffe00, 0x00005e00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateLDRSHRegister,
 | |
|        "ldrsh<c> <Rt>,[<Rn>,<Rm>]"},
 | |
|       {0xfff00fc0, 0xf9300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRSHRegister,
 | |
|        "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"},
 | |
|       {0xfe500000, 0xe8500000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateLDRDImmediate,
 | |
|        "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!"},
 | |
|       {0xfe100f00, 0xec100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0xfe100f00, 0xec100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0xffe00f00, 0xed100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
 | |
|       {0xff300f00, 0xed100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]"},
 | |
|       {0xffb00000, 0xf9200000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1Multiple,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
 | |
|       {0xffb00300, 0xf9a00000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1Single,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
 | |
|       {0xffb00f00, 0xf9a00c00, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVLD1SingleAll,
 | |
|        "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
| 
 | |
|       // Store instructions
 | |
|       {0xfffff800, 0x0000c000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>"},
 | |
|       {0xffd00000, 0xe8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTM, "stm<c>.w <Rn>{!} <registers>"},
 | |
|       {0xffd00000, 0xe9000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>"},
 | |
|       {0xfffff800, 0x00006000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>{,#<imm>}]"},
 | |
|       {0xfffff800, 0x00009000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [SP,#<imm>]"},
 | |
|       {0xfff00000, 0xf8c00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRThumb,
 | |
|        "str<c>.w <Rt>, [<Rn>,#<imm12>]"},
 | |
|       {0xfff00800, 0xf8400800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRThumb,
 | |
|        "str<c> <Rt>, [<Rn>,#+/-<imm8>]"},
 | |
|       {0xfffffe00, 0x00005000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> ,{<Rn>, <Rm>]"},
 | |
|       {0xfff00fc0, 0xf8400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRRegister,
 | |
|        "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]"},
 | |
|       {0xfffff800, 0x00007000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTRBThumb,
 | |
|        "strb<c> <Rt>, [<Rn>, #<imm5>]"},
 | |
|       {0xfff00000, 0xf8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRBThumb,
 | |
|        "strb<c>.w <Rt>, [<Rn>, #<imm12>]"},
 | |
|       {0xfff00800, 0xf8000800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRBThumb,
 | |
|        "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}"},
 | |
|       {0xfffffe00, 0x00005200, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,<Rm>]"},
 | |
|       {0xfff00fc0, 0xf8200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRHRegister,
 | |
|        "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"},
 | |
|       {0xfff00000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTREX,
 | |
|        "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]"},
 | |
|       {0xfe500000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSTRDImm,
 | |
|        "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!"},
 | |
|       {0xfe100f00, 0xec000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0xfea00f00, 0xec000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
 | |
|       {0xff300f00, 0xed000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
 | |
|       {0xff300f00, 0xed000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
 | |
|       {0xffb00000, 0xf9000000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVST1Multiple,
 | |
|        "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
|       {0xffb00300, 0xf9800000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32,
 | |
|        &EmulateInstructionARM::EmulateVST1Single,
 | |
|        "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
 | |
| 
 | |
|       // Other instructions
 | |
|       {0xffffffc0, 0x0000b240, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>"},
 | |
|       {0xfffff080, 0xfa4ff080, ARMV6_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSXTB, "sxtb<c>.w <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0xffffffc0, 0x0000b200, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>"},
 | |
|       {0xfffff080, 0xfa0ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateSXTH, "sxth<c>.w <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0xffffffc0, 0x0000b2c0, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>"},
 | |
|       {0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}"},
 | |
|       {0xffffffc0, 0x0000b280, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16,
 | |
|        &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>"},
 | |
|       {0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
 | |
|        &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}"},
 | |
|   };
 | |
| 
 | |
|   const size_t k_num_thumb_opcodes = llvm::array_lengthof(g_thumb_opcodes);
 | |
|   for (size_t i = 0; i < k_num_thumb_opcodes; ++i) {
 | |
|     if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value &&
 | |
|         (g_thumb_opcodes[i].variants & arm_isa) != 0)
 | |
|       return &g_thumb_opcodes[i];
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::SetArchitecture(const ArchSpec &arch) {
 | |
|   m_arch = arch;
 | |
|   m_arm_isa = 0;
 | |
|   const char *arch_cstr = arch.GetArchitectureName();
 | |
|   if (arch_cstr) {
 | |
|     if (0 == ::strcasecmp(arch_cstr, "armv4t"))
 | |
|       m_arm_isa = ARMv4T;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv5tej"))
 | |
|       m_arm_isa = ARMv5TEJ;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv5te"))
 | |
|       m_arm_isa = ARMv5TE;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv5t"))
 | |
|       m_arm_isa = ARMv5T;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv6k"))
 | |
|       m_arm_isa = ARMv6K;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv6t2"))
 | |
|       m_arm_isa = ARMv6T2;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "armv7s"))
 | |
|       m_arm_isa = ARMv7S;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "arm"))
 | |
|       m_arm_isa = ARMvAll;
 | |
|     else if (0 == ::strcasecmp(arch_cstr, "thumb"))
 | |
|       m_arm_isa = ARMvAll;
 | |
|     else if (0 == ::strncasecmp(arch_cstr, "armv4", 5))
 | |
|       m_arm_isa = ARMv4;
 | |
|     else if (0 == ::strncasecmp(arch_cstr, "armv6", 5))
 | |
|       m_arm_isa = ARMv6;
 | |
|     else if (0 == ::strncasecmp(arch_cstr, "armv7", 5))
 | |
|       m_arm_isa = ARMv7;
 | |
|     else if (0 == ::strncasecmp(arch_cstr, "armv8", 5))
 | |
|       m_arm_isa = ARMv8;
 | |
|   }
 | |
|   return m_arm_isa != 0;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::SetInstruction(const Opcode &insn_opcode,
 | |
|                                            const Address &inst_addr,
 | |
|                                            Target *target) {
 | |
|   if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) {
 | |
|     if (m_arch.GetTriple().getArch() == llvm::Triple::thumb ||
 | |
|         m_arch.IsAlwaysThumbInstructions())
 | |
|       m_opcode_mode = eModeThumb;
 | |
|     else {
 | |
|       AddressClass addr_class = inst_addr.GetAddressClass();
 | |
| 
 | |
|       if ((addr_class == AddressClass::eCode) ||
 | |
|           (addr_class == AddressClass::eUnknown))
 | |
|         m_opcode_mode = eModeARM;
 | |
|       else if (addr_class == AddressClass::eCodeAlternateISA)
 | |
|         m_opcode_mode = eModeThumb;
 | |
|       else
 | |
|         return false;
 | |
|     }
 | |
|     if (m_opcode_mode == eModeThumb || m_arch.IsAlwaysThumbInstructions())
 | |
|       m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T;
 | |
|     else
 | |
|       m_opcode_cpsr = CPSR_MODE_USR;
 | |
|     return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::ReadInstruction() {
 | |
|   bool success = false;
 | |
|   m_opcode_cpsr = ReadRegisterUnsigned(eRegisterKindGeneric,
 | |
|                                        LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
 | |
|   if (success) {
 | |
|     addr_t pc =
 | |
|         ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
 | |
|                              LLDB_INVALID_ADDRESS, &success);
 | |
|     if (success) {
 | |
|       Context read_inst_context;
 | |
|       read_inst_context.type = eContextReadOpcode;
 | |
|       read_inst_context.SetNoArgs();
 | |
| 
 | |
|       if ((m_opcode_cpsr & MASK_CPSR_T) || m_arch.IsAlwaysThumbInstructions()) {
 | |
|         m_opcode_mode = eModeThumb;
 | |
|         uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success);
 | |
| 
 | |
|         if (success) {
 | |
|           if ((thumb_opcode & 0xe000) != 0xe000 ||
 | |
|               ((thumb_opcode & 0x1800u) == 0)) {
 | |
|             m_opcode.SetOpcode16(thumb_opcode, GetByteOrder());
 | |
|           } else {
 | |
|             m_opcode.SetOpcode32(
 | |
|                 (thumb_opcode << 16) |
 | |
|                     MemARead(read_inst_context, pc + 2, 2, 0, &success),
 | |
|                 GetByteOrder());
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         m_opcode_mode = eModeARM;
 | |
|         m_opcode.SetOpcode32(MemARead(read_inst_context, pc, 4, 0, &success),
 | |
|                              GetByteOrder());
 | |
|       }
 | |
| 
 | |
|       if (!m_ignore_conditions) {
 | |
|         // If we are not ignoreing the conditions then init the it session from
 | |
|         // the current value of cpsr.
 | |
|         uint32_t it = (Bits32(m_opcode_cpsr, 15, 10) << 2) |
 | |
|                       Bits32(m_opcode_cpsr, 26, 25);
 | |
|         if (it != 0)
 | |
|           m_it_session.InitIT(it);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (!success) {
 | |
|     m_opcode_mode = eModeInvalid;
 | |
|     m_addr = LLDB_INVALID_ADDRESS;
 | |
|   }
 | |
|   return success;
 | |
| }
 | |
| 
 | |
| uint32_t EmulateInstructionARM::ArchVersion() { return m_arm_isa; }
 | |
| 
 | |
| bool EmulateInstructionARM::ConditionPassed(const uint32_t opcode) {
 | |
|   // If we are ignoring conditions, then always return true. this allows us to
 | |
|   // iterate over disassembly code and still emulate an instruction even if we
 | |
|   // don't have all the right bits set in the CPSR register...
 | |
|   if (m_ignore_conditions)
 | |
|     return true;
 | |
| 
 | |
|   const uint32_t cond = CurrentCond(opcode);
 | |
|   if (cond == UINT32_MAX)
 | |
|     return false;
 | |
| 
 | |
|   bool result = false;
 | |
|   switch (UnsignedBits(cond, 3, 1)) {
 | |
|   case 0:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else
 | |
|       result = (m_opcode_cpsr & MASK_CPSR_Z) != 0;
 | |
|     break;
 | |
|   case 1:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else
 | |
|       result = (m_opcode_cpsr & MASK_CPSR_C) != 0;
 | |
|     break;
 | |
|   case 2:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else
 | |
|       result = (m_opcode_cpsr & MASK_CPSR_N) != 0;
 | |
|     break;
 | |
|   case 3:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else
 | |
|       result = (m_opcode_cpsr & MASK_CPSR_V) != 0;
 | |
|     break;
 | |
|   case 4:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else
 | |
|       result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) &&
 | |
|                ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
 | |
|     break;
 | |
|   case 5:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else {
 | |
|       bool n = (m_opcode_cpsr & MASK_CPSR_N);
 | |
|       bool v = (m_opcode_cpsr & MASK_CPSR_V);
 | |
|       result = n == v;
 | |
|     }
 | |
|     break;
 | |
|   case 6:
 | |
|     if (m_opcode_cpsr == 0)
 | |
|       result = true;
 | |
|     else {
 | |
|       bool n = (m_opcode_cpsr & MASK_CPSR_N);
 | |
|       bool v = (m_opcode_cpsr & MASK_CPSR_V);
 | |
|       result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
 | |
|     }
 | |
|     break;
 | |
|   case 7:
 | |
|     // Always execute (cond == 0b1110, or the special 0b1111 which gives
 | |
|     // opcodes different meanings, but always means execution happens.
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   if (cond & 1)
 | |
|     result = !result;
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| uint32_t EmulateInstructionARM::CurrentCond(const uint32_t opcode) {
 | |
|   switch (m_opcode_mode) {
 | |
|   case eModeInvalid:
 | |
|     break;
 | |
| 
 | |
|   case eModeARM:
 | |
|     return UnsignedBits(opcode, 31, 28);
 | |
| 
 | |
|   case eModeThumb:
 | |
|     // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
 | |
|     // 'cond' field of the encoding.
 | |
|     {
 | |
|       const uint32_t byte_size = m_opcode.GetByteSize();
 | |
|       if (byte_size == 2) {
 | |
|         if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 8) != 0x0f)
 | |
|           return Bits32(opcode, 11, 8);
 | |
|       } else if (byte_size == 4) {
 | |
|         if (Bits32(opcode, 31, 27) == 0x1e && Bits32(opcode, 15, 14) == 0x02 &&
 | |
|             Bits32(opcode, 12, 12) == 0x00 && Bits32(opcode, 25, 22) <= 0x0d) {
 | |
|           return Bits32(opcode, 25, 22);
 | |
|         }
 | |
|       } else
 | |
|         // We have an invalid thumb instruction, let's bail out.
 | |
|         break;
 | |
| 
 | |
|       return m_it_session.GetCond();
 | |
|     }
 | |
|   }
 | |
|   return UINT32_MAX; // Return invalid value
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::InITBlock() {
 | |
|   return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock();
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::LastInITBlock() {
 | |
|   return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock();
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::BadMode(uint32_t mode) {
 | |
| 
 | |
|   switch (mode) {
 | |
|   case 16:
 | |
|     return false; // '10000'
 | |
|   case 17:
 | |
|     return false; // '10001'
 | |
|   case 18:
 | |
|     return false; // '10010'
 | |
|   case 19:
 | |
|     return false; // '10011'
 | |
|   case 22:
 | |
|     return false; // '10110'
 | |
|   case 23:
 | |
|     return false; // '10111'
 | |
|   case 27:
 | |
|     return false; // '11011'
 | |
|   case 31:
 | |
|     return false; // '11111'
 | |
|   default:
 | |
|     return true;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::CurrentModeIsPrivileged() {
 | |
|   uint32_t mode = Bits32(m_opcode_cpsr, 4, 0);
 | |
| 
 | |
|   if (BadMode(mode))
 | |
|     return false;
 | |
| 
 | |
|   if (mode == 16)
 | |
|     return false;
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void EmulateInstructionARM::CPSRWriteByInstr(uint32_t value, uint32_t bytemask,
 | |
|                                              bool affect_execstate) {
 | |
|   bool privileged = CurrentModeIsPrivileged();
 | |
| 
 | |
|   uint32_t tmp_cpsr = Bits32(m_opcode_cpsr, 23, 20) << 20;
 | |
| 
 | |
|   if (BitIsSet(bytemask, 3)) {
 | |
|     tmp_cpsr = tmp_cpsr | (Bits32(value, 31, 27) << 27);
 | |
|     if (affect_execstate)
 | |
|       tmp_cpsr = tmp_cpsr | (Bits32(value, 26, 24) << 24);
 | |
|   }
 | |
| 
 | |
|   if (BitIsSet(bytemask, 2)) {
 | |
|     tmp_cpsr = tmp_cpsr | (Bits32(value, 19, 16) << 16);
 | |
|   }
 | |
| 
 | |
|   if (BitIsSet(bytemask, 1)) {
 | |
|     if (affect_execstate)
 | |
|       tmp_cpsr = tmp_cpsr | (Bits32(value, 15, 10) << 10);
 | |
|     tmp_cpsr = tmp_cpsr | (Bit32(value, 9) << 9);
 | |
|     if (privileged)
 | |
|       tmp_cpsr = tmp_cpsr | (Bit32(value, 8) << 8);
 | |
|   }
 | |
| 
 | |
|   if (BitIsSet(bytemask, 0)) {
 | |
|     if (privileged)
 | |
|       tmp_cpsr = tmp_cpsr | (Bits32(value, 7, 6) << 6);
 | |
|     if (affect_execstate)
 | |
|       tmp_cpsr = tmp_cpsr | (Bit32(value, 5) << 5);
 | |
|     if (privileged)
 | |
|       tmp_cpsr = tmp_cpsr | Bits32(value, 4, 0);
 | |
|   }
 | |
| 
 | |
|   m_opcode_cpsr = tmp_cpsr;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::BranchWritePC(const Context &context,
 | |
|                                           uint32_t addr) {
 | |
|   addr_t target;
 | |
| 
 | |
|   // Check the current instruction set.
 | |
|   if (CurrentInstrSet() == eModeARM)
 | |
|     target = addr & 0xfffffffc;
 | |
|   else
 | |
|     target = addr & 0xfffffffe;
 | |
| 
 | |
|   return WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_PC, target);
 | |
| }
 | |
| 
 | |
| // As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by
 | |
| // inspecting addr.
 | |
| bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) {
 | |
|   addr_t target;
 | |
|   // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
 | |
|   // we want to record it and issue a WriteRegister callback so the clients can
 | |
|   // track the mode changes accordingly.
 | |
|   bool cpsr_changed = false;
 | |
| 
 | |
|   if (BitIsSet(addr, 0)) {
 | |
|     if (CurrentInstrSet() != eModeThumb) {
 | |
|       SelectInstrSet(eModeThumb);
 | |
|       cpsr_changed = true;
 | |
|     }
 | |
|     target = addr & 0xfffffffe;
 | |
|     context.SetISA(eModeThumb);
 | |
|   } else if (BitIsClear(addr, 1)) {
 | |
|     if (CurrentInstrSet() != eModeARM) {
 | |
|       SelectInstrSet(eModeARM);
 | |
|       cpsr_changed = true;
 | |
|     }
 | |
|     target = addr & 0xfffffffc;
 | |
|     context.SetISA(eModeARM);
 | |
|   } else
 | |
|     return false; // address<1:0> == '10' => UNPREDICTABLE
 | |
| 
 | |
|   if (cpsr_changed) {
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
 | |
|       return false;
 | |
|   }
 | |
|   return WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_PC, target);
 | |
| }
 | |
| 
 | |
| // Dispatches to either BXWritePC or BranchWritePC based on architecture
 | |
| // versions.
 | |
| bool EmulateInstructionARM::LoadWritePC(Context &context, uint32_t addr) {
 | |
|   if (ArchVersion() >= ARMv5T)
 | |
|     return BXWritePC(context, addr);
 | |
|   else
 | |
|     return BranchWritePC((const Context)context, addr);
 | |
| }
 | |
| 
 | |
| // Dispatches to either BXWritePC or BranchWritePC based on architecture
 | |
| // versions and current instruction set.
 | |
| bool EmulateInstructionARM::ALUWritePC(Context &context, uint32_t addr) {
 | |
|   if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
 | |
|     return BXWritePC(context, addr);
 | |
|   else
 | |
|     return BranchWritePC((const Context)context, addr);
 | |
| }
 | |
| 
 | |
| EmulateInstructionARM::Mode EmulateInstructionARM::CurrentInstrSet() {
 | |
|   return m_opcode_mode;
 | |
| }
 | |
| 
 | |
| // Set the 'T' bit of our CPSR.  The m_opcode_mode gets updated when the next
 | |
| // ReadInstruction() is performed.  This function has a side effect of updating
 | |
| // the m_new_inst_cpsr member variable if necessary.
 | |
| bool EmulateInstructionARM::SelectInstrSet(Mode arm_or_thumb) {
 | |
|   m_new_inst_cpsr = m_opcode_cpsr;
 | |
|   switch (arm_or_thumb) {
 | |
|   default:
 | |
|     return false;
 | |
|   case eModeARM:
 | |
|     // Clear the T bit.
 | |
|     m_new_inst_cpsr &= ~MASK_CPSR_T;
 | |
|     break;
 | |
|   case eModeThumb:
 | |
|     // Set the T bit.
 | |
|     m_new_inst_cpsr |= MASK_CPSR_T;
 | |
|     break;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This function returns TRUE if the processor currently provides support for
 | |
| // unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
 | |
| // controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
 | |
| bool EmulateInstructionARM::UnalignedSupport() {
 | |
|   return (ArchVersion() >= ARMv7);
 | |
| }
 | |
| 
 | |
| // The main addition and subtraction instructions can produce status
 | |
| // information about both unsigned carry and signed overflow conditions.  This
 | |
| // status information can be used to synthesize multi-word additions and
 | |
| // subtractions.
 | |
| EmulateInstructionARM::AddWithCarryResult
 | |
| EmulateInstructionARM::AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in) {
 | |
|   uint32_t result;
 | |
|   uint8_t carry_out;
 | |
|   uint8_t overflow;
 | |
| 
 | |
|   uint64_t unsigned_sum = x + y + carry_in;
 | |
|   int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
 | |
| 
 | |
|   result = UnsignedBits(unsigned_sum, 31, 0);
 | |
|   //    carry_out = (result == unsigned_sum ? 0 : 1);
 | |
|   overflow = ((int32_t)result == signed_sum ? 0 : 1);
 | |
| 
 | |
|   if (carry_in)
 | |
|     carry_out = ((int32_t)x >= (int32_t)(~y)) ? 1 : 0;
 | |
|   else
 | |
|     carry_out = ((int32_t)x > (int32_t)y) ? 1 : 0;
 | |
| 
 | |
|   AddWithCarryResult res = {result, carry_out, overflow};
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| uint32_t EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) {
 | |
|   lldb::RegisterKind reg_kind;
 | |
|   uint32_t reg_num;
 | |
|   switch (num) {
 | |
|   case SP_REG:
 | |
|     reg_kind = eRegisterKindGeneric;
 | |
|     reg_num = LLDB_REGNUM_GENERIC_SP;
 | |
|     break;
 | |
|   case LR_REG:
 | |
|     reg_kind = eRegisterKindGeneric;
 | |
|     reg_num = LLDB_REGNUM_GENERIC_RA;
 | |
|     break;
 | |
|   case PC_REG:
 | |
|     reg_kind = eRegisterKindGeneric;
 | |
|     reg_num = LLDB_REGNUM_GENERIC_PC;
 | |
|     break;
 | |
|   default:
 | |
|     if (num < SP_REG) {
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_r0 + num;
 | |
|     } else {
 | |
|       // assert(0 && "Invalid register number");
 | |
|       *success = false;
 | |
|       return UINT32_MAX;
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   // Read our register.
 | |
|   uint32_t val = ReadRegisterUnsigned(reg_kind, reg_num, 0, success);
 | |
| 
 | |
|   // When executing an ARM instruction , PC reads as the address of the current
 | |
|   // instruction plus 8. When executing a Thumb instruction , PC reads as the
 | |
|   // address of the current instruction plus 4.
 | |
|   if (num == 15) {
 | |
|     if (CurrentInstrSet() == eModeARM)
 | |
|       val += 8;
 | |
|     else
 | |
|       val += 4;
 | |
|   }
 | |
| 
 | |
|   return val;
 | |
| }
 | |
| 
 | |
| // Write the result to the ARM core register Rd, and optionally update the
 | |
| // condition flags based on the result.
 | |
| //
 | |
| // This helper method tries to encapsulate the following pseudocode from the
 | |
| // ARM Architecture Reference Manual:
 | |
| //
 | |
| // if d == 15 then         // Can only occur for encoding A1
 | |
| //     ALUWritePC(result); // setflags is always FALSE here
 | |
| // else
 | |
| //     R[d] = result;
 | |
| //     if setflags then
 | |
| //         APSR.N = result<31>;
 | |
| //         APSR.Z = IsZeroBit(result);
 | |
| //         APSR.C = carry;
 | |
| //         // APSR.V unchanged
 | |
| //
 | |
| // In the above case, the API client does not pass in the overflow arg, which
 | |
| // defaults to ~0u.
 | |
| bool EmulateInstructionARM::WriteCoreRegOptionalFlags(
 | |
|     Context &context, const uint32_t result, const uint32_t Rd, bool setflags,
 | |
|     const uint32_t carry, const uint32_t overflow) {
 | |
|   if (Rd == 15) {
 | |
|     if (!ALUWritePC(context, result))
 | |
|       return false;
 | |
|   } else {
 | |
|     lldb::RegisterKind reg_kind;
 | |
|     uint32_t reg_num;
 | |
|     switch (Rd) {
 | |
|     case SP_REG:
 | |
|       reg_kind = eRegisterKindGeneric;
 | |
|       reg_num = LLDB_REGNUM_GENERIC_SP;
 | |
|       break;
 | |
|     case LR_REG:
 | |
|       reg_kind = eRegisterKindGeneric;
 | |
|       reg_num = LLDB_REGNUM_GENERIC_RA;
 | |
|       break;
 | |
|     default:
 | |
|       reg_kind = eRegisterKindDWARF;
 | |
|       reg_num = dwarf_r0 + Rd;
 | |
|     }
 | |
|     if (!WriteRegisterUnsigned(context, reg_kind, reg_num, result))
 | |
|       return false;
 | |
|     if (setflags)
 | |
|       return WriteFlags(context, result, carry, overflow);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This helper method tries to encapsulate the following pseudocode from the
 | |
| // ARM Architecture Reference Manual:
 | |
| //
 | |
| // APSR.N = result<31>;
 | |
| // APSR.Z = IsZeroBit(result);
 | |
| // APSR.C = carry;
 | |
| // APSR.V = overflow
 | |
| //
 | |
| // Default arguments can be specified for carry and overflow parameters, which
 | |
| // means not to update the respective flags.
 | |
| bool EmulateInstructionARM::WriteFlags(Context &context, const uint32_t result,
 | |
|                                        const uint32_t carry,
 | |
|                                        const uint32_t overflow) {
 | |
|   m_new_inst_cpsr = m_opcode_cpsr;
 | |
|   SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS));
 | |
|   SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
 | |
|   if (carry != ~0u)
 | |
|     SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry);
 | |
|   if (overflow != ~0u)
 | |
|     SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow);
 | |
|   if (m_new_inst_cpsr != m_opcode_cpsr) {
 | |
|     if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
 | |
|                                LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) {
 | |
|   ARMOpcode *opcode_data = nullptr;
 | |
| 
 | |
|   if (m_opcode_mode == eModeThumb)
 | |
|     opcode_data =
 | |
|         GetThumbOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa);
 | |
|   else if (m_opcode_mode == eModeARM)
 | |
|     opcode_data = GetARMOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa);
 | |
| 
 | |
|   const bool auto_advance_pc =
 | |
|       evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
 | |
|   m_ignore_conditions =
 | |
|       evaluate_options & eEmulateInstructionOptionIgnoreConditions;
 | |
| 
 | |
|   bool success = false;
 | |
|   if (m_opcode_cpsr == 0 || !m_ignore_conditions) {
 | |
|     m_opcode_cpsr =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success);
 | |
|   }
 | |
| 
 | |
|   // Only return false if we are unable to read the CPSR if we care about
 | |
|   // conditions
 | |
|   if (!success && !m_ignore_conditions)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t orig_pc_value = 0;
 | |
|   if (auto_advance_pc) {
 | |
|     orig_pc_value =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   // Call the Emulate... function if we managed to decode the opcode.
 | |
|   if (opcode_data) {
 | |
|     success = (this->*opcode_data->callback)(m_opcode.GetOpcode32(),
 | |
|                                              opcode_data->encoding);
 | |
|     if (!success)
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   // Advance the ITSTATE bits to their values for the next instruction if we
 | |
|   // haven't just executed an IT instruction what initialized it.
 | |
|   if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() &&
 | |
|       (opcode_data == nullptr ||
 | |
|        opcode_data->callback != &EmulateInstructionARM::EmulateIT))
 | |
|     m_it_session.ITAdvance();
 | |
| 
 | |
|   if (auto_advance_pc) {
 | |
|     uint32_t after_pc_value =
 | |
|         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc, 0, &success);
 | |
|     if (!success)
 | |
|       return false;
 | |
| 
 | |
|     if (after_pc_value == orig_pc_value) {
 | |
|       after_pc_value += m_opcode.GetByteSize();
 | |
| 
 | |
|       EmulateInstruction::Context context;
 | |
|       context.type = eContextAdvancePC;
 | |
|       context.SetNoArgs();
 | |
|       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc,
 | |
|                                  after_pc_value))
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| EmulateInstruction::InstructionCondition
 | |
| EmulateInstructionARM::GetInstructionCondition() {
 | |
|   const uint32_t cond = CurrentCond(m_opcode.GetOpcode32());
 | |
|   if (cond == 0xe || cond == 0xf || cond == UINT32_MAX)
 | |
|     return EmulateInstruction::UnconditionalCondition;
 | |
|   return cond;
 | |
| }
 | |
| 
 | |
| bool EmulateInstructionARM::TestEmulation(Stream *out_stream, ArchSpec &arch,
 | |
|                                           OptionValueDictionary *test_data) {
 | |
|   if (!test_data) {
 | |
|     out_stream->Printf("TestEmulation: Missing test data.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   static ConstString opcode_key("opcode");
 | |
|   static ConstString before_key("before_state");
 | |
|   static ConstString after_key("after_state");
 | |
| 
 | |
|   OptionValueSP value_sp = test_data->GetValueForKey(opcode_key);
 | |
| 
 | |
|   uint32_t test_opcode;
 | |
|   if ((value_sp.get() == nullptr) ||
 | |
|       (value_sp->GetType() != OptionValue::eTypeUInt64)) {
 | |
|     out_stream->Printf("TestEmulation: Error reading opcode from test file.\n");
 | |
|     return false;
 | |
|   }
 | |
|   test_opcode = value_sp->GetUInt64Value();
 | |
| 
 | |
|   if (arch.GetTriple().getArch() == llvm::Triple::thumb ||
 | |
|       arch.IsAlwaysThumbInstructions()) {
 | |
|     m_opcode_mode = eModeThumb;
 | |
|     if (test_opcode < 0x10000)
 | |
|       m_opcode.SetOpcode16(test_opcode, endian::InlHostByteOrder());
 | |
|     else
 | |
|       m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder());
 | |
|   } else if (arch.GetTriple().getArch() == llvm::Triple::arm) {
 | |
|     m_opcode_mode = eModeARM;
 | |
|     m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder());
 | |
|   } else {
 | |
|     out_stream->Printf("TestEmulation:  Invalid arch.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   EmulationStateARM before_state;
 | |
|   EmulationStateARM after_state;
 | |
| 
 | |
|   value_sp = test_data->GetValueForKey(before_key);
 | |
|   if ((value_sp.get() == nullptr) ||
 | |
|       (value_sp->GetType() != OptionValue::eTypeDictionary)) {
 | |
|     out_stream->Printf("TestEmulation:  Failed to find 'before' state.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary();
 | |
|   if (!before_state.LoadStateFromDictionary(state_dictionary)) {
 | |
|     out_stream->Printf("TestEmulation:  Failed loading 'before' state.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   value_sp = test_data->GetValueForKey(after_key);
 | |
|   if ((value_sp.get() == nullptr) ||
 | |
|       (value_sp->GetType() != OptionValue::eTypeDictionary)) {
 | |
|     out_stream->Printf("TestEmulation:  Failed to find 'after' state.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   state_dictionary = value_sp->GetAsDictionary();
 | |
|   if (!after_state.LoadStateFromDictionary(state_dictionary)) {
 | |
|     out_stream->Printf("TestEmulation: Failed loading 'after' state.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   SetBaton((void *)&before_state);
 | |
|   SetCallbacks(&EmulationStateARM::ReadPseudoMemory,
 | |
|                &EmulationStateARM::WritePseudoMemory,
 | |
|                &EmulationStateARM::ReadPseudoRegister,
 | |
|                &EmulationStateARM::WritePseudoRegister);
 | |
| 
 | |
|   bool success = EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
 | |
|   if (!success) {
 | |
|     out_stream->Printf("TestEmulation:  EvaluateInstruction() failed.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   success = before_state.CompareState(after_state);
 | |
|   if (!success)
 | |
|     out_stream->Printf(
 | |
|         "TestEmulation:  'before' and 'after' states do not match.\n");
 | |
| 
 | |
|   return success;
 | |
| }
 | |
| //
 | |
| //
 | |
| // const char *
 | |
| // EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num)
 | |
| //{
 | |
| //    if (reg_kind == eRegisterKindGeneric)
 | |
| //    {
 | |
| //        switch (reg_num)
 | |
| //        {
 | |
| //        case LLDB_REGNUM_GENERIC_PC:    return "pc";
 | |
| //        case LLDB_REGNUM_GENERIC_SP:    return "sp";
 | |
| //        case LLDB_REGNUM_GENERIC_FP:    return "fp";
 | |
| //        case LLDB_REGNUM_GENERIC_RA:    return "lr";
 | |
| //        case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr";
 | |
| //        default: return NULL;
 | |
| //        }
 | |
| //    }
 | |
| //    else if (reg_kind == eRegisterKindDWARF)
 | |
| //    {
 | |
| //        return GetARMDWARFRegisterName (reg_num);
 | |
| //    }
 | |
| //    return NULL;
 | |
| //}
 | |
| //
 | |
| bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
 | |
|   unwind_plan.Clear();
 | |
|   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
 | |
| 
 | |
|   UnwindPlan::RowSP row(new UnwindPlan::Row);
 | |
| 
 | |
|   // Our previous Call Frame Address is the stack pointer
 | |
|   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp, 0);
 | |
| 
 | |
|   unwind_plan.AppendRow(row);
 | |
|   unwind_plan.SetSourceName("EmulateInstructionARM");
 | |
|   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
 | |
|   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
 | |
|   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
 | |
|   unwind_plan.SetReturnAddressRegister(dwarf_lr);
 | |
|   return true;
 | |
| }
 |