15ffd83dbSDimitry Andric //===-- EmulateInstructionMIPS.cpp ----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "EmulateInstructionMIPS.h"
100b57cec5SDimitry Andric
11fe6060f1SDimitry Andric #include <cstdlib>
12bdd1243dSDimitry Andric #include <optional>
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "lldb/Core/Address.h"
150b57cec5SDimitry Andric #include "lldb/Core/Opcode.h"
160b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
170b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
180b57cec5SDimitry Andric #include "lldb/Target/Target.h"
190b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h"
200b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h"
210b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
220b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
230b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
240b57cec5SDimitry Andric #include "llvm-c/Disassembler.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h"
280b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
290b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
310b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
32480093f4SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
33349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
340b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric #include "Plugins/Process/Utility/InstructionUtils.h"
390b57cec5SDimitry Andric #include "Plugins/Process/Utility/RegisterContext_mips.h"
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric using namespace lldb;
420b57cec5SDimitry Andric using namespace lldb_private;
430b57cec5SDimitry Andric
LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS,InstructionMIPS)445ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS, InstructionMIPS)
455ffd83dbSDimitry Andric
460b57cec5SDimitry Andric #define UInt(x) ((uint64_t)x)
470b57cec5SDimitry Andric #define integer int64_t
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric //
500b57cec5SDimitry Andric // EmulateInstructionMIPS implementation
510b57cec5SDimitry Andric //
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric #ifdef __mips__
540b57cec5SDimitry Andric extern "C" {
550b57cec5SDimitry Andric void LLVMInitializeMipsTargetInfo();
560b57cec5SDimitry Andric void LLVMInitializeMipsTarget();
570b57cec5SDimitry Andric void LLVMInitializeMipsAsmPrinter();
580b57cec5SDimitry Andric void LLVMInitializeMipsTargetMC();
590b57cec5SDimitry Andric void LLVMInitializeMipsDisassembler();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric #endif
620b57cec5SDimitry Andric
EmulateInstructionMIPS(const lldb_private::ArchSpec & arch)630b57cec5SDimitry Andric EmulateInstructionMIPS::EmulateInstructionMIPS(
640b57cec5SDimitry Andric const lldb_private::ArchSpec &arch)
650b57cec5SDimitry Andric : EmulateInstruction(arch) {
660b57cec5SDimitry Andric /* Create instance of llvm::MCDisassembler */
670b57cec5SDimitry Andric std::string Status;
680b57cec5SDimitry Andric llvm::Triple triple = arch.GetTriple();
690b57cec5SDimitry Andric const llvm::Target *target =
700b57cec5SDimitry Andric llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric /*
730b57cec5SDimitry Andric * If we fail to get the target then we haven't registered it. The
740b57cec5SDimitry Andric * SystemInitializerCommon
750b57cec5SDimitry Andric * does not initialize targets, MCs and disassemblers. However we need the
760b57cec5SDimitry Andric * MCDisassembler
770b57cec5SDimitry Andric * to decode the instructions so that the decoding complexity stays with LLVM.
780b57cec5SDimitry Andric * Initialize the MIPS targets and disassemblers.
790b57cec5SDimitry Andric */
800b57cec5SDimitry Andric #ifdef __mips__
810b57cec5SDimitry Andric if (!target) {
820b57cec5SDimitry Andric LLVMInitializeMipsTargetInfo();
830b57cec5SDimitry Andric LLVMInitializeMipsTarget();
840b57cec5SDimitry Andric LLVMInitializeMipsAsmPrinter();
850b57cec5SDimitry Andric LLVMInitializeMipsTargetMC();
860b57cec5SDimitry Andric LLVMInitializeMipsDisassembler();
870b57cec5SDimitry Andric target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric #endif
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric assert(target);
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric llvm::StringRef cpu;
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric switch (arch.GetCore()) {
960b57cec5SDimitry Andric case ArchSpec::eCore_mips32:
970b57cec5SDimitry Andric case ArchSpec::eCore_mips32el:
980b57cec5SDimitry Andric cpu = "mips32";
990b57cec5SDimitry Andric break;
1000b57cec5SDimitry Andric case ArchSpec::eCore_mips32r2:
1010b57cec5SDimitry Andric case ArchSpec::eCore_mips32r2el:
1020b57cec5SDimitry Andric cpu = "mips32r2";
1030b57cec5SDimitry Andric break;
1040b57cec5SDimitry Andric case ArchSpec::eCore_mips32r3:
1050b57cec5SDimitry Andric case ArchSpec::eCore_mips32r3el:
1060b57cec5SDimitry Andric cpu = "mips32r3";
1070b57cec5SDimitry Andric break;
1080b57cec5SDimitry Andric case ArchSpec::eCore_mips32r5:
1090b57cec5SDimitry Andric case ArchSpec::eCore_mips32r5el:
1100b57cec5SDimitry Andric cpu = "mips32r5";
1110b57cec5SDimitry Andric break;
1120b57cec5SDimitry Andric case ArchSpec::eCore_mips32r6:
1130b57cec5SDimitry Andric case ArchSpec::eCore_mips32r6el:
1140b57cec5SDimitry Andric cpu = "mips32r6";
1150b57cec5SDimitry Andric break;
1160b57cec5SDimitry Andric case ArchSpec::eCore_mips64:
1170b57cec5SDimitry Andric case ArchSpec::eCore_mips64el:
1180b57cec5SDimitry Andric cpu = "mips64";
1190b57cec5SDimitry Andric break;
1200b57cec5SDimitry Andric case ArchSpec::eCore_mips64r2:
1210b57cec5SDimitry Andric case ArchSpec::eCore_mips64r2el:
1220b57cec5SDimitry Andric cpu = "mips64r2";
1230b57cec5SDimitry Andric break;
1240b57cec5SDimitry Andric case ArchSpec::eCore_mips64r3:
1250b57cec5SDimitry Andric case ArchSpec::eCore_mips64r3el:
1260b57cec5SDimitry Andric cpu = "mips64r3";
1270b57cec5SDimitry Andric break;
1280b57cec5SDimitry Andric case ArchSpec::eCore_mips64r5:
1290b57cec5SDimitry Andric case ArchSpec::eCore_mips64r5el:
1300b57cec5SDimitry Andric cpu = "mips64r5";
1310b57cec5SDimitry Andric break;
1320b57cec5SDimitry Andric case ArchSpec::eCore_mips64r6:
1330b57cec5SDimitry Andric case ArchSpec::eCore_mips64r6el:
1340b57cec5SDimitry Andric cpu = "mips64r6";
1350b57cec5SDimitry Andric break;
1360b57cec5SDimitry Andric default:
1370b57cec5SDimitry Andric cpu = "generic";
1380b57cec5SDimitry Andric break;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
14104eeddc0SDimitry Andric std::string features;
1420b57cec5SDimitry Andric uint32_t arch_flags = arch.GetFlags();
1430b57cec5SDimitry Andric if (arch_flags & ArchSpec::eMIPSAse_msa)
1440b57cec5SDimitry Andric features += "+msa,";
1450b57cec5SDimitry Andric if (arch_flags & ArchSpec::eMIPSAse_dsp)
1460b57cec5SDimitry Andric features += "+dsp,";
1470b57cec5SDimitry Andric if (arch_flags & ArchSpec::eMIPSAse_dspr2)
1480b57cec5SDimitry Andric features += "+dspr2,";
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric m_reg_info.reset(target->createMCRegInfo(triple.getTriple()));
1510b57cec5SDimitry Andric assert(m_reg_info.get());
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric m_insn_info.reset(target->createMCInstrInfo());
1540b57cec5SDimitry Andric assert(m_insn_info.get());
1550b57cec5SDimitry Andric
156480093f4SDimitry Andric llvm::MCTargetOptions MCOptions;
157480093f4SDimitry Andric m_asm_info.reset(
158480093f4SDimitry Andric target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions));
1590b57cec5SDimitry Andric m_subtype_info.reset(
1600b57cec5SDimitry Andric target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
1610b57cec5SDimitry Andric assert(m_asm_info.get() && m_subtype_info.get());
1620b57cec5SDimitry Andric
163fe6060f1SDimitry Andric m_context = std::make_unique<llvm::MCContext>(
164fe6060f1SDimitry Andric triple, m_asm_info.get(), m_reg_info.get(), m_subtype_info.get());
1650b57cec5SDimitry Andric assert(m_context.get());
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context));
1680b57cec5SDimitry Andric assert(m_disasm.get());
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric /* Create alternate disassembler for microMIPS */
1710b57cec5SDimitry Andric if (arch_flags & ArchSpec::eMIPSAse_mips16)
1720b57cec5SDimitry Andric features += "+mips16,";
1730b57cec5SDimitry Andric else if (arch_flags & ArchSpec::eMIPSAse_micromips)
1740b57cec5SDimitry Andric features += "+micromips,";
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric m_alt_subtype_info.reset(
1770b57cec5SDimitry Andric target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
1780b57cec5SDimitry Andric assert(m_alt_subtype_info.get());
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric m_alt_disasm.reset(
1810b57cec5SDimitry Andric target->createMCDisassembler(*m_alt_subtype_info, *m_context));
1820b57cec5SDimitry Andric assert(m_alt_disasm.get());
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric m_next_inst_size = 0;
1850b57cec5SDimitry Andric m_use_alt_disaasm = false;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
Initialize()1880b57cec5SDimitry Andric void EmulateInstructionMIPS::Initialize() {
1890b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
1900b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance);
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
Terminate()1930b57cec5SDimitry Andric void EmulateInstructionMIPS::Terminate() {
1940b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
GetPluginDescriptionStatic()197349cc55cSDimitry Andric llvm::StringRef EmulateInstructionMIPS::GetPluginDescriptionStatic() {
1980b57cec5SDimitry Andric return "Emulate instructions for the MIPS32 architecture.";
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric EmulateInstruction *
CreateInstance(const ArchSpec & arch,InstructionType inst_type)2020b57cec5SDimitry Andric EmulateInstructionMIPS::CreateInstance(const ArchSpec &arch,
2030b57cec5SDimitry Andric InstructionType inst_type) {
2040b57cec5SDimitry Andric if (EmulateInstructionMIPS::SupportsEmulatingInstructionsOfTypeStatic(
2050b57cec5SDimitry Andric inst_type)) {
2060b57cec5SDimitry Andric if (arch.GetTriple().getArch() == llvm::Triple::mips ||
2070b57cec5SDimitry Andric arch.GetTriple().getArch() == llvm::Triple::mipsel) {
2080b57cec5SDimitry Andric return new EmulateInstructionMIPS(arch);
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric return nullptr;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric
SetTargetTriple(const ArchSpec & arch)2150b57cec5SDimitry Andric bool EmulateInstructionMIPS::SetTargetTriple(const ArchSpec &arch) {
2160b57cec5SDimitry Andric return arch.GetTriple().getArch() == llvm::Triple::mips ||
2170b57cec5SDimitry Andric arch.GetTriple().getArch() == llvm::Triple::mipsel;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric
GetRegisterName(unsigned reg_num,bool alternate_name)2200b57cec5SDimitry Andric const char *EmulateInstructionMIPS::GetRegisterName(unsigned reg_num,
2210b57cec5SDimitry Andric bool alternate_name) {
2220b57cec5SDimitry Andric if (alternate_name) {
2230b57cec5SDimitry Andric switch (reg_num) {
2240b57cec5SDimitry Andric case dwarf_sp_mips:
2250b57cec5SDimitry Andric return "r29";
2260b57cec5SDimitry Andric case dwarf_r30_mips:
2270b57cec5SDimitry Andric return "r30";
2280b57cec5SDimitry Andric case dwarf_ra_mips:
2290b57cec5SDimitry Andric return "r31";
2300b57cec5SDimitry Andric case dwarf_f0_mips:
2310b57cec5SDimitry Andric return "f0";
2320b57cec5SDimitry Andric case dwarf_f1_mips:
2330b57cec5SDimitry Andric return "f1";
2340b57cec5SDimitry Andric case dwarf_f2_mips:
2350b57cec5SDimitry Andric return "f2";
2360b57cec5SDimitry Andric case dwarf_f3_mips:
2370b57cec5SDimitry Andric return "f3";
2380b57cec5SDimitry Andric case dwarf_f4_mips:
2390b57cec5SDimitry Andric return "f4";
2400b57cec5SDimitry Andric case dwarf_f5_mips:
2410b57cec5SDimitry Andric return "f5";
2420b57cec5SDimitry Andric case dwarf_f6_mips:
2430b57cec5SDimitry Andric return "f6";
2440b57cec5SDimitry Andric case dwarf_f7_mips:
2450b57cec5SDimitry Andric return "f7";
2460b57cec5SDimitry Andric case dwarf_f8_mips:
2470b57cec5SDimitry Andric return "f8";
2480b57cec5SDimitry Andric case dwarf_f9_mips:
2490b57cec5SDimitry Andric return "f9";
2500b57cec5SDimitry Andric case dwarf_f10_mips:
2510b57cec5SDimitry Andric return "f10";
2520b57cec5SDimitry Andric case dwarf_f11_mips:
2530b57cec5SDimitry Andric return "f11";
2540b57cec5SDimitry Andric case dwarf_f12_mips:
2550b57cec5SDimitry Andric return "f12";
2560b57cec5SDimitry Andric case dwarf_f13_mips:
2570b57cec5SDimitry Andric return "f13";
2580b57cec5SDimitry Andric case dwarf_f14_mips:
2590b57cec5SDimitry Andric return "f14";
2600b57cec5SDimitry Andric case dwarf_f15_mips:
2610b57cec5SDimitry Andric return "f15";
2620b57cec5SDimitry Andric case dwarf_f16_mips:
2630b57cec5SDimitry Andric return "f16";
2640b57cec5SDimitry Andric case dwarf_f17_mips:
2650b57cec5SDimitry Andric return "f17";
2660b57cec5SDimitry Andric case dwarf_f18_mips:
2670b57cec5SDimitry Andric return "f18";
2680b57cec5SDimitry Andric case dwarf_f19_mips:
2690b57cec5SDimitry Andric return "f19";
2700b57cec5SDimitry Andric case dwarf_f20_mips:
2710b57cec5SDimitry Andric return "f20";
2720b57cec5SDimitry Andric case dwarf_f21_mips:
2730b57cec5SDimitry Andric return "f21";
2740b57cec5SDimitry Andric case dwarf_f22_mips:
2750b57cec5SDimitry Andric return "f22";
2760b57cec5SDimitry Andric case dwarf_f23_mips:
2770b57cec5SDimitry Andric return "f23";
2780b57cec5SDimitry Andric case dwarf_f24_mips:
2790b57cec5SDimitry Andric return "f24";
2800b57cec5SDimitry Andric case dwarf_f25_mips:
2810b57cec5SDimitry Andric return "f25";
2820b57cec5SDimitry Andric case dwarf_f26_mips:
2830b57cec5SDimitry Andric return "f26";
2840b57cec5SDimitry Andric case dwarf_f27_mips:
2850b57cec5SDimitry Andric return "f27";
2860b57cec5SDimitry Andric case dwarf_f28_mips:
2870b57cec5SDimitry Andric return "f28";
2880b57cec5SDimitry Andric case dwarf_f29_mips:
2890b57cec5SDimitry Andric return "f29";
2900b57cec5SDimitry Andric case dwarf_f30_mips:
2910b57cec5SDimitry Andric return "f30";
2920b57cec5SDimitry Andric case dwarf_f31_mips:
2930b57cec5SDimitry Andric return "f31";
2940b57cec5SDimitry Andric case dwarf_w0_mips:
2950b57cec5SDimitry Andric return "w0";
2960b57cec5SDimitry Andric case dwarf_w1_mips:
2970b57cec5SDimitry Andric return "w1";
2980b57cec5SDimitry Andric case dwarf_w2_mips:
2990b57cec5SDimitry Andric return "w2";
3000b57cec5SDimitry Andric case dwarf_w3_mips:
3010b57cec5SDimitry Andric return "w3";
3020b57cec5SDimitry Andric case dwarf_w4_mips:
3030b57cec5SDimitry Andric return "w4";
3040b57cec5SDimitry Andric case dwarf_w5_mips:
3050b57cec5SDimitry Andric return "w5";
3060b57cec5SDimitry Andric case dwarf_w6_mips:
3070b57cec5SDimitry Andric return "w6";
3080b57cec5SDimitry Andric case dwarf_w7_mips:
3090b57cec5SDimitry Andric return "w7";
3100b57cec5SDimitry Andric case dwarf_w8_mips:
3110b57cec5SDimitry Andric return "w8";
3120b57cec5SDimitry Andric case dwarf_w9_mips:
3130b57cec5SDimitry Andric return "w9";
3140b57cec5SDimitry Andric case dwarf_w10_mips:
3150b57cec5SDimitry Andric return "w10";
3160b57cec5SDimitry Andric case dwarf_w11_mips:
3170b57cec5SDimitry Andric return "w11";
3180b57cec5SDimitry Andric case dwarf_w12_mips:
3190b57cec5SDimitry Andric return "w12";
3200b57cec5SDimitry Andric case dwarf_w13_mips:
3210b57cec5SDimitry Andric return "w13";
3220b57cec5SDimitry Andric case dwarf_w14_mips:
3230b57cec5SDimitry Andric return "w14";
3240b57cec5SDimitry Andric case dwarf_w15_mips:
3250b57cec5SDimitry Andric return "w15";
3260b57cec5SDimitry Andric case dwarf_w16_mips:
3270b57cec5SDimitry Andric return "w16";
3280b57cec5SDimitry Andric case dwarf_w17_mips:
3290b57cec5SDimitry Andric return "w17";
3300b57cec5SDimitry Andric case dwarf_w18_mips:
3310b57cec5SDimitry Andric return "w18";
3320b57cec5SDimitry Andric case dwarf_w19_mips:
3330b57cec5SDimitry Andric return "w19";
3340b57cec5SDimitry Andric case dwarf_w20_mips:
3350b57cec5SDimitry Andric return "w20";
3360b57cec5SDimitry Andric case dwarf_w21_mips:
3370b57cec5SDimitry Andric return "w21";
3380b57cec5SDimitry Andric case dwarf_w22_mips:
3390b57cec5SDimitry Andric return "w22";
3400b57cec5SDimitry Andric case dwarf_w23_mips:
3410b57cec5SDimitry Andric return "w23";
3420b57cec5SDimitry Andric case dwarf_w24_mips:
3430b57cec5SDimitry Andric return "w24";
3440b57cec5SDimitry Andric case dwarf_w25_mips:
3450b57cec5SDimitry Andric return "w25";
3460b57cec5SDimitry Andric case dwarf_w26_mips:
3470b57cec5SDimitry Andric return "w26";
3480b57cec5SDimitry Andric case dwarf_w27_mips:
3490b57cec5SDimitry Andric return "w27";
3500b57cec5SDimitry Andric case dwarf_w28_mips:
3510b57cec5SDimitry Andric return "w28";
3520b57cec5SDimitry Andric case dwarf_w29_mips:
3530b57cec5SDimitry Andric return "w29";
3540b57cec5SDimitry Andric case dwarf_w30_mips:
3550b57cec5SDimitry Andric return "w30";
3560b57cec5SDimitry Andric case dwarf_w31_mips:
3570b57cec5SDimitry Andric return "w31";
3580b57cec5SDimitry Andric case dwarf_mir_mips:
3590b57cec5SDimitry Andric return "mir";
3600b57cec5SDimitry Andric case dwarf_mcsr_mips:
3610b57cec5SDimitry Andric return "mcsr";
3620b57cec5SDimitry Andric case dwarf_config5_mips:
3630b57cec5SDimitry Andric return "config5";
3640b57cec5SDimitry Andric default:
3650b57cec5SDimitry Andric break;
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric return nullptr;
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric
3700b57cec5SDimitry Andric switch (reg_num) {
3710b57cec5SDimitry Andric case dwarf_zero_mips:
3720b57cec5SDimitry Andric return "r0";
3730b57cec5SDimitry Andric case dwarf_r1_mips:
3740b57cec5SDimitry Andric return "r1";
3750b57cec5SDimitry Andric case dwarf_r2_mips:
3760b57cec5SDimitry Andric return "r2";
3770b57cec5SDimitry Andric case dwarf_r3_mips:
3780b57cec5SDimitry Andric return "r3";
3790b57cec5SDimitry Andric case dwarf_r4_mips:
3800b57cec5SDimitry Andric return "r4";
3810b57cec5SDimitry Andric case dwarf_r5_mips:
3820b57cec5SDimitry Andric return "r5";
3830b57cec5SDimitry Andric case dwarf_r6_mips:
3840b57cec5SDimitry Andric return "r6";
3850b57cec5SDimitry Andric case dwarf_r7_mips:
3860b57cec5SDimitry Andric return "r7";
3870b57cec5SDimitry Andric case dwarf_r8_mips:
3880b57cec5SDimitry Andric return "r8";
3890b57cec5SDimitry Andric case dwarf_r9_mips:
3900b57cec5SDimitry Andric return "r9";
3910b57cec5SDimitry Andric case dwarf_r10_mips:
3920b57cec5SDimitry Andric return "r10";
3930b57cec5SDimitry Andric case dwarf_r11_mips:
3940b57cec5SDimitry Andric return "r11";
3950b57cec5SDimitry Andric case dwarf_r12_mips:
3960b57cec5SDimitry Andric return "r12";
3970b57cec5SDimitry Andric case dwarf_r13_mips:
3980b57cec5SDimitry Andric return "r13";
3990b57cec5SDimitry Andric case dwarf_r14_mips:
4000b57cec5SDimitry Andric return "r14";
4010b57cec5SDimitry Andric case dwarf_r15_mips:
4020b57cec5SDimitry Andric return "r15";
4030b57cec5SDimitry Andric case dwarf_r16_mips:
4040b57cec5SDimitry Andric return "r16";
4050b57cec5SDimitry Andric case dwarf_r17_mips:
4060b57cec5SDimitry Andric return "r17";
4070b57cec5SDimitry Andric case dwarf_r18_mips:
4080b57cec5SDimitry Andric return "r18";
4090b57cec5SDimitry Andric case dwarf_r19_mips:
4100b57cec5SDimitry Andric return "r19";
4110b57cec5SDimitry Andric case dwarf_r20_mips:
4120b57cec5SDimitry Andric return "r20";
4130b57cec5SDimitry Andric case dwarf_r21_mips:
4140b57cec5SDimitry Andric return "r21";
4150b57cec5SDimitry Andric case dwarf_r22_mips:
4160b57cec5SDimitry Andric return "r22";
4170b57cec5SDimitry Andric case dwarf_r23_mips:
4180b57cec5SDimitry Andric return "r23";
4190b57cec5SDimitry Andric case dwarf_r24_mips:
4200b57cec5SDimitry Andric return "r24";
4210b57cec5SDimitry Andric case dwarf_r25_mips:
4220b57cec5SDimitry Andric return "r25";
4230b57cec5SDimitry Andric case dwarf_r26_mips:
4240b57cec5SDimitry Andric return "r26";
4250b57cec5SDimitry Andric case dwarf_r27_mips:
4260b57cec5SDimitry Andric return "r27";
4270b57cec5SDimitry Andric case dwarf_gp_mips:
4280b57cec5SDimitry Andric return "gp";
4290b57cec5SDimitry Andric case dwarf_sp_mips:
4300b57cec5SDimitry Andric return "sp";
4310b57cec5SDimitry Andric case dwarf_r30_mips:
4320b57cec5SDimitry Andric return "fp";
4330b57cec5SDimitry Andric case dwarf_ra_mips:
4340b57cec5SDimitry Andric return "ra";
4350b57cec5SDimitry Andric case dwarf_sr_mips:
4360b57cec5SDimitry Andric return "sr";
4370b57cec5SDimitry Andric case dwarf_lo_mips:
4380b57cec5SDimitry Andric return "lo";
4390b57cec5SDimitry Andric case dwarf_hi_mips:
4400b57cec5SDimitry Andric return "hi";
4410b57cec5SDimitry Andric case dwarf_bad_mips:
4420b57cec5SDimitry Andric return "bad";
4430b57cec5SDimitry Andric case dwarf_cause_mips:
4440b57cec5SDimitry Andric return "cause";
4450b57cec5SDimitry Andric case dwarf_pc_mips:
4460b57cec5SDimitry Andric return "pc";
4470b57cec5SDimitry Andric case dwarf_f0_mips:
4480b57cec5SDimitry Andric return "f0";
4490b57cec5SDimitry Andric case dwarf_f1_mips:
4500b57cec5SDimitry Andric return "f1";
4510b57cec5SDimitry Andric case dwarf_f2_mips:
4520b57cec5SDimitry Andric return "f2";
4530b57cec5SDimitry Andric case dwarf_f3_mips:
4540b57cec5SDimitry Andric return "f3";
4550b57cec5SDimitry Andric case dwarf_f4_mips:
4560b57cec5SDimitry Andric return "f4";
4570b57cec5SDimitry Andric case dwarf_f5_mips:
4580b57cec5SDimitry Andric return "f5";
4590b57cec5SDimitry Andric case dwarf_f6_mips:
4600b57cec5SDimitry Andric return "f6";
4610b57cec5SDimitry Andric case dwarf_f7_mips:
4620b57cec5SDimitry Andric return "f7";
4630b57cec5SDimitry Andric case dwarf_f8_mips:
4640b57cec5SDimitry Andric return "f8";
4650b57cec5SDimitry Andric case dwarf_f9_mips:
4660b57cec5SDimitry Andric return "f9";
4670b57cec5SDimitry Andric case dwarf_f10_mips:
4680b57cec5SDimitry Andric return "f10";
4690b57cec5SDimitry Andric case dwarf_f11_mips:
4700b57cec5SDimitry Andric return "f11";
4710b57cec5SDimitry Andric case dwarf_f12_mips:
4720b57cec5SDimitry Andric return "f12";
4730b57cec5SDimitry Andric case dwarf_f13_mips:
4740b57cec5SDimitry Andric return "f13";
4750b57cec5SDimitry Andric case dwarf_f14_mips:
4760b57cec5SDimitry Andric return "f14";
4770b57cec5SDimitry Andric case dwarf_f15_mips:
4780b57cec5SDimitry Andric return "f15";
4790b57cec5SDimitry Andric case dwarf_f16_mips:
4800b57cec5SDimitry Andric return "f16";
4810b57cec5SDimitry Andric case dwarf_f17_mips:
4820b57cec5SDimitry Andric return "f17";
4830b57cec5SDimitry Andric case dwarf_f18_mips:
4840b57cec5SDimitry Andric return "f18";
4850b57cec5SDimitry Andric case dwarf_f19_mips:
4860b57cec5SDimitry Andric return "f19";
4870b57cec5SDimitry Andric case dwarf_f20_mips:
4880b57cec5SDimitry Andric return "f20";
4890b57cec5SDimitry Andric case dwarf_f21_mips:
4900b57cec5SDimitry Andric return "f21";
4910b57cec5SDimitry Andric case dwarf_f22_mips:
4920b57cec5SDimitry Andric return "f22";
4930b57cec5SDimitry Andric case dwarf_f23_mips:
4940b57cec5SDimitry Andric return "f23";
4950b57cec5SDimitry Andric case dwarf_f24_mips:
4960b57cec5SDimitry Andric return "f24";
4970b57cec5SDimitry Andric case dwarf_f25_mips:
4980b57cec5SDimitry Andric return "f25";
4990b57cec5SDimitry Andric case dwarf_f26_mips:
5000b57cec5SDimitry Andric return "f26";
5010b57cec5SDimitry Andric case dwarf_f27_mips:
5020b57cec5SDimitry Andric return "f27";
5030b57cec5SDimitry Andric case dwarf_f28_mips:
5040b57cec5SDimitry Andric return "f28";
5050b57cec5SDimitry Andric case dwarf_f29_mips:
5060b57cec5SDimitry Andric return "f29";
5070b57cec5SDimitry Andric case dwarf_f30_mips:
5080b57cec5SDimitry Andric return "f30";
5090b57cec5SDimitry Andric case dwarf_f31_mips:
5100b57cec5SDimitry Andric return "f31";
5110b57cec5SDimitry Andric case dwarf_fcsr_mips:
5120b57cec5SDimitry Andric return "fcsr";
5130b57cec5SDimitry Andric case dwarf_fir_mips:
5140b57cec5SDimitry Andric return "fir";
5150b57cec5SDimitry Andric case dwarf_w0_mips:
5160b57cec5SDimitry Andric return "w0";
5170b57cec5SDimitry Andric case dwarf_w1_mips:
5180b57cec5SDimitry Andric return "w1";
5190b57cec5SDimitry Andric case dwarf_w2_mips:
5200b57cec5SDimitry Andric return "w2";
5210b57cec5SDimitry Andric case dwarf_w3_mips:
5220b57cec5SDimitry Andric return "w3";
5230b57cec5SDimitry Andric case dwarf_w4_mips:
5240b57cec5SDimitry Andric return "w4";
5250b57cec5SDimitry Andric case dwarf_w5_mips:
5260b57cec5SDimitry Andric return "w5";
5270b57cec5SDimitry Andric case dwarf_w6_mips:
5280b57cec5SDimitry Andric return "w6";
5290b57cec5SDimitry Andric case dwarf_w7_mips:
5300b57cec5SDimitry Andric return "w7";
5310b57cec5SDimitry Andric case dwarf_w8_mips:
5320b57cec5SDimitry Andric return "w8";
5330b57cec5SDimitry Andric case dwarf_w9_mips:
5340b57cec5SDimitry Andric return "w9";
5350b57cec5SDimitry Andric case dwarf_w10_mips:
5360b57cec5SDimitry Andric return "w10";
5370b57cec5SDimitry Andric case dwarf_w11_mips:
5380b57cec5SDimitry Andric return "w11";
5390b57cec5SDimitry Andric case dwarf_w12_mips:
5400b57cec5SDimitry Andric return "w12";
5410b57cec5SDimitry Andric case dwarf_w13_mips:
5420b57cec5SDimitry Andric return "w13";
5430b57cec5SDimitry Andric case dwarf_w14_mips:
5440b57cec5SDimitry Andric return "w14";
5450b57cec5SDimitry Andric case dwarf_w15_mips:
5460b57cec5SDimitry Andric return "w15";
5470b57cec5SDimitry Andric case dwarf_w16_mips:
5480b57cec5SDimitry Andric return "w16";
5490b57cec5SDimitry Andric case dwarf_w17_mips:
5500b57cec5SDimitry Andric return "w17";
5510b57cec5SDimitry Andric case dwarf_w18_mips:
5520b57cec5SDimitry Andric return "w18";
5530b57cec5SDimitry Andric case dwarf_w19_mips:
5540b57cec5SDimitry Andric return "w19";
5550b57cec5SDimitry Andric case dwarf_w20_mips:
5560b57cec5SDimitry Andric return "w20";
5570b57cec5SDimitry Andric case dwarf_w21_mips:
5580b57cec5SDimitry Andric return "w21";
5590b57cec5SDimitry Andric case dwarf_w22_mips:
5600b57cec5SDimitry Andric return "w22";
5610b57cec5SDimitry Andric case dwarf_w23_mips:
5620b57cec5SDimitry Andric return "w23";
5630b57cec5SDimitry Andric case dwarf_w24_mips:
5640b57cec5SDimitry Andric return "w24";
5650b57cec5SDimitry Andric case dwarf_w25_mips:
5660b57cec5SDimitry Andric return "w25";
5670b57cec5SDimitry Andric case dwarf_w26_mips:
5680b57cec5SDimitry Andric return "w26";
5690b57cec5SDimitry Andric case dwarf_w27_mips:
5700b57cec5SDimitry Andric return "w27";
5710b57cec5SDimitry Andric case dwarf_w28_mips:
5720b57cec5SDimitry Andric return "w28";
5730b57cec5SDimitry Andric case dwarf_w29_mips:
5740b57cec5SDimitry Andric return "w29";
5750b57cec5SDimitry Andric case dwarf_w30_mips:
5760b57cec5SDimitry Andric return "w30";
5770b57cec5SDimitry Andric case dwarf_w31_mips:
5780b57cec5SDimitry Andric return "w31";
5790b57cec5SDimitry Andric case dwarf_mcsr_mips:
5800b57cec5SDimitry Andric return "mcsr";
5810b57cec5SDimitry Andric case dwarf_mir_mips:
5820b57cec5SDimitry Andric return "mir";
5830b57cec5SDimitry Andric case dwarf_config5_mips:
5840b57cec5SDimitry Andric return "config5";
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric return nullptr;
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric
589bdd1243dSDimitry Andric std::optional<RegisterInfo>
GetRegisterInfo(RegisterKind reg_kind,uint32_t reg_num)590bdd1243dSDimitry Andric EmulateInstructionMIPS::GetRegisterInfo(RegisterKind reg_kind,
591bdd1243dSDimitry Andric uint32_t reg_num) {
5920b57cec5SDimitry Andric if (reg_kind == eRegisterKindGeneric) {
5930b57cec5SDimitry Andric switch (reg_num) {
5940b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_PC:
5950b57cec5SDimitry Andric reg_kind = eRegisterKindDWARF;
5960b57cec5SDimitry Andric reg_num = dwarf_pc_mips;
5970b57cec5SDimitry Andric break;
5980b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_SP:
5990b57cec5SDimitry Andric reg_kind = eRegisterKindDWARF;
6000b57cec5SDimitry Andric reg_num = dwarf_sp_mips;
6010b57cec5SDimitry Andric break;
6020b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_FP:
6030b57cec5SDimitry Andric reg_kind = eRegisterKindDWARF;
6040b57cec5SDimitry Andric reg_num = dwarf_r30_mips;
6050b57cec5SDimitry Andric break;
6060b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_RA:
6070b57cec5SDimitry Andric reg_kind = eRegisterKindDWARF;
6080b57cec5SDimitry Andric reg_num = dwarf_ra_mips;
6090b57cec5SDimitry Andric break;
6100b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_FLAGS:
6110b57cec5SDimitry Andric reg_kind = eRegisterKindDWARF;
6120b57cec5SDimitry Andric reg_num = dwarf_sr_mips;
6130b57cec5SDimitry Andric break;
6140b57cec5SDimitry Andric default:
615bdd1243dSDimitry Andric return {};
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric }
6180b57cec5SDimitry Andric
6190b57cec5SDimitry Andric if (reg_kind == eRegisterKindDWARF) {
620bdd1243dSDimitry Andric RegisterInfo reg_info;
6210b57cec5SDimitry Andric ::memset(®_info, 0, sizeof(RegisterInfo));
6220b57cec5SDimitry Andric ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
6230b57cec5SDimitry Andric
6240b57cec5SDimitry Andric if (reg_num == dwarf_sr_mips || reg_num == dwarf_fcsr_mips ||
6250b57cec5SDimitry Andric reg_num == dwarf_fir_mips || reg_num == dwarf_mcsr_mips ||
6260b57cec5SDimitry Andric reg_num == dwarf_mir_mips || reg_num == dwarf_config5_mips) {
6270b57cec5SDimitry Andric reg_info.byte_size = 4;
6280b57cec5SDimitry Andric reg_info.format = eFormatHex;
6290b57cec5SDimitry Andric reg_info.encoding = eEncodingUint;
6300b57cec5SDimitry Andric } else if ((int)reg_num >= dwarf_zero_mips &&
6310b57cec5SDimitry Andric (int)reg_num <= dwarf_f31_mips) {
6320b57cec5SDimitry Andric reg_info.byte_size = 4;
6330b57cec5SDimitry Andric reg_info.format = eFormatHex;
6340b57cec5SDimitry Andric reg_info.encoding = eEncodingUint;
6350b57cec5SDimitry Andric } else if ((int)reg_num >= dwarf_w0_mips &&
6360b57cec5SDimitry Andric (int)reg_num <= dwarf_w31_mips) {
6370b57cec5SDimitry Andric reg_info.byte_size = 16;
6380b57cec5SDimitry Andric reg_info.format = eFormatVectorOfUInt8;
6390b57cec5SDimitry Andric reg_info.encoding = eEncodingVector;
6400b57cec5SDimitry Andric } else {
641bdd1243dSDimitry Andric return {};
6420b57cec5SDimitry Andric }
6430b57cec5SDimitry Andric
6440b57cec5SDimitry Andric reg_info.name = GetRegisterName(reg_num, false);
6450b57cec5SDimitry Andric reg_info.alt_name = GetRegisterName(reg_num, true);
6460b57cec5SDimitry Andric reg_info.kinds[eRegisterKindDWARF] = reg_num;
6470b57cec5SDimitry Andric
6480b57cec5SDimitry Andric switch (reg_num) {
6490b57cec5SDimitry Andric case dwarf_r30_mips:
6500b57cec5SDimitry Andric reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
6510b57cec5SDimitry Andric break;
6520b57cec5SDimitry Andric case dwarf_ra_mips:
6530b57cec5SDimitry Andric reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
6540b57cec5SDimitry Andric break;
6550b57cec5SDimitry Andric case dwarf_sp_mips:
6560b57cec5SDimitry Andric reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
6570b57cec5SDimitry Andric break;
6580b57cec5SDimitry Andric case dwarf_pc_mips:
6590b57cec5SDimitry Andric reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
6600b57cec5SDimitry Andric break;
6610b57cec5SDimitry Andric case dwarf_sr_mips:
6620b57cec5SDimitry Andric reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
6630b57cec5SDimitry Andric break;
6640b57cec5SDimitry Andric default:
6650b57cec5SDimitry Andric break;
6660b57cec5SDimitry Andric }
667bdd1243dSDimitry Andric return reg_info;
6680b57cec5SDimitry Andric }
669bdd1243dSDimitry Andric return {};
6700b57cec5SDimitry Andric }
6710b57cec5SDimitry Andric
6720b57cec5SDimitry Andric EmulateInstructionMIPS::MipsOpcode *
GetOpcodeForInstruction(llvm::StringRef name)67381ad6265SDimitry Andric EmulateInstructionMIPS::GetOpcodeForInstruction(llvm::StringRef name) {
6740b57cec5SDimitry Andric static EmulateInstructionMIPS::MipsOpcode g_opcodes[] = {
6750b57cec5SDimitry Andric // Prologue/Epilogue instructions
6760b57cec5SDimitry Andric {"ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu,
6770b57cec5SDimitry Andric "ADDIU rt, rs, immediate"},
6780b57cec5SDimitry Andric {"SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt, offset(rs)"},
6790b57cec5SDimitry Andric {"LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt, offset(base)"},
6800b57cec5SDimitry Andric {"SUBU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "SUBU rd, rs, rt"},
6810b57cec5SDimitry Andric {"ADDU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "ADDU rd, rs, rt"},
6820b57cec5SDimitry Andric {"LUI", &EmulateInstructionMIPS::Emulate_LUI, "LUI rt, immediate"},
6830b57cec5SDimitry Andric
6840b57cec5SDimitry Andric // MicroMIPS Prologue/Epilogue instructions
6850b57cec5SDimitry Andric {"ADDIUSP_MM", &EmulateInstructionMIPS::Emulate_ADDIUSP,
6860b57cec5SDimitry Andric "ADDIU immediate"},
6870b57cec5SDimitry Andric {"ADDIUS5_MM", &EmulateInstructionMIPS::Emulate_ADDIUS5,
6880b57cec5SDimitry Andric "ADDIUS5 rd,immediate"},
6890b57cec5SDimitry Andric {"SWSP_MM", &EmulateInstructionMIPS::Emulate_SWSP, "SWSP rt,offset(sp)"},
6900b57cec5SDimitry Andric {"SWM16_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
6910b57cec5SDimitry Andric "SWM16 reglist,offset(sp)"},
6920b57cec5SDimitry Andric {"SWM32_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
6930b57cec5SDimitry Andric "SWM32 reglist,offset(base)"},
6940b57cec5SDimitry Andric {"SWP_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
6950b57cec5SDimitry Andric "SWP rs1,offset(base)"},
6960b57cec5SDimitry Andric {"LWSP_MM", &EmulateInstructionMIPS::Emulate_LWSP, "LWSP rt,offset(sp)"},
6970b57cec5SDimitry Andric {"LWM16_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
6980b57cec5SDimitry Andric "LWM16 reglist,offset(sp)"},
6990b57cec5SDimitry Andric {"LWM32_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
7000b57cec5SDimitry Andric "LWM32 reglist,offset(base)"},
7010b57cec5SDimitry Andric {"LWP_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
7020b57cec5SDimitry Andric "LWP rd,offset(base)"},
7030b57cec5SDimitry Andric {"JRADDIUSP", &EmulateInstructionMIPS::Emulate_JRADDIUSP,
7040b57cec5SDimitry Andric "JRADDIUSP immediate"},
7050b57cec5SDimitry Andric
7060b57cec5SDimitry Andric // Load/Store instructions
7070b57cec5SDimitry Andric /* Following list of emulated instructions are required by implementation
7080b57cec5SDimitry Andric of hardware watchpoint
7090b57cec5SDimitry Andric for MIPS in lldb. As we just need the address accessed by instructions,
7100b57cec5SDimitry Andric we have generalised
7110b57cec5SDimitry Andric all these instructions in 2 functions depending on their addressing
7120b57cec5SDimitry Andric modes */
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric {"LB", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7150b57cec5SDimitry Andric "LB rt, offset(base)"},
7160b57cec5SDimitry Andric {"LBE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7170b57cec5SDimitry Andric "LBE rt, offset(base)"},
7180b57cec5SDimitry Andric {"LBU", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7190b57cec5SDimitry Andric "LBU rt, offset(base)"},
7200b57cec5SDimitry Andric {"LBUE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7210b57cec5SDimitry Andric "LBUE rt, offset(base)"},
7220b57cec5SDimitry Andric {"LDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7230b57cec5SDimitry Andric "LDC1 ft, offset(base)"},
7240b57cec5SDimitry Andric {"LD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7250b57cec5SDimitry Andric "LD rt, offset(base)"},
7260b57cec5SDimitry Andric {"LDL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7270b57cec5SDimitry Andric "LDL rt, offset(base)"},
7280b57cec5SDimitry Andric {"LDR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7290b57cec5SDimitry Andric "LDR rt, offset(base)"},
7300b57cec5SDimitry Andric {"LLD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7310b57cec5SDimitry Andric "LLD rt, offset(base)"},
7320b57cec5SDimitry Andric {"LDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7330b57cec5SDimitry Andric "LDC2 rt, offset(base)"},
7340b57cec5SDimitry Andric {"LDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
7350b57cec5SDimitry Andric "LDXC1 fd, index (base)"},
7360b57cec5SDimitry Andric {"LH", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7370b57cec5SDimitry Andric "LH rt, offset(base)"},
7380b57cec5SDimitry Andric {"LHE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7390b57cec5SDimitry Andric "LHE rt, offset(base)"},
7400b57cec5SDimitry Andric {"LHU", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7410b57cec5SDimitry Andric "LHU rt, offset(base)"},
7420b57cec5SDimitry Andric {"LHUE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7430b57cec5SDimitry Andric "LHUE rt, offset(base)"},
7440b57cec5SDimitry Andric {"LL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7450b57cec5SDimitry Andric "LL rt, offset(base)"},
7460b57cec5SDimitry Andric {"LLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7470b57cec5SDimitry Andric "LLE rt, offset(base)"},
7480b57cec5SDimitry Andric {"LUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
7490b57cec5SDimitry Andric "LUXC1 fd, index (base)"},
7500b57cec5SDimitry Andric {"LW", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7510b57cec5SDimitry Andric "LW rt, offset(base)"},
7520b57cec5SDimitry Andric {"LWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7530b57cec5SDimitry Andric "LWC1 ft, offset(base)"},
7540b57cec5SDimitry Andric {"LWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7550b57cec5SDimitry Andric "LWC2 rt, offset(base)"},
7560b57cec5SDimitry Andric {"LWE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7570b57cec5SDimitry Andric "LWE rt, offset(base)"},
7580b57cec5SDimitry Andric {"LWL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7590b57cec5SDimitry Andric "LWL rt, offset(base)"},
7600b57cec5SDimitry Andric {"LWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7610b57cec5SDimitry Andric "LWLE rt, offset(base)"},
7620b57cec5SDimitry Andric {"LWR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7630b57cec5SDimitry Andric "LWR rt, offset(base)"},
7640b57cec5SDimitry Andric {"LWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7650b57cec5SDimitry Andric "LWRE rt, offset(base)"},
7660b57cec5SDimitry Andric {"LWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
7670b57cec5SDimitry Andric "LWXC1 fd, index (base)"},
7680b57cec5SDimitry Andric {"LLX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7690b57cec5SDimitry Andric "LLX rt, offset(base)"},
7700b57cec5SDimitry Andric {"LLXE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7710b57cec5SDimitry Andric "LLXE rt, offset(base)"},
7720b57cec5SDimitry Andric {"LLDX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7730b57cec5SDimitry Andric "LLDX rt, offset(base)"},
7740b57cec5SDimitry Andric
7750b57cec5SDimitry Andric {"SB", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7760b57cec5SDimitry Andric "SB rt, offset(base)"},
7770b57cec5SDimitry Andric {"SBE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7780b57cec5SDimitry Andric "SBE rt, offset(base)"},
7790b57cec5SDimitry Andric {"SC", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7800b57cec5SDimitry Andric "SC rt, offset(base)"},
7810b57cec5SDimitry Andric {"SCE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7820b57cec5SDimitry Andric "SCE rt, offset(base)"},
7830b57cec5SDimitry Andric {"SCD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7840b57cec5SDimitry Andric "SCD rt, offset(base)"},
7850b57cec5SDimitry Andric {"SD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7860b57cec5SDimitry Andric "SD rt, offset(base)"},
7870b57cec5SDimitry Andric {"SDL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7880b57cec5SDimitry Andric "SDL rt, offset(base)"},
7890b57cec5SDimitry Andric {"SDR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7900b57cec5SDimitry Andric "SDR rt, offset(base)"},
7910b57cec5SDimitry Andric {"SDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7920b57cec5SDimitry Andric "SDC1 ft, offset(base)"},
7930b57cec5SDimitry Andric {"SDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7940b57cec5SDimitry Andric "SDC2 rt, offset(base)"},
7950b57cec5SDimitry Andric {"SDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
7960b57cec5SDimitry Andric "SDXC1 fs, index(base)"},
7970b57cec5SDimitry Andric {"SH", &EmulateInstructionMIPS::Emulate_LDST_Imm,
7980b57cec5SDimitry Andric "SH rt, offset(base)"},
7990b57cec5SDimitry Andric {"SHE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8000b57cec5SDimitry Andric "SHE rt, offset(base)"},
8010b57cec5SDimitry Andric {"SUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
8020b57cec5SDimitry Andric "SUXC1 fs, index (base)"},
8030b57cec5SDimitry Andric {"SWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8040b57cec5SDimitry Andric "SWC1 ft, offset(base)"},
8050b57cec5SDimitry Andric {"SWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8060b57cec5SDimitry Andric "SWC2 rt, offset(base)"},
8070b57cec5SDimitry Andric {"SWE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8080b57cec5SDimitry Andric "SWE rt, offset(base)"},
8090b57cec5SDimitry Andric {"SWL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8100b57cec5SDimitry Andric "SWL rt, offset(base)"},
8110b57cec5SDimitry Andric {"SWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8120b57cec5SDimitry Andric "SWLE rt, offset(base)"},
8130b57cec5SDimitry Andric {"SWR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8140b57cec5SDimitry Andric "SWR rt, offset(base)"},
8150b57cec5SDimitry Andric {"SWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8160b57cec5SDimitry Andric "SWRE rt, offset(base)"},
8170b57cec5SDimitry Andric {"SWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
8180b57cec5SDimitry Andric "SWXC1 fs, index (base)"},
8190b57cec5SDimitry Andric {"SCX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8200b57cec5SDimitry Andric "SCX rt, offset(base)"},
8210b57cec5SDimitry Andric {"SCXE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8220b57cec5SDimitry Andric "SCXE rt, offset(base)"},
8230b57cec5SDimitry Andric {"SCDX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8240b57cec5SDimitry Andric "SCDX rt, offset(base)"},
8250b57cec5SDimitry Andric
8260b57cec5SDimitry Andric // MicroMIPS Load/Store instructions
8270b57cec5SDimitry Andric {"LBU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8280b57cec5SDimitry Andric "LBU16 rt, decoded_offset(base)"},
8290b57cec5SDimitry Andric {"LHU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8300b57cec5SDimitry Andric "LHU16 rt, left_shifted_offset(base)"},
8310b57cec5SDimitry Andric {"LW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8320b57cec5SDimitry Andric "LW16 rt, left_shifted_offset(base)"},
8330b57cec5SDimitry Andric {"LWGP_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8340b57cec5SDimitry Andric "LWGP rt, left_shifted_offset(gp)"},
8350b57cec5SDimitry Andric {"SH16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8360b57cec5SDimitry Andric "SH16 rt, left_shifted_offset(base)"},
8370b57cec5SDimitry Andric {"SW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8380b57cec5SDimitry Andric "SW16 rt, left_shifted_offset(base)"},
8390b57cec5SDimitry Andric {"SW_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8400b57cec5SDimitry Andric "SWSP rt, left_shifted_offset(base)"},
8410b57cec5SDimitry Andric {"SB16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
8420b57cec5SDimitry Andric "SB16 rt, offset(base)"},
8430b57cec5SDimitry Andric
8440b57cec5SDimitry Andric // Branch instructions
8450b57cec5SDimitry Andric {"BEQ", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQ rs,rt,offset"},
8460b57cec5SDimitry Andric {"BNE", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNE rs,rt,offset"},
8470b57cec5SDimitry Andric {"BEQL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQL rs,rt,offset"},
8480b57cec5SDimitry Andric {"BNEL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNEL rs,rt,offset"},
8490b57cec5SDimitry Andric {"BGEZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
8500b57cec5SDimitry Andric "BGEZALL rt,offset"},
8510b57cec5SDimitry Andric {"BAL", &EmulateInstructionMIPS::Emulate_BAL, "BAL offset"},
8520b57cec5SDimitry Andric {"BGEZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
8530b57cec5SDimitry Andric "BGEZAL rs,offset"},
8540b57cec5SDimitry Andric {"BALC", &EmulateInstructionMIPS::Emulate_BALC, "BALC offset"},
8550b57cec5SDimitry Andric {"BC", &EmulateInstructionMIPS::Emulate_BC, "BC offset"},
8560b57cec5SDimitry Andric {"BGEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZ rs,offset"},
8570b57cec5SDimitry Andric {"BLEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8580b57cec5SDimitry Andric "BLEZALC rs,offset"},
8590b57cec5SDimitry Andric {"BGEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8600b57cec5SDimitry Andric "BGEZALC rs,offset"},
8610b57cec5SDimitry Andric {"BLTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8620b57cec5SDimitry Andric "BLTZALC rs,offset"},
8630b57cec5SDimitry Andric {"BGTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8640b57cec5SDimitry Andric "BGTZALC rs,offset"},
8650b57cec5SDimitry Andric {"BEQZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8660b57cec5SDimitry Andric "BEQZALC rs,offset"},
8670b57cec5SDimitry Andric {"BNEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
8680b57cec5SDimitry Andric "BNEZALC rs,offset"},
8690b57cec5SDimitry Andric {"BEQC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8700b57cec5SDimitry Andric "BEQC rs,rt,offset"},
8710b57cec5SDimitry Andric {"BNEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8720b57cec5SDimitry Andric "BNEC rs,rt,offset"},
8730b57cec5SDimitry Andric {"BLTC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8740b57cec5SDimitry Andric "BLTC rs,rt,offset"},
8750b57cec5SDimitry Andric {"BGEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8760b57cec5SDimitry Andric "BGEC rs,rt,offset"},
8770b57cec5SDimitry Andric {"BLTUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8780b57cec5SDimitry Andric "BLTUC rs,rt,offset"},
8790b57cec5SDimitry Andric {"BGEUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8800b57cec5SDimitry Andric "BGEUC rs,rt,offset"},
8810b57cec5SDimitry Andric {"BLTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLTZC rt,offset"},
8820b57cec5SDimitry Andric {"BLEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLEZC rt,offset"},
8830b57cec5SDimitry Andric {"BGEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGEZC rt,offset"},
8840b57cec5SDimitry Andric {"BGTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGTZC rt,offset"},
8850b57cec5SDimitry Andric {"BEQZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BEQZC rt,offset"},
8860b57cec5SDimitry Andric {"BNEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BNEZC rt,offset"},
8870b57cec5SDimitry Andric {"BGEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZL rt,offset"},
8880b57cec5SDimitry Andric {"BGTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZ rt,offset"},
8890b57cec5SDimitry Andric {"BGTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZL rt,offset"},
8900b57cec5SDimitry Andric {"BLEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZ rt,offset"},
8910b57cec5SDimitry Andric {"BLEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZL rt,offset"},
8920b57cec5SDimitry Andric {"BLTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZ rt,offset"},
8930b57cec5SDimitry Andric {"BLTZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
8940b57cec5SDimitry Andric "BLTZAL rt,offset"},
8950b57cec5SDimitry Andric {"BLTZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
8960b57cec5SDimitry Andric "BLTZALL rt,offset"},
8970b57cec5SDimitry Andric {"BLTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZL rt,offset"},
8980b57cec5SDimitry Andric {"BOVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
8990b57cec5SDimitry Andric "BOVC rs,rt,offset"},
9000b57cec5SDimitry Andric {"BNVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
9010b57cec5SDimitry Andric "BNVC rs,rt,offset"},
9020b57cec5SDimitry Andric {"J", &EmulateInstructionMIPS::Emulate_J, "J target"},
9030b57cec5SDimitry Andric {"JAL", &EmulateInstructionMIPS::Emulate_JAL, "JAL target"},
9040b57cec5SDimitry Andric {"JALX", &EmulateInstructionMIPS::Emulate_JAL, "JALX target"},
9050b57cec5SDimitry Andric {"JALR", &EmulateInstructionMIPS::Emulate_JALR, "JALR target"},
9060b57cec5SDimitry Andric {"JALR_HB", &EmulateInstructionMIPS::Emulate_JALR, "JALR.HB target"},
9070b57cec5SDimitry Andric {"JIALC", &EmulateInstructionMIPS::Emulate_JIALC, "JIALC rt,offset"},
9080b57cec5SDimitry Andric {"JIC", &EmulateInstructionMIPS::Emulate_JIC, "JIC rt,offset"},
9090b57cec5SDimitry Andric {"JR", &EmulateInstructionMIPS::Emulate_JR, "JR target"},
9100b57cec5SDimitry Andric {"JR_HB", &EmulateInstructionMIPS::Emulate_JR, "JR.HB target"},
9110b57cec5SDimitry Andric {"BC1F", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1F cc, offset"},
9120b57cec5SDimitry Andric {"BC1T", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1T cc, offset"},
9130b57cec5SDimitry Andric {"BC1FL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1FL cc, offset"},
9140b57cec5SDimitry Andric {"BC1TL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1TL cc, offset"},
9150b57cec5SDimitry Andric {"BC1EQZ", &EmulateInstructionMIPS::Emulate_BC1EQZ, "BC1EQZ ft, offset"},
9160b57cec5SDimitry Andric {"BC1NEZ", &EmulateInstructionMIPS::Emulate_BC1NEZ, "BC1NEZ ft, offset"},
9170b57cec5SDimitry Andric {"BC1ANY2F", &EmulateInstructionMIPS::Emulate_3D_branch,
9180b57cec5SDimitry Andric "BC1ANY2F cc, offset"},
9190b57cec5SDimitry Andric {"BC1ANY2T", &EmulateInstructionMIPS::Emulate_3D_branch,
9200b57cec5SDimitry Andric "BC1ANY2T cc, offset"},
9210b57cec5SDimitry Andric {"BC1ANY4F", &EmulateInstructionMIPS::Emulate_3D_branch,
9220b57cec5SDimitry Andric "BC1ANY4F cc, offset"},
9230b57cec5SDimitry Andric {"BC1ANY4T", &EmulateInstructionMIPS::Emulate_3D_branch,
9240b57cec5SDimitry Andric "BC1ANY4T cc, offset"},
9250b57cec5SDimitry Andric {"BNZ_B", &EmulateInstructionMIPS::Emulate_BNZB, "BNZ.b wt,s16"},
9260b57cec5SDimitry Andric {"BNZ_H", &EmulateInstructionMIPS::Emulate_BNZH, "BNZ.h wt,s16"},
9270b57cec5SDimitry Andric {"BNZ_W", &EmulateInstructionMIPS::Emulate_BNZW, "BNZ.w wt,s16"},
9280b57cec5SDimitry Andric {"BNZ_D", &EmulateInstructionMIPS::Emulate_BNZD, "BNZ.d wt,s16"},
9290b57cec5SDimitry Andric {"BZ_B", &EmulateInstructionMIPS::Emulate_BZB, "BZ.b wt,s16"},
9300b57cec5SDimitry Andric {"BZ_H", &EmulateInstructionMIPS::Emulate_BZH, "BZ.h wt,s16"},
9310b57cec5SDimitry Andric {"BZ_W", &EmulateInstructionMIPS::Emulate_BZW, "BZ.w wt,s16"},
9320b57cec5SDimitry Andric {"BZ_D", &EmulateInstructionMIPS::Emulate_BZD, "BZ.d wt,s16"},
9330b57cec5SDimitry Andric {"BNZ_V", &EmulateInstructionMIPS::Emulate_BNZV, "BNZ.V wt,s16"},
9340b57cec5SDimitry Andric {"BZ_V", &EmulateInstructionMIPS::Emulate_BZV, "BZ.V wt,s16"},
9350b57cec5SDimitry Andric
9360b57cec5SDimitry Andric // MicroMIPS Branch instructions
9370b57cec5SDimitry Andric {"B16_MM", &EmulateInstructionMIPS::Emulate_B16_MM, "B16 offset"},
9380b57cec5SDimitry Andric {"BEQZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9390b57cec5SDimitry Andric "BEQZ16 rs, offset"},
9400b57cec5SDimitry Andric {"BNEZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9410b57cec5SDimitry Andric "BNEZ16 rs, offset"},
9420b57cec5SDimitry Andric {"BEQZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9430b57cec5SDimitry Andric "BEQZC rs, offset"},
9440b57cec5SDimitry Andric {"BNEZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9450b57cec5SDimitry Andric "BNEZC rs, offset"},
9460b57cec5SDimitry Andric {"BGEZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9470b57cec5SDimitry Andric "BGEZALS rs, offset"},
9480b57cec5SDimitry Andric {"BLTZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
9490b57cec5SDimitry Andric "BLTZALS rs, offset"},
9500b57cec5SDimitry Andric {"JALR16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALR16 rs"},
9510b57cec5SDimitry Andric {"JALRS16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALRS16 rs"},
9520b57cec5SDimitry Andric {"JR16_MM", &EmulateInstructionMIPS::Emulate_JR, "JR16 rs rs"},
9530b57cec5SDimitry Andric {"JRC16_MM", &EmulateInstructionMIPS::Emulate_JR, "JRC16 rs rs"},
9540b57cec5SDimitry Andric {"JALS_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALS target"},
9550b57cec5SDimitry Andric {"JALX_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALX target"},
9560b57cec5SDimitry Andric {"JALRS_MM", &EmulateInstructionMIPS::Emulate_JALRS, "JALRS rt, rs"},
9570b57cec5SDimitry Andric };
9580b57cec5SDimitry Andric
95981ad6265SDimitry Andric for (MipsOpcode &opcode : g_opcodes) {
96081ad6265SDimitry Andric if (name.equals_insensitive(opcode.op_name))
96181ad6265SDimitry Andric return &opcode;
9620b57cec5SDimitry Andric }
9630b57cec5SDimitry Andric return nullptr;
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric
9660b57cec5SDimitry Andric uint32_t
GetSizeOfInstruction(lldb_private::DataExtractor & data,uint64_t inst_addr)9670b57cec5SDimitry Andric EmulateInstructionMIPS::GetSizeOfInstruction(lldb_private::DataExtractor &data,
9680b57cec5SDimitry Andric uint64_t inst_addr) {
9690b57cec5SDimitry Andric uint64_t next_inst_size = 0;
9700b57cec5SDimitry Andric llvm::MCInst mc_insn;
9710b57cec5SDimitry Andric llvm::MCDisassembler::DecodeStatus decode_status;
9720b57cec5SDimitry Andric llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize());
9730b57cec5SDimitry Andric
9740b57cec5SDimitry Andric if (m_use_alt_disaasm)
975480093f4SDimitry Andric decode_status = m_alt_disasm->getInstruction(
976480093f4SDimitry Andric mc_insn, next_inst_size, raw_insn, inst_addr, llvm::nulls());
9770b57cec5SDimitry Andric else
978480093f4SDimitry Andric decode_status = m_disasm->getInstruction(mc_insn, next_inst_size, raw_insn,
979480093f4SDimitry Andric inst_addr, llvm::nulls());
9800b57cec5SDimitry Andric
9810b57cec5SDimitry Andric if (decode_status != llvm::MCDisassembler::Success)
9820b57cec5SDimitry Andric return false;
9830b57cec5SDimitry Andric
9840b57cec5SDimitry Andric return m_insn_info->get(mc_insn.getOpcode()).getSize();
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric
SetInstruction(const Opcode & insn_opcode,const Address & inst_addr,Target * target)9870b57cec5SDimitry Andric bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode,
9880b57cec5SDimitry Andric const Address &inst_addr,
9890b57cec5SDimitry Andric Target *target) {
9900b57cec5SDimitry Andric m_use_alt_disaasm = false;
9910b57cec5SDimitry Andric
9920b57cec5SDimitry Andric if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) {
9930b57cec5SDimitry Andric if (inst_addr.GetAddressClass() == AddressClass::eCodeAlternateISA) {
9940b57cec5SDimitry Andric Status error;
9950b57cec5SDimitry Andric lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andric /*
9980b57cec5SDimitry Andric * The address belongs to microMIPS function. To find the size of
9990b57cec5SDimitry Andric * next instruction use microMIPS disassembler.
10000b57cec5SDimitry Andric */
10010b57cec5SDimitry Andric m_use_alt_disaasm = true;
10020b57cec5SDimitry Andric
10030b57cec5SDimitry Andric uint32_t current_inst_size = insn_opcode.GetByteSize();
10040b57cec5SDimitry Andric uint8_t buf[sizeof(uint32_t)];
10050b57cec5SDimitry Andric uint64_t next_inst_addr = (m_addr & (~1ull)) + current_inst_size;
10060b57cec5SDimitry Andric Address next_addr(next_inst_addr);
10070b57cec5SDimitry Andric
10080b57cec5SDimitry Andric const size_t bytes_read =
10090b57cec5SDimitry Andric target->ReadMemory(next_addr, /* Address of next instruction */
1010fe6060f1SDimitry Andric buf, sizeof(uint32_t), error,
1011fe6060f1SDimitry Andric false, /* force_live_memory */
1012fe6060f1SDimitry Andric &load_addr);
10130b57cec5SDimitry Andric
10140b57cec5SDimitry Andric if (bytes_read == 0)
10150b57cec5SDimitry Andric return true;
10160b57cec5SDimitry Andric
10170b57cec5SDimitry Andric DataExtractor data(buf, sizeof(uint32_t), GetByteOrder(),
10180b57cec5SDimitry Andric GetAddressByteSize());
10190b57cec5SDimitry Andric m_next_inst_size = GetSizeOfInstruction(data, next_inst_addr);
10200b57cec5SDimitry Andric return true;
10210b57cec5SDimitry Andric } else {
10220b57cec5SDimitry Andric /*
10230b57cec5SDimitry Andric * If the address class is not AddressClass::eCodeAlternateISA then
10240b57cec5SDimitry Andric * the function is not microMIPS. In this case instruction size is
10250b57cec5SDimitry Andric * always 4 bytes.
10260b57cec5SDimitry Andric */
10270b57cec5SDimitry Andric m_next_inst_size = 4;
10280b57cec5SDimitry Andric return true;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric return false;
10320b57cec5SDimitry Andric }
10330b57cec5SDimitry Andric
ReadInstruction()10340b57cec5SDimitry Andric bool EmulateInstructionMIPS::ReadInstruction() {
10350b57cec5SDimitry Andric bool success = false;
10360b57cec5SDimitry Andric m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
10370b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &success);
10380b57cec5SDimitry Andric if (success) {
10390b57cec5SDimitry Andric Context read_inst_context;
10400b57cec5SDimitry Andric read_inst_context.type = eContextReadOpcode;
10410b57cec5SDimitry Andric read_inst_context.SetNoArgs();
10420b57cec5SDimitry Andric m_opcode.SetOpcode32(
10430b57cec5SDimitry Andric ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
10440b57cec5SDimitry Andric GetByteOrder());
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric if (!success)
10470b57cec5SDimitry Andric m_addr = LLDB_INVALID_ADDRESS;
10480b57cec5SDimitry Andric return success;
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric
EvaluateInstruction(uint32_t evaluate_options)10510b57cec5SDimitry Andric bool EmulateInstructionMIPS::EvaluateInstruction(uint32_t evaluate_options) {
10520b57cec5SDimitry Andric bool success = false;
10530b57cec5SDimitry Andric llvm::MCInst mc_insn;
10540b57cec5SDimitry Andric uint64_t insn_size;
10550b57cec5SDimitry Andric DataExtractor data;
10560b57cec5SDimitry Andric
10570b57cec5SDimitry Andric /* Keep the complexity of the decode logic with the llvm::MCDisassembler
10580b57cec5SDimitry Andric * class. */
10590b57cec5SDimitry Andric if (m_opcode.GetData(data)) {
10600b57cec5SDimitry Andric llvm::MCDisassembler::DecodeStatus decode_status;
10610b57cec5SDimitry Andric llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize());
10620b57cec5SDimitry Andric if (m_use_alt_disaasm)
1063480093f4SDimitry Andric decode_status = m_alt_disasm->getInstruction(mc_insn, insn_size, raw_insn,
1064480093f4SDimitry Andric m_addr, llvm::nulls());
10650b57cec5SDimitry Andric else
1066480093f4SDimitry Andric decode_status = m_disasm->getInstruction(mc_insn, insn_size, raw_insn,
1067480093f4SDimitry Andric m_addr, llvm::nulls());
10680b57cec5SDimitry Andric
10690b57cec5SDimitry Andric if (decode_status != llvm::MCDisassembler::Success)
10700b57cec5SDimitry Andric return false;
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric
10730b57cec5SDimitry Andric /*
10740b57cec5SDimitry Andric * mc_insn.getOpcode() returns decoded opcode. However to make use
10750b57cec5SDimitry Andric * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc".
10760b57cec5SDimitry Andric */
10770b57cec5SDimitry Andric const char *op_name = m_insn_info->getName(mc_insn.getOpcode()).data();
10780b57cec5SDimitry Andric
10790b57cec5SDimitry Andric if (op_name == nullptr)
10800b57cec5SDimitry Andric return false;
10810b57cec5SDimitry Andric
10820b57cec5SDimitry Andric /*
10830b57cec5SDimitry Andric * Decoding has been done already. Just get the call-back function
10840b57cec5SDimitry Andric * and emulate the instruction.
10850b57cec5SDimitry Andric */
10860b57cec5SDimitry Andric MipsOpcode *opcode_data = GetOpcodeForInstruction(op_name);
10870b57cec5SDimitry Andric
10880b57cec5SDimitry Andric if (opcode_data == nullptr)
10890b57cec5SDimitry Andric return false;
10900b57cec5SDimitry Andric
10910b57cec5SDimitry Andric uint64_t old_pc = 0, new_pc = 0;
10920b57cec5SDimitry Andric const bool auto_advance_pc =
10930b57cec5SDimitry Andric evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
10940b57cec5SDimitry Andric
10950b57cec5SDimitry Andric if (auto_advance_pc) {
10960b57cec5SDimitry Andric old_pc =
10970b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
10980b57cec5SDimitry Andric if (!success)
10990b57cec5SDimitry Andric return false;
11000b57cec5SDimitry Andric }
11010b57cec5SDimitry Andric
11020b57cec5SDimitry Andric /* emulate instruction */
11030b57cec5SDimitry Andric success = (this->*opcode_data->callback)(mc_insn);
11040b57cec5SDimitry Andric if (!success)
11050b57cec5SDimitry Andric return false;
11060b57cec5SDimitry Andric
11070b57cec5SDimitry Andric if (auto_advance_pc) {
11080b57cec5SDimitry Andric new_pc =
11090b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
11100b57cec5SDimitry Andric if (!success)
11110b57cec5SDimitry Andric return false;
11120b57cec5SDimitry Andric
11130b57cec5SDimitry Andric /* If we haven't changed the PC, change it here */
11140b57cec5SDimitry Andric if (old_pc == new_pc) {
11150b57cec5SDimitry Andric new_pc += 4;
11160b57cec5SDimitry Andric Context context;
11170b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
11180b57cec5SDimitry Andric new_pc))
11190b57cec5SDimitry Andric return false;
11200b57cec5SDimitry Andric }
11210b57cec5SDimitry Andric }
11220b57cec5SDimitry Andric
11230b57cec5SDimitry Andric return true;
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric
CreateFunctionEntryUnwind(UnwindPlan & unwind_plan)11260b57cec5SDimitry Andric bool EmulateInstructionMIPS::CreateFunctionEntryUnwind(
11270b57cec5SDimitry Andric UnwindPlan &unwind_plan) {
11280b57cec5SDimitry Andric unwind_plan.Clear();
11290b57cec5SDimitry Andric unwind_plan.SetRegisterKind(eRegisterKindDWARF);
11300b57cec5SDimitry Andric
11310b57cec5SDimitry Andric UnwindPlan::RowSP row(new UnwindPlan::Row);
11320b57cec5SDimitry Andric const bool can_replace = false;
11330b57cec5SDimitry Andric
11340b57cec5SDimitry Andric // Our previous Call Frame Address is the stack pointer
11350b57cec5SDimitry Andric row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp_mips, 0);
11360b57cec5SDimitry Andric
11370b57cec5SDimitry Andric // Our previous PC is in the RA
11380b57cec5SDimitry Andric row->SetRegisterLocationToRegister(dwarf_pc_mips, dwarf_ra_mips, can_replace);
11390b57cec5SDimitry Andric
11400b57cec5SDimitry Andric unwind_plan.AppendRow(row);
11410b57cec5SDimitry Andric
11420b57cec5SDimitry Andric // All other registers are the same.
11430b57cec5SDimitry Andric unwind_plan.SetSourceName("EmulateInstructionMIPS");
11440b57cec5SDimitry Andric unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
11450b57cec5SDimitry Andric unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
11469dba64beSDimitry Andric unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
11470b57cec5SDimitry Andric unwind_plan.SetReturnAddressRegister(dwarf_ra_mips);
11480b57cec5SDimitry Andric
11490b57cec5SDimitry Andric return true;
11500b57cec5SDimitry Andric }
11510b57cec5SDimitry Andric
nonvolatile_reg_p(uint32_t regnum)11520b57cec5SDimitry Andric bool EmulateInstructionMIPS::nonvolatile_reg_p(uint32_t regnum) {
11530b57cec5SDimitry Andric switch (regnum) {
11540b57cec5SDimitry Andric case dwarf_r16_mips:
11550b57cec5SDimitry Andric case dwarf_r17_mips:
11560b57cec5SDimitry Andric case dwarf_r18_mips:
11570b57cec5SDimitry Andric case dwarf_r19_mips:
11580b57cec5SDimitry Andric case dwarf_r20_mips:
11590b57cec5SDimitry Andric case dwarf_r21_mips:
11600b57cec5SDimitry Andric case dwarf_r22_mips:
11610b57cec5SDimitry Andric case dwarf_r23_mips:
11620b57cec5SDimitry Andric case dwarf_gp_mips:
11630b57cec5SDimitry Andric case dwarf_sp_mips:
11640b57cec5SDimitry Andric case dwarf_r30_mips:
11650b57cec5SDimitry Andric case dwarf_ra_mips:
11660b57cec5SDimitry Andric return true;
11670b57cec5SDimitry Andric default:
11680b57cec5SDimitry Andric return false;
11690b57cec5SDimitry Andric }
11700b57cec5SDimitry Andric return false;
11710b57cec5SDimitry Andric }
11720b57cec5SDimitry Andric
Emulate_ADDiu(llvm::MCInst & insn)11730b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_ADDiu(llvm::MCInst &insn) {
11740b57cec5SDimitry Andric // ADDIU rt, rs, immediate
11750b57cec5SDimitry Andric // GPR[rt] <- GPR[rs] + sign_extend(immediate)
11760b57cec5SDimitry Andric
11770b57cec5SDimitry Andric uint8_t dst, src;
11780b57cec5SDimitry Andric bool success = false;
11790b57cec5SDimitry Andric const uint32_t imm16 = insn.getOperand(2).getImm();
11800b57cec5SDimitry Andric int64_t imm = SignedBits(imm16, 15, 0);
11810b57cec5SDimitry Andric
11820b57cec5SDimitry Andric dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
11830b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
11840b57cec5SDimitry Andric
11850b57cec5SDimitry Andric // If immediate value is greater then 2^16 - 1 then clang generate LUI,
11860b57cec5SDimitry Andric // ADDIU, SUBU instructions in prolog. Example lui $1, 0x2 addiu $1, $1,
11870b57cec5SDimitry Andric // -0x5920 subu $sp, $sp, $1 In this case, ADDIU dst and src will be same
11880b57cec5SDimitry Andric // and not equal to sp
11890b57cec5SDimitry Andric if (dst == src) {
11900b57cec5SDimitry Andric Context context;
11910b57cec5SDimitry Andric
11920b57cec5SDimitry Andric /* read <src> register */
11930b57cec5SDimitry Andric const int64_t src_opd_val = ReadRegisterUnsigned(
11940b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
11950b57cec5SDimitry Andric if (!success)
11960b57cec5SDimitry Andric return false;
11970b57cec5SDimitry Andric
11980b57cec5SDimitry Andric /* Check if this is daddiu sp, sp, imm16 */
11990b57cec5SDimitry Andric if (dst == dwarf_sp_mips) {
12000b57cec5SDimitry Andric uint64_t result = src_opd_val + imm;
1201bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_sp =
1202bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1203bdd1243dSDimitry Andric if (reg_info_sp)
1204bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_sp, imm);
12050b57cec5SDimitry Andric
12060b57cec5SDimitry Andric /* We are allocating bytes on stack */
12070b57cec5SDimitry Andric context.type = eContextAdjustStackPointer;
12080b57cec5SDimitry Andric
12090b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
12100b57cec5SDimitry Andric return true;
12110b57cec5SDimitry Andric }
12120b57cec5SDimitry Andric
12130b57cec5SDimitry Andric imm += src_opd_val;
12140b57cec5SDimitry Andric context.SetImmediateSigned(imm);
12150b57cec5SDimitry Andric context.type = eContextImmediate;
12160b57cec5SDimitry Andric
12170b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
12180b57cec5SDimitry Andric dwarf_zero_mips + dst, imm))
12190b57cec5SDimitry Andric return false;
12200b57cec5SDimitry Andric }
12210b57cec5SDimitry Andric
12220b57cec5SDimitry Andric return true;
12230b57cec5SDimitry Andric }
12240b57cec5SDimitry Andric
Emulate_SW(llvm::MCInst & insn)12250b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_SW(llvm::MCInst &insn) {
12260b57cec5SDimitry Andric bool success = false;
12270b57cec5SDimitry Andric uint32_t imm16 = insn.getOperand(2).getImm();
12280b57cec5SDimitry Andric uint32_t imm = SignedBits(imm16, 15, 0);
12290b57cec5SDimitry Andric uint32_t src, base;
12300b57cec5SDimitry Andric int32_t address;
12310b57cec5SDimitry Andric Context bad_vaddr_context;
12320b57cec5SDimitry Andric
12330b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
12340b57cec5SDimitry Andric base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
12350b57cec5SDimitry Andric
1236bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_base =
1237bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1238bdd1243dSDimitry Andric if (!reg_info_base)
12390b57cec5SDimitry Andric return false;
12400b57cec5SDimitry Andric
12410b57cec5SDimitry Andric /* read base register */
12420b57cec5SDimitry Andric address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
12430b57cec5SDimitry Andric dwarf_zero_mips + base, 0, &success);
12440b57cec5SDimitry Andric if (!success)
12450b57cec5SDimitry Andric return false;
12460b57cec5SDimitry Andric
12470b57cec5SDimitry Andric /* destination address */
12480b57cec5SDimitry Andric address = address + imm;
12490b57cec5SDimitry Andric
12500b57cec5SDimitry Andric /* Set the bad_vaddr register with base address used in the instruction */
12510b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
12520b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
12530b57cec5SDimitry Andric address);
12540b57cec5SDimitry Andric
12550b57cec5SDimitry Andric /* We look for sp based non-volatile register stores */
12560b57cec5SDimitry Andric if (nonvolatile_reg_p(src)) {
1257bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_src =
1258bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1259bdd1243dSDimitry Andric if (!reg_info_src)
12600b57cec5SDimitry Andric return false;
12610b57cec5SDimitry Andric
12620b57cec5SDimitry Andric Context context;
12630b57cec5SDimitry Andric context.type = eContextPushRegisterOnStack;
1264bdd1243dSDimitry Andric context.SetRegisterToRegisterPlusOffset(*reg_info_src, *reg_info_base, 0);
12650b57cec5SDimitry Andric
1266*06c3fb27SDimitry Andric RegisterValue::BytesContainer buffer(reg_info_src->byte_size);
12670b57cec5SDimitry Andric Status error;
12680b57cec5SDimitry Andric
1269bdd1243dSDimitry Andric std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1270bdd1243dSDimitry Andric if (!data_src)
12710b57cec5SDimitry Andric return false;
12720b57cec5SDimitry Andric
1273*06c3fb27SDimitry Andric if (data_src->GetAsMemoryData(*reg_info_src, buffer.data(),
1274bdd1243dSDimitry Andric reg_info_src->byte_size, eByteOrderLittle,
1275bdd1243dSDimitry Andric error) == 0)
12760b57cec5SDimitry Andric return false;
12770b57cec5SDimitry Andric
1278*06c3fb27SDimitry Andric if (!WriteMemory(context, address, buffer.data(), reg_info_src->byte_size))
12790b57cec5SDimitry Andric return false;
12800b57cec5SDimitry Andric
12810b57cec5SDimitry Andric return true;
12820b57cec5SDimitry Andric }
12830b57cec5SDimitry Andric
12840b57cec5SDimitry Andric return false;
12850b57cec5SDimitry Andric }
12860b57cec5SDimitry Andric
Emulate_LW(llvm::MCInst & insn)12870b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LW(llvm::MCInst &insn) {
12880b57cec5SDimitry Andric bool success = false;
12890b57cec5SDimitry Andric uint32_t src, base;
12900b57cec5SDimitry Andric int32_t imm, address;
12910b57cec5SDimitry Andric Context bad_vaddr_context;
12920b57cec5SDimitry Andric
12930b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
12940b57cec5SDimitry Andric base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
12950b57cec5SDimitry Andric imm = insn.getOperand(2).getImm();
12960b57cec5SDimitry Andric
1297bdd1243dSDimitry Andric if (GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
12980b57cec5SDimitry Andric return false;
12990b57cec5SDimitry Andric
13000b57cec5SDimitry Andric /* read base register */
13010b57cec5SDimitry Andric address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
13020b57cec5SDimitry Andric dwarf_zero_mips + base, 0, &success);
13030b57cec5SDimitry Andric if (!success)
13040b57cec5SDimitry Andric return false;
13050b57cec5SDimitry Andric
13060b57cec5SDimitry Andric /* destination address */
13070b57cec5SDimitry Andric address = address + imm;
13080b57cec5SDimitry Andric
13090b57cec5SDimitry Andric /* Set the bad_vaddr register with base address used in the instruction */
13100b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
13110b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
13120b57cec5SDimitry Andric address);
13130b57cec5SDimitry Andric
13140b57cec5SDimitry Andric if (nonvolatile_reg_p(src)) {
13150b57cec5SDimitry Andric RegisterValue data_src;
1316bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_src =
1317bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1318bdd1243dSDimitry Andric if (!reg_info_src)
13190b57cec5SDimitry Andric return false;
13200b57cec5SDimitry Andric
13210b57cec5SDimitry Andric Context context;
13220b57cec5SDimitry Andric context.type = eContextPopRegisterOffStack;
13230b57cec5SDimitry Andric context.SetAddress(address);
13240b57cec5SDimitry Andric
1325bdd1243dSDimitry Andric return WriteRegister(context, *reg_info_src, data_src);
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric
13280b57cec5SDimitry Andric return false;
13290b57cec5SDimitry Andric }
13300b57cec5SDimitry Andric
Emulate_SUBU_ADDU(llvm::MCInst & insn)13310b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_SUBU_ADDU(llvm::MCInst &insn) {
13320b57cec5SDimitry Andric // SUBU sp, <src>, <rt>
13330b57cec5SDimitry Andric // ADDU sp, <src>, <rt>
13340b57cec5SDimitry Andric // ADDU dst, sp, <rt>
13350b57cec5SDimitry Andric
13360b57cec5SDimitry Andric bool success = false;
13370b57cec5SDimitry Andric uint64_t result;
13380b57cec5SDimitry Andric uint8_t src, dst, rt;
133981ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
13400b57cec5SDimitry Andric
13410b57cec5SDimitry Andric dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
13420b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
13430b57cec5SDimitry Andric
13440b57cec5SDimitry Andric /* Check if sp is destination register */
13450b57cec5SDimitry Andric if (dst == dwarf_sp_mips) {
13460b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(2).getReg());
13470b57cec5SDimitry Andric
13480b57cec5SDimitry Andric /* read <src> register */
13490b57cec5SDimitry Andric uint64_t src_opd_val = ReadRegisterUnsigned(
13500b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
13510b57cec5SDimitry Andric if (!success)
13520b57cec5SDimitry Andric return false;
13530b57cec5SDimitry Andric
13540b57cec5SDimitry Andric /* read <rt > register */
13550b57cec5SDimitry Andric uint64_t rt_opd_val = ReadRegisterUnsigned(
13560b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
13570b57cec5SDimitry Andric if (!success)
13580b57cec5SDimitry Andric return false;
13590b57cec5SDimitry Andric
136081ad6265SDimitry Andric if (op_name.equals_insensitive("SUBU"))
13610b57cec5SDimitry Andric result = src_opd_val - rt_opd_val;
13620b57cec5SDimitry Andric else
13630b57cec5SDimitry Andric result = src_opd_val + rt_opd_val;
13640b57cec5SDimitry Andric
13650b57cec5SDimitry Andric Context context;
1366bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_sp =
1367bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1368bdd1243dSDimitry Andric if (reg_info_sp)
1369bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_sp, rt_opd_val);
13700b57cec5SDimitry Andric
13710b57cec5SDimitry Andric /* We are allocating bytes on stack */
13720b57cec5SDimitry Andric context.type = eContextAdjustStackPointer;
13730b57cec5SDimitry Andric
13740b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
13750b57cec5SDimitry Andric
13760b57cec5SDimitry Andric return true;
13770b57cec5SDimitry Andric } else if (src == dwarf_sp_mips) {
13780b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(2).getReg());
13790b57cec5SDimitry Andric
13800b57cec5SDimitry Andric /* read <src> register */
13810b57cec5SDimitry Andric uint64_t src_opd_val = ReadRegisterUnsigned(
13820b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
13830b57cec5SDimitry Andric if (!success)
13840b57cec5SDimitry Andric return false;
13850b57cec5SDimitry Andric
13860b57cec5SDimitry Andric /* read <rt> register */
13870b57cec5SDimitry Andric uint64_t rt_opd_val = ReadRegisterUnsigned(
13880b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
13890b57cec5SDimitry Andric if (!success)
13900b57cec5SDimitry Andric return false;
13910b57cec5SDimitry Andric
13920b57cec5SDimitry Andric Context context;
13930b57cec5SDimitry Andric
139481ad6265SDimitry Andric if (op_name.equals_insensitive("SUBU"))
13950b57cec5SDimitry Andric result = src_opd_val - rt_opd_val;
13960b57cec5SDimitry Andric else
13970b57cec5SDimitry Andric result = src_opd_val + rt_opd_val;
13980b57cec5SDimitry Andric
13990b57cec5SDimitry Andric context.SetImmediateSigned(result);
14000b57cec5SDimitry Andric context.type = eContextImmediate;
14010b57cec5SDimitry Andric
14020b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
14030b57cec5SDimitry Andric dwarf_zero_mips + dst, result))
14040b57cec5SDimitry Andric return false;
14050b57cec5SDimitry Andric }
14060b57cec5SDimitry Andric
14070b57cec5SDimitry Andric return true;
14080b57cec5SDimitry Andric }
14090b57cec5SDimitry Andric
Emulate_LUI(llvm::MCInst & insn)14100b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LUI(llvm::MCInst &insn) {
14110b57cec5SDimitry Andric // LUI rt, immediate
14120b57cec5SDimitry Andric // GPR[rt] <- sign_extend(immediate << 16)
14130b57cec5SDimitry Andric
14140b57cec5SDimitry Andric const uint32_t imm32 = insn.getOperand(1).getImm() << 16;
14150b57cec5SDimitry Andric int64_t imm = SignedBits(imm32, 31, 0);
14160b57cec5SDimitry Andric uint8_t rt;
14170b57cec5SDimitry Andric Context context;
14180b57cec5SDimitry Andric
14190b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
14200b57cec5SDimitry Andric context.SetImmediateSigned(imm);
14210b57cec5SDimitry Andric context.type = eContextImmediate;
14220b57cec5SDimitry Andric
14230b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF,
14240b57cec5SDimitry Andric dwarf_zero_mips + rt, imm);
14250b57cec5SDimitry Andric }
14260b57cec5SDimitry Andric
Emulate_ADDIUSP(llvm::MCInst & insn)14270b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_ADDIUSP(llvm::MCInst &insn) {
14280b57cec5SDimitry Andric bool success = false;
14290b57cec5SDimitry Andric const uint32_t imm9 = insn.getOperand(0).getImm();
14300b57cec5SDimitry Andric uint64_t result;
14310b57cec5SDimitry Andric
14320b57cec5SDimitry Andric // This instruction operates implicitly on stack pointer, so read <sp>
14330b57cec5SDimitry Andric // register.
14340b57cec5SDimitry Andric uint64_t src_opd_val =
14350b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_sp_mips, 0, &success);
14360b57cec5SDimitry Andric if (!success)
14370b57cec5SDimitry Andric return false;
14380b57cec5SDimitry Andric
14390b57cec5SDimitry Andric result = src_opd_val + imm9;
14400b57cec5SDimitry Andric
14410b57cec5SDimitry Andric Context context;
1442bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_sp =
1443bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1444bdd1243dSDimitry Andric if (reg_info_sp)
1445bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_sp, imm9);
14460b57cec5SDimitry Andric
14470b57cec5SDimitry Andric // We are adjusting the stack.
14480b57cec5SDimitry Andric context.type = eContextAdjustStackPointer;
14490b57cec5SDimitry Andric
14500b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
14510b57cec5SDimitry Andric return true;
14520b57cec5SDimitry Andric }
14530b57cec5SDimitry Andric
Emulate_ADDIUS5(llvm::MCInst & insn)14540b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_ADDIUS5(llvm::MCInst &insn) {
14550b57cec5SDimitry Andric bool success = false;
14560b57cec5SDimitry Andric uint32_t base;
14570b57cec5SDimitry Andric const uint32_t imm4 = insn.getOperand(2).getImm();
14580b57cec5SDimitry Andric uint64_t result;
14590b57cec5SDimitry Andric
14600b57cec5SDimitry Andric // The source and destination register is same for this instruction.
14610b57cec5SDimitry Andric base = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
14620b57cec5SDimitry Andric
14630b57cec5SDimitry Andric // We are looking for stack adjustment only
14640b57cec5SDimitry Andric if (base == dwarf_sp_mips) {
14650b57cec5SDimitry Andric // Read stack pointer register
14660b57cec5SDimitry Andric uint64_t src_opd_val = ReadRegisterUnsigned(
14670b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
14680b57cec5SDimitry Andric if (!success)
14690b57cec5SDimitry Andric return false;
14700b57cec5SDimitry Andric
14710b57cec5SDimitry Andric result = src_opd_val + imm4;
14720b57cec5SDimitry Andric
14730b57cec5SDimitry Andric Context context;
1474bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_sp =
1475bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1476bdd1243dSDimitry Andric if (reg_info_sp)
1477bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_sp, imm4);
14780b57cec5SDimitry Andric
14790b57cec5SDimitry Andric // We are adjusting the stack.
14800b57cec5SDimitry Andric context.type = eContextAdjustStackPointer;
14810b57cec5SDimitry Andric
14820b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
14830b57cec5SDimitry Andric }
14840b57cec5SDimitry Andric
14850b57cec5SDimitry Andric return true;
14860b57cec5SDimitry Andric }
14870b57cec5SDimitry Andric
Emulate_SWSP(llvm::MCInst & insn)14880b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_SWSP(llvm::MCInst &insn) {
14890b57cec5SDimitry Andric bool success = false;
14900b57cec5SDimitry Andric uint32_t imm5 = insn.getOperand(2).getImm();
14910b57cec5SDimitry Andric uint32_t src, base;
14920b57cec5SDimitry Andric Context bad_vaddr_context;
14930b57cec5SDimitry Andric uint32_t address;
14940b57cec5SDimitry Andric
14950b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
14960b57cec5SDimitry Andric base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
14970b57cec5SDimitry Andric
1498bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_base =
1499bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1500bdd1243dSDimitry Andric if (!reg_info_base)
15010b57cec5SDimitry Andric return false;
15020b57cec5SDimitry Andric
15030b57cec5SDimitry Andric // read base register
15040b57cec5SDimitry Andric address = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + base, 0,
15050b57cec5SDimitry Andric &success);
15060b57cec5SDimitry Andric if (!success)
15070b57cec5SDimitry Andric return false;
15080b57cec5SDimitry Andric
15090b57cec5SDimitry Andric // destination address
15100b57cec5SDimitry Andric address = address + imm5;
15110b57cec5SDimitry Andric
15120b57cec5SDimitry Andric // We use bad_vaddr_context to store base address which is used by H/W
15130b57cec5SDimitry Andric // watchpoint Set the bad_vaddr register with base address used in the
15140b57cec5SDimitry Andric // instruction
15150b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
15160b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
15170b57cec5SDimitry Andric address);
15180b57cec5SDimitry Andric
15190b57cec5SDimitry Andric // We look for sp based non-volatile register stores.
15200b57cec5SDimitry Andric if (base == dwarf_sp_mips && nonvolatile_reg_p(src)) {
15210b57cec5SDimitry Andric RegisterInfo reg_info_src = {};
15220b57cec5SDimitry Andric Context context;
15230b57cec5SDimitry Andric context.type = eContextPushRegisterOnStack;
1524bdd1243dSDimitry Andric context.SetRegisterToRegisterPlusOffset(reg_info_src, *reg_info_base, 0);
15250b57cec5SDimitry Andric
1526*06c3fb27SDimitry Andric RegisterValue::BytesContainer buffer(reg_info_src.byte_size);
15270b57cec5SDimitry Andric Status error;
15280b57cec5SDimitry Andric
1529bdd1243dSDimitry Andric std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1530bdd1243dSDimitry Andric if (!data_src)
15310b57cec5SDimitry Andric return false;
15320b57cec5SDimitry Andric
1533*06c3fb27SDimitry Andric if (data_src->GetAsMemoryData(reg_info_src, buffer.data(),
1534*06c3fb27SDimitry Andric reg_info_src.byte_size, eByteOrderLittle,
1535*06c3fb27SDimitry Andric error) == 0)
15360b57cec5SDimitry Andric return false;
15370b57cec5SDimitry Andric
1538*06c3fb27SDimitry Andric if (!WriteMemory(context, address, buffer.data(), reg_info_src.byte_size))
15390b57cec5SDimitry Andric return false;
15400b57cec5SDimitry Andric
15410b57cec5SDimitry Andric return true;
15420b57cec5SDimitry Andric }
15430b57cec5SDimitry Andric
15440b57cec5SDimitry Andric return false;
15450b57cec5SDimitry Andric }
15460b57cec5SDimitry Andric
15470b57cec5SDimitry Andric /* Emulate SWM16,SWM32 and SWP instruction.
15480b57cec5SDimitry Andric
15490b57cec5SDimitry Andric SWM16 always has stack pointer as a base register (but it is still available
15500b57cec5SDimitry Andric in MCInst as an operand).
15510b57cec5SDimitry Andric SWM32 and SWP can have base register other than stack pointer.
15520b57cec5SDimitry Andric */
Emulate_SWM16_32(llvm::MCInst & insn)15530b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_SWM16_32(llvm::MCInst &insn) {
15540b57cec5SDimitry Andric bool success = false;
15550b57cec5SDimitry Andric uint32_t src, base;
15560b57cec5SDimitry Andric uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on
15570b57cec5SDimitry Andric // no of regs to store.
15580b57cec5SDimitry Andric
15590b57cec5SDimitry Andric // Base register is second last operand of the instruction.
15600b57cec5SDimitry Andric base =
15610b57cec5SDimitry Andric m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
15620b57cec5SDimitry Andric
15630b57cec5SDimitry Andric // We are looking for sp based stores so if base is not a stack pointer then
15640b57cec5SDimitry Andric // don't proceed.
15650b57cec5SDimitry Andric if (base != dwarf_sp_mips)
15660b57cec5SDimitry Andric return false;
15670b57cec5SDimitry Andric
15680b57cec5SDimitry Andric // offset is always the last operand.
15690b57cec5SDimitry Andric uint32_t offset = insn.getOperand(num_operands - 1).getImm();
15700b57cec5SDimitry Andric
1571bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_base =
1572bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1573bdd1243dSDimitry Andric if (!reg_info_base)
15740b57cec5SDimitry Andric return false;
15750b57cec5SDimitry Andric
15760b57cec5SDimitry Andric // read SP
15770b57cec5SDimitry Andric uint32_t base_address = ReadRegisterUnsigned(
15780b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
15790b57cec5SDimitry Andric if (!success)
15800b57cec5SDimitry Andric return false;
15810b57cec5SDimitry Andric
15820b57cec5SDimitry Andric // Resulting base addrss
15830b57cec5SDimitry Andric base_address = base_address + offset;
15840b57cec5SDimitry Andric
15850b57cec5SDimitry Andric // Total no of registers to be stored are num_operands-2.
15860b57cec5SDimitry Andric for (uint32_t i = 0; i < num_operands - 2; i++) {
15870b57cec5SDimitry Andric // Get the register number to be stored.
15880b57cec5SDimitry Andric src = m_reg_info->getEncodingValue(insn.getOperand(i).getReg());
15890b57cec5SDimitry Andric
15900b57cec5SDimitry Andric /*
15910b57cec5SDimitry Andric Record only non-volatile stores.
15920b57cec5SDimitry Andric This check is required for SWP instruction because source operand could
15930b57cec5SDimitry Andric be any register.
15940b57cec5SDimitry Andric SWM16 and SWM32 instruction always has saved registers as source
15950b57cec5SDimitry Andric operands.
15960b57cec5SDimitry Andric */
15970b57cec5SDimitry Andric if (!nonvolatile_reg_p(src))
15980b57cec5SDimitry Andric return false;
15990b57cec5SDimitry Andric
1600bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_src =
1601bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1602bdd1243dSDimitry Andric if (!reg_info_src)
16030b57cec5SDimitry Andric return false;
16040b57cec5SDimitry Andric
16050b57cec5SDimitry Andric Context context;
16060b57cec5SDimitry Andric context.type = eContextPushRegisterOnStack;
1607bdd1243dSDimitry Andric context.SetRegisterToRegisterPlusOffset(*reg_info_src, *reg_info_base, 0);
16080b57cec5SDimitry Andric
1609*06c3fb27SDimitry Andric RegisterValue::BytesContainer buffer(reg_info_src->byte_size);
16100b57cec5SDimitry Andric Status error;
16110b57cec5SDimitry Andric
1612bdd1243dSDimitry Andric std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1613bdd1243dSDimitry Andric if (!data_src)
16140b57cec5SDimitry Andric return false;
16150b57cec5SDimitry Andric
1616*06c3fb27SDimitry Andric if (data_src->GetAsMemoryData(*reg_info_src, buffer.data(),
1617bdd1243dSDimitry Andric reg_info_src->byte_size, eByteOrderLittle,
1618bdd1243dSDimitry Andric error) == 0)
16190b57cec5SDimitry Andric return false;
16200b57cec5SDimitry Andric
1621*06c3fb27SDimitry Andric if (!WriteMemory(context, base_address, buffer.data(),
1622*06c3fb27SDimitry Andric reg_info_src->byte_size))
16230b57cec5SDimitry Andric return false;
16240b57cec5SDimitry Andric
16250b57cec5SDimitry Andric // Stack address for next register
1626bdd1243dSDimitry Andric base_address = base_address + reg_info_src->byte_size;
16270b57cec5SDimitry Andric }
16280b57cec5SDimitry Andric return true;
16290b57cec5SDimitry Andric }
16300b57cec5SDimitry Andric
Emulate_LWSP(llvm::MCInst & insn)16310b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LWSP(llvm::MCInst &insn) {
16320b57cec5SDimitry Andric bool success = false;
16330b57cec5SDimitry Andric uint32_t src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
16340b57cec5SDimitry Andric uint32_t base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
16350b57cec5SDimitry Andric uint32_t imm5 = insn.getOperand(2).getImm();
16360b57cec5SDimitry Andric Context bad_vaddr_context;
16370b57cec5SDimitry Andric
1638bdd1243dSDimitry Andric if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
16390b57cec5SDimitry Andric return false;
16400b57cec5SDimitry Andric
16410b57cec5SDimitry Andric // read base register
16420b57cec5SDimitry Andric uint32_t base_address = ReadRegisterUnsigned(
16430b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
16440b57cec5SDimitry Andric if (!success)
16450b57cec5SDimitry Andric return false;
16460b57cec5SDimitry Andric
16470b57cec5SDimitry Andric base_address = base_address + imm5;
16480b57cec5SDimitry Andric
16490b57cec5SDimitry Andric // We use bad_vaddr_context to store base address which is used by H/W
16500b57cec5SDimitry Andric // watchpoint Set the bad_vaddr register with base address used in the
16510b57cec5SDimitry Andric // instruction
16520b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
16530b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
16540b57cec5SDimitry Andric base_address);
16550b57cec5SDimitry Andric
16560b57cec5SDimitry Andric if (base == dwarf_sp_mips && nonvolatile_reg_p(src)) {
16570b57cec5SDimitry Andric RegisterValue data_src;
1658bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_src =
1659bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1660bdd1243dSDimitry Andric if (!reg_info_src)
16610b57cec5SDimitry Andric return false;
16620b57cec5SDimitry Andric
16630b57cec5SDimitry Andric Context context;
16640b57cec5SDimitry Andric context.type = eContextPopRegisterOffStack;
16650b57cec5SDimitry Andric context.SetAddress(base_address);
16660b57cec5SDimitry Andric
1667bdd1243dSDimitry Andric return WriteRegister(context, *reg_info_src, data_src);
16680b57cec5SDimitry Andric }
16690b57cec5SDimitry Andric
16700b57cec5SDimitry Andric return false;
16710b57cec5SDimitry Andric }
16720b57cec5SDimitry Andric
16730b57cec5SDimitry Andric /* Emulate LWM16, LWM32 and LWP instructions.
16740b57cec5SDimitry Andric
16750b57cec5SDimitry Andric LWM16 always has stack pointer as a base register (but it is still available
16760b57cec5SDimitry Andric in MCInst as an operand).
16770b57cec5SDimitry Andric LWM32 and LWP can have base register other than stack pointer.
16780b57cec5SDimitry Andric */
Emulate_LWM16_32(llvm::MCInst & insn)16790b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LWM16_32(llvm::MCInst &insn) {
16800b57cec5SDimitry Andric bool success = false;
16810b57cec5SDimitry Andric uint32_t dst, base;
16820b57cec5SDimitry Andric uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on
16830b57cec5SDimitry Andric // no of regs to store.
16840b57cec5SDimitry Andric uint32_t imm = insn.getOperand(num_operands - 1)
16850b57cec5SDimitry Andric .getImm(); // imm is the last operand in the instruction.
16860b57cec5SDimitry Andric
16870b57cec5SDimitry Andric // Base register is second last operand of the instruction.
16880b57cec5SDimitry Andric base =
16890b57cec5SDimitry Andric m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
16900b57cec5SDimitry Andric
16910b57cec5SDimitry Andric // We are looking for sp based loads so if base is not a stack pointer then
16920b57cec5SDimitry Andric // don't proceed.
16930b57cec5SDimitry Andric if (base != dwarf_sp_mips)
16940b57cec5SDimitry Andric return false;
16950b57cec5SDimitry Andric
16960b57cec5SDimitry Andric uint32_t base_address = ReadRegisterUnsigned(
16970b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
16980b57cec5SDimitry Andric if (!success)
16990b57cec5SDimitry Andric return false;
17000b57cec5SDimitry Andric
17010b57cec5SDimitry Andric base_address = base_address + imm;
17020b57cec5SDimitry Andric
17030b57cec5SDimitry Andric RegisterValue data_dst;
17040b57cec5SDimitry Andric
17050b57cec5SDimitry Andric // Total no of registers to be re-stored are num_operands-2.
17060b57cec5SDimitry Andric for (uint32_t i = 0; i < num_operands - 2; i++) {
17070b57cec5SDimitry Andric // Get the register number to be re-stored.
17080b57cec5SDimitry Andric dst = m_reg_info->getEncodingValue(insn.getOperand(i).getReg());
17090b57cec5SDimitry Andric
17100b57cec5SDimitry Andric /*
17110b57cec5SDimitry Andric Record only non-volatile loads.
17120b57cec5SDimitry Andric This check is required for LWP instruction because destination operand
17130b57cec5SDimitry Andric could be any register.
17140b57cec5SDimitry Andric LWM16 and LWM32 instruction always has saved registers as destination
17150b57cec5SDimitry Andric operands.
17160b57cec5SDimitry Andric */
17170b57cec5SDimitry Andric if (!nonvolatile_reg_p(dst))
17180b57cec5SDimitry Andric return false;
17190b57cec5SDimitry Andric
1720bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_dst =
1721bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + dst);
1722bdd1243dSDimitry Andric if (!reg_info_dst)
17230b57cec5SDimitry Andric return false;
17240b57cec5SDimitry Andric
17250b57cec5SDimitry Andric Context context;
17260b57cec5SDimitry Andric context.type = eContextPopRegisterOffStack;
17270b57cec5SDimitry Andric context.SetAddress(base_address + (i * 4));
17280b57cec5SDimitry Andric
1729bdd1243dSDimitry Andric if (!WriteRegister(context, *reg_info_dst, data_dst))
17300b57cec5SDimitry Andric return false;
17310b57cec5SDimitry Andric }
17320b57cec5SDimitry Andric
17330b57cec5SDimitry Andric return true;
17340b57cec5SDimitry Andric }
17350b57cec5SDimitry Andric
Emulate_JRADDIUSP(llvm::MCInst & insn)17360b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JRADDIUSP(llvm::MCInst &insn) {
17370b57cec5SDimitry Andric bool success = false;
17380b57cec5SDimitry Andric int32_t imm5 = insn.getOperand(0).getImm();
17390b57cec5SDimitry Andric
17400b57cec5SDimitry Andric /* JRADDIUSP immediate
17410b57cec5SDimitry Andric * PC <- RA
17420b57cec5SDimitry Andric * SP <- SP + zero_extend(Immediate << 2)
17430b57cec5SDimitry Andric */
17440b57cec5SDimitry Andric
17450b57cec5SDimitry Andric // This instruction operates implicitly on stack pointer, so read <sp>
17460b57cec5SDimitry Andric // register.
17470b57cec5SDimitry Andric int32_t src_opd_val =
17480b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_sp_mips, 0, &success);
17490b57cec5SDimitry Andric if (!success)
17500b57cec5SDimitry Andric return false;
17510b57cec5SDimitry Andric
17520b57cec5SDimitry Andric int32_t ra_val =
17530b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_ra_mips, 0, &success);
17540b57cec5SDimitry Andric if (!success)
17550b57cec5SDimitry Andric return false;
17560b57cec5SDimitry Andric
17570b57cec5SDimitry Andric int32_t result = src_opd_val + imm5;
17580b57cec5SDimitry Andric
17590b57cec5SDimitry Andric Context context;
17600b57cec5SDimitry Andric
17610b57cec5SDimitry Andric // Update the PC
17620b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
17630b57cec5SDimitry Andric ra_val))
17640b57cec5SDimitry Andric return false;
17650b57cec5SDimitry Andric
1766bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_sp =
1767bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1768bdd1243dSDimitry Andric if (reg_info_sp)
1769bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_sp, imm5);
17700b57cec5SDimitry Andric
17710b57cec5SDimitry Andric // We are adjusting stack
17720b57cec5SDimitry Andric context.type = eContextAdjustStackPointer;
17730b57cec5SDimitry Andric
17740b57cec5SDimitry Andric // update SP
17750b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips,
17760b57cec5SDimitry Andric result);
17770b57cec5SDimitry Andric }
17780b57cec5SDimitry Andric
IsAdd64bitOverflow(int32_t a,int32_t b)17790b57cec5SDimitry Andric static int IsAdd64bitOverflow(int32_t a, int32_t b) {
17800b57cec5SDimitry Andric int32_t r = (uint32_t)a + (uint32_t)b;
17810b57cec5SDimitry Andric return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
17820b57cec5SDimitry Andric }
17830b57cec5SDimitry Andric
17840b57cec5SDimitry Andric /*
17850b57cec5SDimitry Andric Emulate below MIPS branch instructions.
17860b57cec5SDimitry Andric BEQ, BNE : Branch on condition
17870b57cec5SDimitry Andric BEQL, BNEL : Branch likely
17880b57cec5SDimitry Andric */
Emulate_BXX_3ops(llvm::MCInst & insn)17890b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BXX_3ops(llvm::MCInst &insn) {
17900b57cec5SDimitry Andric bool success = false;
17910b57cec5SDimitry Andric uint32_t rs, rt;
17920b57cec5SDimitry Andric int32_t offset, pc, target = 0, rs_val, rt_val;
179381ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
17940b57cec5SDimitry Andric
17950b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
17960b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
17970b57cec5SDimitry Andric offset = insn.getOperand(2).getImm();
17980b57cec5SDimitry Andric
17990b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
18000b57cec5SDimitry Andric if (!success)
18010b57cec5SDimitry Andric return false;
18020b57cec5SDimitry Andric
18030b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
18040b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
18050b57cec5SDimitry Andric if (!success)
18060b57cec5SDimitry Andric return false;
18070b57cec5SDimitry Andric
18080b57cec5SDimitry Andric rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
18090b57cec5SDimitry Andric dwarf_zero_mips + rt, 0, &success);
18100b57cec5SDimitry Andric if (!success)
18110b57cec5SDimitry Andric return false;
18120b57cec5SDimitry Andric
181381ad6265SDimitry Andric if (op_name.equals_insensitive("BEQ") || op_name.equals_insensitive("BEQL")) {
18140b57cec5SDimitry Andric if (rs_val == rt_val)
18150b57cec5SDimitry Andric target = pc + offset;
18160b57cec5SDimitry Andric else
18170b57cec5SDimitry Andric target = pc + 8;
181881ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNE") ||
181981ad6265SDimitry Andric op_name.equals_insensitive("BNEL")) {
18200b57cec5SDimitry Andric if (rs_val != rt_val)
18210b57cec5SDimitry Andric target = pc + offset;
18220b57cec5SDimitry Andric else
18230b57cec5SDimitry Andric target = pc + 8;
18240b57cec5SDimitry Andric }
18250b57cec5SDimitry Andric
18260b57cec5SDimitry Andric Context context;
18270b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
18280b57cec5SDimitry Andric context.SetImmediate(offset);
18290b57cec5SDimitry Andric
18300b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
18310b57cec5SDimitry Andric target);
18320b57cec5SDimitry Andric }
18330b57cec5SDimitry Andric
18340b57cec5SDimitry Andric /*
18350b57cec5SDimitry Andric Emulate below MIPS branch instructions.
18360b57cec5SDimitry Andric BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch
18370b57cec5SDimitry Andric instructions with no delay slot
18380b57cec5SDimitry Andric */
Emulate_BXX_3ops_C(llvm::MCInst & insn)18390b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BXX_3ops_C(llvm::MCInst &insn) {
18400b57cec5SDimitry Andric bool success = false;
18410b57cec5SDimitry Andric uint32_t rs, rt;
18420b57cec5SDimitry Andric int32_t offset, pc, target = 0, rs_val, rt_val;
184381ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
18440b57cec5SDimitry Andric uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
18450b57cec5SDimitry Andric
18460b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
18470b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
18480b57cec5SDimitry Andric offset = insn.getOperand(2).getImm();
18490b57cec5SDimitry Andric
18500b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
18510b57cec5SDimitry Andric if (!success)
18520b57cec5SDimitry Andric return false;
18530b57cec5SDimitry Andric
18540b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
18550b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
18560b57cec5SDimitry Andric if (!success)
18570b57cec5SDimitry Andric return false;
18580b57cec5SDimitry Andric
18590b57cec5SDimitry Andric rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
18600b57cec5SDimitry Andric dwarf_zero_mips + rt, 0, &success);
18610b57cec5SDimitry Andric if (!success)
18620b57cec5SDimitry Andric return false;
18630b57cec5SDimitry Andric
186481ad6265SDimitry Andric if (op_name.equals_insensitive("BEQC")) {
18650b57cec5SDimitry Andric if (rs_val == rt_val)
18660b57cec5SDimitry Andric target = pc + offset;
18670b57cec5SDimitry Andric else
18680b57cec5SDimitry Andric target = pc + 4;
186981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNEC")) {
18700b57cec5SDimitry Andric if (rs_val != rt_val)
18710b57cec5SDimitry Andric target = pc + offset;
18720b57cec5SDimitry Andric else
18730b57cec5SDimitry Andric target = pc + 4;
187481ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLTC")) {
18750b57cec5SDimitry Andric if (rs_val < rt_val)
18760b57cec5SDimitry Andric target = pc + offset;
18770b57cec5SDimitry Andric else
18780b57cec5SDimitry Andric target = pc + 4;
187981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEC")) {
18800b57cec5SDimitry Andric if (rs_val >= rt_val)
18810b57cec5SDimitry Andric target = pc + offset;
18820b57cec5SDimitry Andric else
18830b57cec5SDimitry Andric target = pc + 4;
188481ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLTUC")) {
18850b57cec5SDimitry Andric if (rs_val < rt_val)
18860b57cec5SDimitry Andric target = pc + offset;
18870b57cec5SDimitry Andric else
18880b57cec5SDimitry Andric target = pc + 4;
188981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEUC")) {
18900b57cec5SDimitry Andric if ((uint32_t)rs_val >= (uint32_t)rt_val)
18910b57cec5SDimitry Andric target = pc + offset;
18920b57cec5SDimitry Andric else
18930b57cec5SDimitry Andric target = pc + 4;
189481ad6265SDimitry Andric } else if (op_name.equals_insensitive("BOVC")) {
18950b57cec5SDimitry Andric if (IsAdd64bitOverflow(rs_val, rt_val))
18960b57cec5SDimitry Andric target = pc + offset;
18970b57cec5SDimitry Andric else
18980b57cec5SDimitry Andric target = pc + 4;
189981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNVC")) {
19000b57cec5SDimitry Andric if (!IsAdd64bitOverflow(rs_val, rt_val))
19010b57cec5SDimitry Andric target = pc + offset;
19020b57cec5SDimitry Andric else
19030b57cec5SDimitry Andric target = pc + 4;
19040b57cec5SDimitry Andric }
19050b57cec5SDimitry Andric
19060b57cec5SDimitry Andric Context context;
19070b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
19080b57cec5SDimitry Andric context.SetImmediate(current_inst_size + offset);
19090b57cec5SDimitry Andric
19100b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
19110b57cec5SDimitry Andric target);
19120b57cec5SDimitry Andric }
19130b57cec5SDimitry Andric
19140b57cec5SDimitry Andric /*
19150b57cec5SDimitry Andric Emulate below MIPS conditional branch and link instructions.
19160b57cec5SDimitry Andric BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches
19170b57cec5SDimitry Andric */
Emulate_Bcond_Link_C(llvm::MCInst & insn)19180b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_Bcond_Link_C(llvm::MCInst &insn) {
19190b57cec5SDimitry Andric bool success = false;
19200b57cec5SDimitry Andric uint32_t rs;
19210b57cec5SDimitry Andric int32_t offset, pc, target = 0;
19220b57cec5SDimitry Andric int32_t rs_val;
192381ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
19240b57cec5SDimitry Andric
19250b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
19260b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
19270b57cec5SDimitry Andric
19280b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
19290b57cec5SDimitry Andric if (!success)
19300b57cec5SDimitry Andric return false;
19310b57cec5SDimitry Andric
19320b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
19330b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
19340b57cec5SDimitry Andric if (!success)
19350b57cec5SDimitry Andric return false;
19360b57cec5SDimitry Andric
193781ad6265SDimitry Andric if (op_name.equals_insensitive("BLEZALC")) {
19380b57cec5SDimitry Andric if (rs_val <= 0)
19390b57cec5SDimitry Andric target = pc + offset;
19400b57cec5SDimitry Andric else
19410b57cec5SDimitry Andric target = pc + 4;
194281ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEZALC")) {
19430b57cec5SDimitry Andric if (rs_val >= 0)
19440b57cec5SDimitry Andric target = pc + offset;
19450b57cec5SDimitry Andric else
19460b57cec5SDimitry Andric target = pc + 4;
194781ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLTZALC")) {
19480b57cec5SDimitry Andric if (rs_val < 0)
19490b57cec5SDimitry Andric target = pc + offset;
19500b57cec5SDimitry Andric else
19510b57cec5SDimitry Andric target = pc + 4;
195281ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGTZALC")) {
19530b57cec5SDimitry Andric if (rs_val > 0)
19540b57cec5SDimitry Andric target = pc + offset;
19550b57cec5SDimitry Andric else
19560b57cec5SDimitry Andric target = pc + 4;
195781ad6265SDimitry Andric } else if (op_name.equals_insensitive("BEQZALC")) {
19580b57cec5SDimitry Andric if (rs_val == 0)
19590b57cec5SDimitry Andric target = pc + offset;
19600b57cec5SDimitry Andric else
19610b57cec5SDimitry Andric target = pc + 4;
196281ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNEZALC")) {
19630b57cec5SDimitry Andric if (rs_val != 0)
19640b57cec5SDimitry Andric target = pc + offset;
19650b57cec5SDimitry Andric else
19660b57cec5SDimitry Andric target = pc + 4;
19670b57cec5SDimitry Andric }
19680b57cec5SDimitry Andric
19690b57cec5SDimitry Andric Context context;
19700b57cec5SDimitry Andric
19710b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
19720b57cec5SDimitry Andric target))
19730b57cec5SDimitry Andric return false;
19740b57cec5SDimitry Andric
19750b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
19760b57cec5SDimitry Andric pc + 4))
19770b57cec5SDimitry Andric return false;
19780b57cec5SDimitry Andric
19790b57cec5SDimitry Andric return true;
19800b57cec5SDimitry Andric }
19810b57cec5SDimitry Andric
19820b57cec5SDimitry Andric /*
19830b57cec5SDimitry Andric Emulate below MIPS Non-Compact conditional branch and link instructions.
19840b57cec5SDimitry Andric BLTZAL, BGEZAL :
19850b57cec5SDimitry Andric BLTZALL, BGEZALL : Branch likely
19860b57cec5SDimitry Andric */
Emulate_Bcond_Link(llvm::MCInst & insn)19870b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_Bcond_Link(llvm::MCInst &insn) {
19880b57cec5SDimitry Andric bool success = false;
19890b57cec5SDimitry Andric uint32_t rs;
19900b57cec5SDimitry Andric int32_t offset, pc, target = 0;
19910b57cec5SDimitry Andric int32_t rs_val;
199281ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
19930b57cec5SDimitry Andric
19940b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
19950b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
19960b57cec5SDimitry Andric
19970b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
19980b57cec5SDimitry Andric if (!success)
19990b57cec5SDimitry Andric return false;
20000b57cec5SDimitry Andric
20010b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
20020b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
20030b57cec5SDimitry Andric if (!success)
20040b57cec5SDimitry Andric return false;
20050b57cec5SDimitry Andric
200681ad6265SDimitry Andric if (op_name.equals_insensitive("BLTZAL") ||
200781ad6265SDimitry Andric op_name.equals_insensitive("BLTZALL")) {
20080b57cec5SDimitry Andric if ((int32_t)rs_val < 0)
20090b57cec5SDimitry Andric target = pc + offset;
20100b57cec5SDimitry Andric else
20110b57cec5SDimitry Andric target = pc + 8;
201281ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEZAL") ||
201381ad6265SDimitry Andric op_name.equals_insensitive("BGEZALL")) {
20140b57cec5SDimitry Andric if ((int32_t)rs_val >= 0)
20150b57cec5SDimitry Andric target = pc + offset;
20160b57cec5SDimitry Andric else
20170b57cec5SDimitry Andric target = pc + 8;
20180b57cec5SDimitry Andric }
20190b57cec5SDimitry Andric
20200b57cec5SDimitry Andric Context context;
20210b57cec5SDimitry Andric
20220b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
20230b57cec5SDimitry Andric target))
20240b57cec5SDimitry Andric return false;
20250b57cec5SDimitry Andric
20260b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
20270b57cec5SDimitry Andric pc + 8))
20280b57cec5SDimitry Andric return false;
20290b57cec5SDimitry Andric
20300b57cec5SDimitry Andric return true;
20310b57cec5SDimitry Andric }
20320b57cec5SDimitry Andric
20330b57cec5SDimitry Andric /*
20340b57cec5SDimitry Andric Emulate below MIPS branch instructions.
20350b57cec5SDimitry Andric BLTZL, BGEZL, BGTZL, BLEZL : Branch likely
20360b57cec5SDimitry Andric BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches
20370b57cec5SDimitry Andric */
Emulate_BXX_2ops(llvm::MCInst & insn)20380b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BXX_2ops(llvm::MCInst &insn) {
20390b57cec5SDimitry Andric bool success = false;
20400b57cec5SDimitry Andric uint32_t rs;
20410b57cec5SDimitry Andric int32_t offset, pc, target = 0;
20420b57cec5SDimitry Andric int32_t rs_val;
204381ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
20440b57cec5SDimitry Andric
20450b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
20460b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
20470b57cec5SDimitry Andric
20480b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
20490b57cec5SDimitry Andric if (!success)
20500b57cec5SDimitry Andric return false;
20510b57cec5SDimitry Andric
20520b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
20530b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
20540b57cec5SDimitry Andric if (!success)
20550b57cec5SDimitry Andric return false;
20560b57cec5SDimitry Andric
205781ad6265SDimitry Andric if (op_name.equals_insensitive("BLTZL") ||
205881ad6265SDimitry Andric op_name.equals_insensitive("BLTZ")) {
20590b57cec5SDimitry Andric if (rs_val < 0)
20600b57cec5SDimitry Andric target = pc + offset;
20610b57cec5SDimitry Andric else
20620b57cec5SDimitry Andric target = pc + 8;
206381ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEZL") ||
206481ad6265SDimitry Andric op_name.equals_insensitive("BGEZ")) {
20650b57cec5SDimitry Andric if (rs_val >= 0)
20660b57cec5SDimitry Andric target = pc + offset;
20670b57cec5SDimitry Andric else
20680b57cec5SDimitry Andric target = pc + 8;
206981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGTZL") ||
207081ad6265SDimitry Andric op_name.equals_insensitive("BGTZ")) {
20710b57cec5SDimitry Andric if (rs_val > 0)
20720b57cec5SDimitry Andric target = pc + offset;
20730b57cec5SDimitry Andric else
20740b57cec5SDimitry Andric target = pc + 8;
207581ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLEZL") ||
207681ad6265SDimitry Andric op_name.equals_insensitive("BLEZ")) {
20770b57cec5SDimitry Andric if (rs_val <= 0)
20780b57cec5SDimitry Andric target = pc + offset;
20790b57cec5SDimitry Andric else
20800b57cec5SDimitry Andric target = pc + 8;
20810b57cec5SDimitry Andric }
20820b57cec5SDimitry Andric
20830b57cec5SDimitry Andric Context context;
20840b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
20850b57cec5SDimitry Andric context.SetImmediate(offset);
20860b57cec5SDimitry Andric
20870b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
20880b57cec5SDimitry Andric target);
20890b57cec5SDimitry Andric }
20900b57cec5SDimitry Andric
20910b57cec5SDimitry Andric /*
20920b57cec5SDimitry Andric Emulate below MIPS branch instructions.
20930b57cec5SDimitry Andric BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches
20940b57cec5SDimitry Andric */
Emulate_BXX_2ops_C(llvm::MCInst & insn)20950b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BXX_2ops_C(llvm::MCInst &insn) {
20960b57cec5SDimitry Andric bool success = false;
20970b57cec5SDimitry Andric uint32_t rs;
20980b57cec5SDimitry Andric int32_t offset, pc, target = 0;
20990b57cec5SDimitry Andric int32_t rs_val;
210081ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
21010b57cec5SDimitry Andric uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
21020b57cec5SDimitry Andric
21030b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
21040b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
21050b57cec5SDimitry Andric
21060b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
21070b57cec5SDimitry Andric if (!success)
21080b57cec5SDimitry Andric return false;
21090b57cec5SDimitry Andric
21100b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
21110b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
21120b57cec5SDimitry Andric if (!success)
21130b57cec5SDimitry Andric return false;
21140b57cec5SDimitry Andric
211581ad6265SDimitry Andric if (op_name.equals_insensitive("BLTZC")) {
21160b57cec5SDimitry Andric if (rs_val < 0)
21170b57cec5SDimitry Andric target = pc + offset;
21180b57cec5SDimitry Andric else
21190b57cec5SDimitry Andric target = pc + 4;
212081ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLEZC")) {
21210b57cec5SDimitry Andric if (rs_val <= 0)
21220b57cec5SDimitry Andric target = pc + offset;
21230b57cec5SDimitry Andric else
21240b57cec5SDimitry Andric target = pc + 4;
212581ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEZC")) {
21260b57cec5SDimitry Andric if (rs_val >= 0)
21270b57cec5SDimitry Andric target = pc + offset;
21280b57cec5SDimitry Andric else
21290b57cec5SDimitry Andric target = pc + 4;
213081ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGTZC")) {
21310b57cec5SDimitry Andric if (rs_val > 0)
21320b57cec5SDimitry Andric target = pc + offset;
21330b57cec5SDimitry Andric else
21340b57cec5SDimitry Andric target = pc + 4;
213581ad6265SDimitry Andric } else if (op_name.equals_insensitive("BEQZC")) {
21360b57cec5SDimitry Andric if (rs_val == 0)
21370b57cec5SDimitry Andric target = pc + offset;
21380b57cec5SDimitry Andric else
21390b57cec5SDimitry Andric target = pc + 4;
214081ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNEZC")) {
21410b57cec5SDimitry Andric if (rs_val != 0)
21420b57cec5SDimitry Andric target = pc + offset;
21430b57cec5SDimitry Andric else
21440b57cec5SDimitry Andric target = pc + 4;
21450b57cec5SDimitry Andric }
21460b57cec5SDimitry Andric
21470b57cec5SDimitry Andric Context context;
21480b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
21490b57cec5SDimitry Andric context.SetImmediate(current_inst_size + offset);
21500b57cec5SDimitry Andric
21510b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
21520b57cec5SDimitry Andric target);
21530b57cec5SDimitry Andric }
21540b57cec5SDimitry Andric
Emulate_B16_MM(llvm::MCInst & insn)21550b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_B16_MM(llvm::MCInst &insn) {
21560b57cec5SDimitry Andric bool success = false;
21570b57cec5SDimitry Andric int32_t offset, pc, target;
21580b57cec5SDimitry Andric uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
21590b57cec5SDimitry Andric
21600b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
21610b57cec5SDimitry Andric
21620b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
21630b57cec5SDimitry Andric if (!success)
21640b57cec5SDimitry Andric return false;
21650b57cec5SDimitry Andric
21660b57cec5SDimitry Andric // unconditional branch
21670b57cec5SDimitry Andric target = pc + offset;
21680b57cec5SDimitry Andric
21690b57cec5SDimitry Andric Context context;
21700b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
21710b57cec5SDimitry Andric context.SetImmediate(current_inst_size + offset);
21720b57cec5SDimitry Andric
21730b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
21740b57cec5SDimitry Andric target);
21750b57cec5SDimitry Andric }
21760b57cec5SDimitry Andric
21770b57cec5SDimitry Andric /*
21780b57cec5SDimitry Andric BEQZC, BNEZC are 32 bit compact instructions without a delay slot.
21790b57cec5SDimitry Andric BEQZ16, BNEZ16 are 16 bit instructions with delay slot.
21800b57cec5SDimitry Andric BGEZALS, BLTZALS are 16 bit instructions with short (2-byte) delay slot.
21810b57cec5SDimitry Andric */
Emulate_Branch_MM(llvm::MCInst & insn)21820b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_Branch_MM(llvm::MCInst &insn) {
21830b57cec5SDimitry Andric bool success = false;
21840b57cec5SDimitry Andric int32_t target = 0;
21850b57cec5SDimitry Andric uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
218681ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
21870b57cec5SDimitry Andric bool update_ra = false;
21880b57cec5SDimitry Andric uint32_t ra_offset = 0;
21890b57cec5SDimitry Andric
21900b57cec5SDimitry Andric /*
21910b57cec5SDimitry Andric * BEQZ16 rs, offset
21920b57cec5SDimitry Andric * condition <- (GPR[rs] = 0)
21930b57cec5SDimitry Andric * if condition then
21940b57cec5SDimitry Andric * PC = PC + sign_ext (offset || 0)
21950b57cec5SDimitry Andric *
21960b57cec5SDimitry Andric * BNEZ16 rs, offset
21970b57cec5SDimitry Andric * condition <- (GPR[rs] != 0)
21980b57cec5SDimitry Andric * if condition then
21990b57cec5SDimitry Andric * PC = PC + sign_ext (offset || 0)
22000b57cec5SDimitry Andric *
22010b57cec5SDimitry Andric * BEQZC rs, offset (compact instruction: No delay slot)
22020b57cec5SDimitry Andric * condition <- (GPR[rs] == 0)
22030b57cec5SDimitry Andric * if condition then
22040b57cec5SDimitry Andric * PC = PC + 4 + sign_ext (offset || 0)
22050b57cec5SDimitry Andric */
22060b57cec5SDimitry Andric
22070b57cec5SDimitry Andric uint32_t rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
22080b57cec5SDimitry Andric int32_t offset = insn.getOperand(1).getImm();
22090b57cec5SDimitry Andric
22100b57cec5SDimitry Andric int32_t pc =
22110b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
22120b57cec5SDimitry Andric if (!success)
22130b57cec5SDimitry Andric return false;
22140b57cec5SDimitry Andric
22150b57cec5SDimitry Andric int32_t rs_val = (int32_t)ReadRegisterUnsigned(
22160b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
22170b57cec5SDimitry Andric if (!success)
22180b57cec5SDimitry Andric return false;
22190b57cec5SDimitry Andric
222081ad6265SDimitry Andric if (op_name.equals_insensitive("BEQZ16_MM")) {
22210b57cec5SDimitry Andric if (rs_val == 0)
22220b57cec5SDimitry Andric target = pc + offset;
22230b57cec5SDimitry Andric else
22240b57cec5SDimitry Andric target = pc + current_inst_size +
22250b57cec5SDimitry Andric m_next_inst_size; // Skip delay slot instruction.
222681ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNEZ16_MM")) {
22270b57cec5SDimitry Andric if (rs_val != 0)
22280b57cec5SDimitry Andric target = pc + offset;
22290b57cec5SDimitry Andric else
22300b57cec5SDimitry Andric target = pc + current_inst_size +
22310b57cec5SDimitry Andric m_next_inst_size; // Skip delay slot instruction.
223281ad6265SDimitry Andric } else if (op_name.equals_insensitive("BEQZC_MM")) {
22330b57cec5SDimitry Andric if (rs_val == 0)
22340b57cec5SDimitry Andric target = pc + 4 + offset;
22350b57cec5SDimitry Andric else
22360b57cec5SDimitry Andric target =
22370b57cec5SDimitry Andric pc +
22380b57cec5SDimitry Andric 4; // 32 bit instruction and does not have delay slot instruction.
223981ad6265SDimitry Andric } else if (op_name.equals_insensitive("BNEZC_MM")) {
22400b57cec5SDimitry Andric if (rs_val != 0)
22410b57cec5SDimitry Andric target = pc + 4 + offset;
22420b57cec5SDimitry Andric else
22430b57cec5SDimitry Andric target =
22440b57cec5SDimitry Andric pc +
22450b57cec5SDimitry Andric 4; // 32 bit instruction and does not have delay slot instruction.
224681ad6265SDimitry Andric } else if (op_name.equals_insensitive("BGEZALS_MM")) {
22470b57cec5SDimitry Andric if (rs_val >= 0)
22480b57cec5SDimitry Andric target = pc + offset;
22490b57cec5SDimitry Andric else
22500b57cec5SDimitry Andric target = pc + 6; // 32 bit instruction with short (2-byte) delay slot
22510b57cec5SDimitry Andric
22520b57cec5SDimitry Andric update_ra = true;
22530b57cec5SDimitry Andric ra_offset = 6;
225481ad6265SDimitry Andric } else if (op_name.equals_insensitive("BLTZALS_MM")) {
22550b57cec5SDimitry Andric if (rs_val >= 0)
22560b57cec5SDimitry Andric target = pc + offset;
22570b57cec5SDimitry Andric else
22580b57cec5SDimitry Andric target = pc + 6; // 32 bit instruction with short (2-byte) delay slot
22590b57cec5SDimitry Andric
22600b57cec5SDimitry Andric update_ra = true;
22610b57cec5SDimitry Andric ra_offset = 6;
22620b57cec5SDimitry Andric }
22630b57cec5SDimitry Andric
22640b57cec5SDimitry Andric Context context;
22650b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
22660b57cec5SDimitry Andric context.SetImmediate(current_inst_size + offset);
22670b57cec5SDimitry Andric
22680b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
22690b57cec5SDimitry Andric target))
22700b57cec5SDimitry Andric return false;
22710b57cec5SDimitry Andric
22720b57cec5SDimitry Andric if (update_ra) {
22730b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
22740b57cec5SDimitry Andric pc + ra_offset))
22750b57cec5SDimitry Andric return false;
22760b57cec5SDimitry Andric }
22770b57cec5SDimitry Andric return true;
22780b57cec5SDimitry Andric }
22790b57cec5SDimitry Andric
22800b57cec5SDimitry Andric /* Emulate micromips jump instructions.
22810b57cec5SDimitry Andric JALR16,JALRS16
22820b57cec5SDimitry Andric */
Emulate_JALRx16_MM(llvm::MCInst & insn)22830b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JALRx16_MM(llvm::MCInst &insn) {
22840b57cec5SDimitry Andric bool success = false;
22850b57cec5SDimitry Andric uint32_t ra_offset = 0;
228681ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
22870b57cec5SDimitry Andric
22880b57cec5SDimitry Andric uint32_t rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
22890b57cec5SDimitry Andric
22900b57cec5SDimitry Andric uint32_t pc =
22910b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
22920b57cec5SDimitry Andric if (!success)
22930b57cec5SDimitry Andric return false;
22940b57cec5SDimitry Andric
22950b57cec5SDimitry Andric uint32_t rs_val = ReadRegisterUnsigned(eRegisterKindDWARF,
22960b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
22970b57cec5SDimitry Andric if (!success)
22980b57cec5SDimitry Andric return false;
22990b57cec5SDimitry Andric
230081ad6265SDimitry Andric if (op_name.equals_insensitive("JALR16_MM"))
23010b57cec5SDimitry Andric ra_offset = 6; // 2-byte instruction with 4-byte delay slot.
230281ad6265SDimitry Andric else if (op_name.equals_insensitive("JALRS16_MM"))
23030b57cec5SDimitry Andric ra_offset = 4; // 2-byte instruction with 2-byte delay slot.
23040b57cec5SDimitry Andric
23050b57cec5SDimitry Andric Context context;
23060b57cec5SDimitry Andric
23070b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
23080b57cec5SDimitry Andric rs_val))
23090b57cec5SDimitry Andric return false;
23100b57cec5SDimitry Andric
23110b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
23120b57cec5SDimitry Andric pc + ra_offset))
23130b57cec5SDimitry Andric return false;
23140b57cec5SDimitry Andric
23150b57cec5SDimitry Andric return true;
23160b57cec5SDimitry Andric }
23170b57cec5SDimitry Andric
23180b57cec5SDimitry Andric /* Emulate JALS and JALX instructions.
23190b57cec5SDimitry Andric JALS 32 bit instruction with short (2-byte) delay slot.
23200b57cec5SDimitry Andric JALX 32 bit instruction with 4-byte delay slot.
23210b57cec5SDimitry Andric */
Emulate_JALx(llvm::MCInst & insn)23220b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JALx(llvm::MCInst &insn) {
23230b57cec5SDimitry Andric bool success = false;
23240b57cec5SDimitry Andric uint32_t offset = 0, target = 0, pc = 0, ra_offset = 0;
232581ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
23260b57cec5SDimitry Andric
23270b57cec5SDimitry Andric /*
23280b57cec5SDimitry Andric * JALS target
23290b57cec5SDimitry Andric * RA = PC + 6
23300b57cec5SDimitry Andric * offset = sign_ext (offset << 1)
23310b57cec5SDimitry Andric * PC = PC[31-27] | offset
23320b57cec5SDimitry Andric * JALX target
23330b57cec5SDimitry Andric * RA = PC + 8
23340b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
23350b57cec5SDimitry Andric * PC = PC[31-28] | offset
23360b57cec5SDimitry Andric */
23370b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
23380b57cec5SDimitry Andric
23390b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
23400b57cec5SDimitry Andric if (!success)
23410b57cec5SDimitry Andric return false;
23420b57cec5SDimitry Andric
23430b57cec5SDimitry Andric // These are PC-region branches and not PC-relative.
234481ad6265SDimitry Andric if (op_name.equals_insensitive("JALS_MM")) {
23450b57cec5SDimitry Andric // target address is in the “current” 128 MB-aligned region
23460b57cec5SDimitry Andric target = (pc & 0xF8000000UL) | offset;
23470b57cec5SDimitry Andric ra_offset = 6;
234881ad6265SDimitry Andric } else if (op_name.equals_insensitive("JALX_MM")) {
23490b57cec5SDimitry Andric // target address is in the “current” 256 MB-aligned region
23500b57cec5SDimitry Andric target = (pc & 0xF0000000UL) | offset;
23510b57cec5SDimitry Andric ra_offset = 8;
23520b57cec5SDimitry Andric }
23530b57cec5SDimitry Andric
23540b57cec5SDimitry Andric Context context;
23550b57cec5SDimitry Andric
23560b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
23570b57cec5SDimitry Andric target))
23580b57cec5SDimitry Andric return false;
23590b57cec5SDimitry Andric
23600b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
23610b57cec5SDimitry Andric pc + ra_offset))
23620b57cec5SDimitry Andric return false;
23630b57cec5SDimitry Andric
23640b57cec5SDimitry Andric return true;
23650b57cec5SDimitry Andric }
23660b57cec5SDimitry Andric
Emulate_JALRS(llvm::MCInst & insn)23670b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JALRS(llvm::MCInst &insn) {
23680b57cec5SDimitry Andric bool success = false;
23690b57cec5SDimitry Andric uint32_t rs = 0, rt = 0;
23700b57cec5SDimitry Andric int32_t pc = 0, rs_val = 0;
23710b57cec5SDimitry Andric
23720b57cec5SDimitry Andric /*
23730b57cec5SDimitry Andric JALRS rt, rs
23740b57cec5SDimitry Andric GPR[rt] <- PC + 6
23750b57cec5SDimitry Andric PC <- GPR[rs]
23760b57cec5SDimitry Andric */
23770b57cec5SDimitry Andric
23780b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
23790b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
23800b57cec5SDimitry Andric
23810b57cec5SDimitry Andric rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
23820b57cec5SDimitry Andric dwarf_zero_mips + rs, 0, &success);
23830b57cec5SDimitry Andric if (!success)
23840b57cec5SDimitry Andric return false;
23850b57cec5SDimitry Andric
23860b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
23870b57cec5SDimitry Andric if (!success)
23880b57cec5SDimitry Andric return false;
23890b57cec5SDimitry Andric
23900b57cec5SDimitry Andric Context context;
23910b57cec5SDimitry Andric
23920b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
23930b57cec5SDimitry Andric rs_val))
23940b57cec5SDimitry Andric return false;
23950b57cec5SDimitry Andric
23960b57cec5SDimitry Andric // This is 4-byte instruction with 2-byte delay slot.
23970b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips + rt,
23980b57cec5SDimitry Andric pc + 6))
23990b57cec5SDimitry Andric return false;
24000b57cec5SDimitry Andric
24010b57cec5SDimitry Andric return true;
24020b57cec5SDimitry Andric }
24030b57cec5SDimitry Andric
Emulate_BAL(llvm::MCInst & insn)24040b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BAL(llvm::MCInst &insn) {
24050b57cec5SDimitry Andric bool success = false;
24060b57cec5SDimitry Andric int32_t offset, pc, target;
24070b57cec5SDimitry Andric
24080b57cec5SDimitry Andric /*
24090b57cec5SDimitry Andric * BAL offset
24100b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
24110b57cec5SDimitry Andric * RA = PC + 8
24120b57cec5SDimitry Andric * PC = PC + offset
24130b57cec5SDimitry Andric */
24140b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
24150b57cec5SDimitry Andric
24160b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
24170b57cec5SDimitry Andric if (!success)
24180b57cec5SDimitry Andric return false;
24190b57cec5SDimitry Andric
24200b57cec5SDimitry Andric target = pc + offset;
24210b57cec5SDimitry Andric
24220b57cec5SDimitry Andric Context context;
24230b57cec5SDimitry Andric
24240b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
24250b57cec5SDimitry Andric target))
24260b57cec5SDimitry Andric return false;
24270b57cec5SDimitry Andric
24280b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
24290b57cec5SDimitry Andric pc + 8))
24300b57cec5SDimitry Andric return false;
24310b57cec5SDimitry Andric
24320b57cec5SDimitry Andric return true;
24330b57cec5SDimitry Andric }
24340b57cec5SDimitry Andric
Emulate_BALC(llvm::MCInst & insn)24350b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BALC(llvm::MCInst &insn) {
24360b57cec5SDimitry Andric bool success = false;
24370b57cec5SDimitry Andric int32_t offset, pc, target;
24380b57cec5SDimitry Andric
24390b57cec5SDimitry Andric /*
24400b57cec5SDimitry Andric * BALC offset
24410b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
24420b57cec5SDimitry Andric * RA = PC + 4
24430b57cec5SDimitry Andric * PC = PC + 4 + offset
24440b57cec5SDimitry Andric */
24450b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
24460b57cec5SDimitry Andric
24470b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
24480b57cec5SDimitry Andric if (!success)
24490b57cec5SDimitry Andric return false;
24500b57cec5SDimitry Andric
24510b57cec5SDimitry Andric target = pc + offset;
24520b57cec5SDimitry Andric
24530b57cec5SDimitry Andric Context context;
24540b57cec5SDimitry Andric
24550b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
24560b57cec5SDimitry Andric target))
24570b57cec5SDimitry Andric return false;
24580b57cec5SDimitry Andric
24590b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
24600b57cec5SDimitry Andric pc + 4))
24610b57cec5SDimitry Andric return false;
24620b57cec5SDimitry Andric
24630b57cec5SDimitry Andric return true;
24640b57cec5SDimitry Andric }
24650b57cec5SDimitry Andric
Emulate_BC(llvm::MCInst & insn)24660b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BC(llvm::MCInst &insn) {
24670b57cec5SDimitry Andric bool success = false;
24680b57cec5SDimitry Andric int32_t offset, pc, target;
24690b57cec5SDimitry Andric
24700b57cec5SDimitry Andric /*
24710b57cec5SDimitry Andric * BC offset
24720b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
24730b57cec5SDimitry Andric * PC = PC + 4 + offset
24740b57cec5SDimitry Andric */
24750b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
24760b57cec5SDimitry Andric
24770b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
24780b57cec5SDimitry Andric if (!success)
24790b57cec5SDimitry Andric return false;
24800b57cec5SDimitry Andric
24810b57cec5SDimitry Andric target = pc + offset;
24820b57cec5SDimitry Andric
24830b57cec5SDimitry Andric Context context;
24840b57cec5SDimitry Andric
24850b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
24860b57cec5SDimitry Andric target);
24870b57cec5SDimitry Andric }
24880b57cec5SDimitry Andric
Emulate_J(llvm::MCInst & insn)24890b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_J(llvm::MCInst &insn) {
24900b57cec5SDimitry Andric bool success = false;
24910b57cec5SDimitry Andric uint32_t offset, pc;
24920b57cec5SDimitry Andric
24930b57cec5SDimitry Andric /*
24940b57cec5SDimitry Andric * J offset
24950b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
24960b57cec5SDimitry Andric * PC = PC[63-28] | offset
24970b57cec5SDimitry Andric */
24980b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
24990b57cec5SDimitry Andric
25000b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
25010b57cec5SDimitry Andric if (!success)
25020b57cec5SDimitry Andric return false;
25030b57cec5SDimitry Andric
25040b57cec5SDimitry Andric /* This is a PC-region branch and not PC-relative */
25050b57cec5SDimitry Andric pc = (pc & 0xF0000000UL) | offset;
25060b57cec5SDimitry Andric
25070b57cec5SDimitry Andric Context context;
25080b57cec5SDimitry Andric
25090b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, pc);
25100b57cec5SDimitry Andric }
25110b57cec5SDimitry Andric
Emulate_JAL(llvm::MCInst & insn)25120b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JAL(llvm::MCInst &insn) {
25130b57cec5SDimitry Andric bool success = false;
25140b57cec5SDimitry Andric uint32_t offset, target, pc;
25150b57cec5SDimitry Andric
25160b57cec5SDimitry Andric /*
25170b57cec5SDimitry Andric * JAL offset
25180b57cec5SDimitry Andric * offset = sign_ext (offset << 2)
25190b57cec5SDimitry Andric * PC = PC[63-28] | offset
25200b57cec5SDimitry Andric */
25210b57cec5SDimitry Andric offset = insn.getOperand(0).getImm();
25220b57cec5SDimitry Andric
25230b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
25240b57cec5SDimitry Andric if (!success)
25250b57cec5SDimitry Andric return false;
25260b57cec5SDimitry Andric
25270b57cec5SDimitry Andric /* This is a PC-region branch and not PC-relative */
25280b57cec5SDimitry Andric target = (pc & 0xF0000000UL) | offset;
25290b57cec5SDimitry Andric
25300b57cec5SDimitry Andric Context context;
25310b57cec5SDimitry Andric
25320b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
25330b57cec5SDimitry Andric target))
25340b57cec5SDimitry Andric return false;
25350b57cec5SDimitry Andric
25360b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
25370b57cec5SDimitry Andric pc + 8))
25380b57cec5SDimitry Andric return false;
25390b57cec5SDimitry Andric
25400b57cec5SDimitry Andric return true;
25410b57cec5SDimitry Andric }
25420b57cec5SDimitry Andric
Emulate_JALR(llvm::MCInst & insn)25430b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JALR(llvm::MCInst &insn) {
25440b57cec5SDimitry Andric bool success = false;
25450b57cec5SDimitry Andric uint32_t rs, rt;
25460b57cec5SDimitry Andric uint32_t pc, rs_val;
25470b57cec5SDimitry Andric
25480b57cec5SDimitry Andric /*
25490b57cec5SDimitry Andric * JALR rt, rs
25500b57cec5SDimitry Andric * GPR[rt] = PC + 8
25510b57cec5SDimitry Andric * PC = GPR[rs]
25520b57cec5SDimitry Andric */
25530b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
25540b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
25550b57cec5SDimitry Andric
25560b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
25570b57cec5SDimitry Andric if (!success)
25580b57cec5SDimitry Andric return false;
25590b57cec5SDimitry Andric
25600b57cec5SDimitry Andric rs_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + rs, 0,
25610b57cec5SDimitry Andric &success);
25620b57cec5SDimitry Andric if (!success)
25630b57cec5SDimitry Andric return false;
25640b57cec5SDimitry Andric
25650b57cec5SDimitry Andric Context context;
25660b57cec5SDimitry Andric
25670b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
25680b57cec5SDimitry Andric rs_val))
25690b57cec5SDimitry Andric return false;
25700b57cec5SDimitry Andric
25710b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips + rt,
25720b57cec5SDimitry Andric pc + 8))
25730b57cec5SDimitry Andric return false;
25740b57cec5SDimitry Andric
25750b57cec5SDimitry Andric return true;
25760b57cec5SDimitry Andric }
25770b57cec5SDimitry Andric
Emulate_JIALC(llvm::MCInst & insn)25780b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JIALC(llvm::MCInst &insn) {
25790b57cec5SDimitry Andric bool success = false;
25800b57cec5SDimitry Andric uint32_t rt;
25810b57cec5SDimitry Andric int32_t target, offset, pc, rt_val;
25820b57cec5SDimitry Andric
25830b57cec5SDimitry Andric /*
25840b57cec5SDimitry Andric * JIALC rt, offset
25850b57cec5SDimitry Andric * offset = sign_ext (offset)
25860b57cec5SDimitry Andric * PC = GPR[rt] + offset
25870b57cec5SDimitry Andric * RA = PC + 4
25880b57cec5SDimitry Andric */
25890b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
25900b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
25910b57cec5SDimitry Andric
25920b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
25930b57cec5SDimitry Andric if (!success)
25940b57cec5SDimitry Andric return false;
25950b57cec5SDimitry Andric
25960b57cec5SDimitry Andric rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
25970b57cec5SDimitry Andric dwarf_zero_mips + rt, 0, &success);
25980b57cec5SDimitry Andric if (!success)
25990b57cec5SDimitry Andric return false;
26000b57cec5SDimitry Andric
26010b57cec5SDimitry Andric target = rt_val + offset;
26020b57cec5SDimitry Andric
26030b57cec5SDimitry Andric Context context;
26040b57cec5SDimitry Andric
26050b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
26060b57cec5SDimitry Andric target))
26070b57cec5SDimitry Andric return false;
26080b57cec5SDimitry Andric
26090b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
26100b57cec5SDimitry Andric pc + 4))
26110b57cec5SDimitry Andric return false;
26120b57cec5SDimitry Andric
26130b57cec5SDimitry Andric return true;
26140b57cec5SDimitry Andric }
26150b57cec5SDimitry Andric
Emulate_JIC(llvm::MCInst & insn)26160b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JIC(llvm::MCInst &insn) {
26170b57cec5SDimitry Andric bool success = false;
26180b57cec5SDimitry Andric uint32_t rt;
26190b57cec5SDimitry Andric int32_t target, offset, rt_val;
26200b57cec5SDimitry Andric
26210b57cec5SDimitry Andric /*
26220b57cec5SDimitry Andric * JIC rt, offset
26230b57cec5SDimitry Andric * offset = sign_ext (offset)
26240b57cec5SDimitry Andric * PC = GPR[rt] + offset
26250b57cec5SDimitry Andric */
26260b57cec5SDimitry Andric rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
26270b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
26280b57cec5SDimitry Andric
26290b57cec5SDimitry Andric rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
26300b57cec5SDimitry Andric dwarf_zero_mips + rt, 0, &success);
26310b57cec5SDimitry Andric if (!success)
26320b57cec5SDimitry Andric return false;
26330b57cec5SDimitry Andric
26340b57cec5SDimitry Andric target = rt_val + offset;
26350b57cec5SDimitry Andric
26360b57cec5SDimitry Andric Context context;
26370b57cec5SDimitry Andric
26380b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
26390b57cec5SDimitry Andric target);
26400b57cec5SDimitry Andric }
26410b57cec5SDimitry Andric
Emulate_JR(llvm::MCInst & insn)26420b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_JR(llvm::MCInst &insn) {
26430b57cec5SDimitry Andric bool success = false;
26440b57cec5SDimitry Andric uint32_t rs;
26450b57cec5SDimitry Andric uint32_t rs_val;
26460b57cec5SDimitry Andric
26470b57cec5SDimitry Andric /*
26480b57cec5SDimitry Andric * JR rs
26490b57cec5SDimitry Andric * PC = GPR[rs]
26500b57cec5SDimitry Andric */
26510b57cec5SDimitry Andric rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
26520b57cec5SDimitry Andric
26530b57cec5SDimitry Andric rs_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + rs, 0,
26540b57cec5SDimitry Andric &success);
26550b57cec5SDimitry Andric if (!success)
26560b57cec5SDimitry Andric return false;
26570b57cec5SDimitry Andric
26580b57cec5SDimitry Andric Context context;
26590b57cec5SDimitry Andric
26600b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
26610b57cec5SDimitry Andric rs_val);
26620b57cec5SDimitry Andric }
26630b57cec5SDimitry Andric
26640b57cec5SDimitry Andric /*
26650b57cec5SDimitry Andric Emulate Branch on FP True/False
26660b57cec5SDimitry Andric BC1F, BC1FL : Branch on FP False (L stands for branch likely)
26670b57cec5SDimitry Andric BC1T, BC1TL : Branch on FP True (L stands for branch likely)
26680b57cec5SDimitry Andric */
Emulate_FP_branch(llvm::MCInst & insn)26690b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_FP_branch(llvm::MCInst &insn) {
26700b57cec5SDimitry Andric bool success = false;
26710b57cec5SDimitry Andric uint32_t cc, fcsr;
26720b57cec5SDimitry Andric int32_t pc, offset, target = 0;
267381ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
26740b57cec5SDimitry Andric
26750b57cec5SDimitry Andric cc = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
26760b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
26770b57cec5SDimitry Andric
26780b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
26790b57cec5SDimitry Andric if (!success)
26800b57cec5SDimitry Andric return false;
26810b57cec5SDimitry Andric
26820b57cec5SDimitry Andric fcsr = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
26830b57cec5SDimitry Andric if (!success)
26840b57cec5SDimitry Andric return false;
26850b57cec5SDimitry Andric
26860b57cec5SDimitry Andric /* fcsr[23], fcsr[25-31] are vaild condition bits */
26870b57cec5SDimitry Andric fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
26880b57cec5SDimitry Andric
268981ad6265SDimitry Andric if (op_name.equals_insensitive("BC1F") ||
269081ad6265SDimitry Andric op_name.equals_insensitive("BC1FL")) {
26910b57cec5SDimitry Andric if ((fcsr & (1 << cc)) == 0)
26920b57cec5SDimitry Andric target = pc + offset;
26930b57cec5SDimitry Andric else
26940b57cec5SDimitry Andric target = pc + 8;
269581ad6265SDimitry Andric } else if (op_name.equals_insensitive("BC1T") ||
269681ad6265SDimitry Andric op_name.equals_insensitive("BC1TL")) {
26970b57cec5SDimitry Andric if ((fcsr & (1 << cc)) != 0)
26980b57cec5SDimitry Andric target = pc + offset;
26990b57cec5SDimitry Andric else
27000b57cec5SDimitry Andric target = pc + 8;
27010b57cec5SDimitry Andric }
27020b57cec5SDimitry Andric Context context;
27030b57cec5SDimitry Andric
27040b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
27050b57cec5SDimitry Andric target);
27060b57cec5SDimitry Andric }
27070b57cec5SDimitry Andric
Emulate_BC1EQZ(llvm::MCInst & insn)27080b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BC1EQZ(llvm::MCInst &insn) {
27090b57cec5SDimitry Andric bool success = false;
27100b57cec5SDimitry Andric uint32_t ft;
27110b57cec5SDimitry Andric uint32_t ft_val;
27120b57cec5SDimitry Andric int32_t target, pc, offset;
27130b57cec5SDimitry Andric
27140b57cec5SDimitry Andric /*
27150b57cec5SDimitry Andric * BC1EQZ ft, offset
27160b57cec5SDimitry Andric * condition <- (FPR[ft].bit0 == 0)
27170b57cec5SDimitry Andric * if condition then
27180b57cec5SDimitry Andric * offset = sign_ext (offset)
27190b57cec5SDimitry Andric * PC = PC + 4 + offset
27200b57cec5SDimitry Andric */
27210b57cec5SDimitry Andric ft = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
27220b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
27230b57cec5SDimitry Andric
27240b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
27250b57cec5SDimitry Andric if (!success)
27260b57cec5SDimitry Andric return false;
27270b57cec5SDimitry Andric
27280b57cec5SDimitry Andric ft_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + ft, 0,
27290b57cec5SDimitry Andric &success);
27300b57cec5SDimitry Andric if (!success)
27310b57cec5SDimitry Andric return false;
27320b57cec5SDimitry Andric
27330b57cec5SDimitry Andric if ((ft_val & 1) == 0)
27340b57cec5SDimitry Andric target = pc + 4 + offset;
27350b57cec5SDimitry Andric else
27360b57cec5SDimitry Andric target = pc + 8;
27370b57cec5SDimitry Andric
27380b57cec5SDimitry Andric Context context;
27390b57cec5SDimitry Andric
27400b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
27410b57cec5SDimitry Andric target);
27420b57cec5SDimitry Andric }
27430b57cec5SDimitry Andric
Emulate_BC1NEZ(llvm::MCInst & insn)27440b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BC1NEZ(llvm::MCInst &insn) {
27450b57cec5SDimitry Andric bool success = false;
27460b57cec5SDimitry Andric uint32_t ft;
27470b57cec5SDimitry Andric uint32_t ft_val;
27480b57cec5SDimitry Andric int32_t target, pc, offset;
27490b57cec5SDimitry Andric
27500b57cec5SDimitry Andric /*
27510b57cec5SDimitry Andric * BC1NEZ ft, offset
27520b57cec5SDimitry Andric * condition <- (FPR[ft].bit0 != 0)
27530b57cec5SDimitry Andric * if condition then
27540b57cec5SDimitry Andric * offset = sign_ext (offset)
27550b57cec5SDimitry Andric * PC = PC + 4 + offset
27560b57cec5SDimitry Andric */
27570b57cec5SDimitry Andric ft = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
27580b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
27590b57cec5SDimitry Andric
27600b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
27610b57cec5SDimitry Andric if (!success)
27620b57cec5SDimitry Andric return false;
27630b57cec5SDimitry Andric
27640b57cec5SDimitry Andric ft_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + ft, 0,
27650b57cec5SDimitry Andric &success);
27660b57cec5SDimitry Andric if (!success)
27670b57cec5SDimitry Andric return false;
27680b57cec5SDimitry Andric
27690b57cec5SDimitry Andric if ((ft_val & 1) != 0)
27700b57cec5SDimitry Andric target = pc + 4 + offset;
27710b57cec5SDimitry Andric else
27720b57cec5SDimitry Andric target = pc + 8;
27730b57cec5SDimitry Andric
27740b57cec5SDimitry Andric Context context;
27750b57cec5SDimitry Andric
27760b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
27770b57cec5SDimitry Andric target);
27780b57cec5SDimitry Andric }
27790b57cec5SDimitry Andric
27800b57cec5SDimitry Andric /*
27810b57cec5SDimitry Andric Emulate MIPS-3D Branch instructions
27820b57cec5SDimitry Andric BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes
27830b57cec5SDimitry Andric False/True
27840b57cec5SDimitry Andric BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes
27850b57cec5SDimitry Andric False/True
27860b57cec5SDimitry Andric */
Emulate_3D_branch(llvm::MCInst & insn)27870b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_3D_branch(llvm::MCInst &insn) {
27880b57cec5SDimitry Andric bool success = false;
27890b57cec5SDimitry Andric uint32_t cc, fcsr;
27900b57cec5SDimitry Andric int32_t pc, offset, target = 0;
279181ad6265SDimitry Andric llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
27920b57cec5SDimitry Andric
27930b57cec5SDimitry Andric cc = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
27940b57cec5SDimitry Andric offset = insn.getOperand(1).getImm();
27950b57cec5SDimitry Andric
27960b57cec5SDimitry Andric pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
27970b57cec5SDimitry Andric if (!success)
27980b57cec5SDimitry Andric return false;
27990b57cec5SDimitry Andric
28000b57cec5SDimitry Andric fcsr = (uint32_t)ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_fcsr_mips, 0,
28010b57cec5SDimitry Andric &success);
28020b57cec5SDimitry Andric if (!success)
28030b57cec5SDimitry Andric return false;
28040b57cec5SDimitry Andric
28050b57cec5SDimitry Andric /* fcsr[23], fcsr[25-31] are vaild condition bits */
28060b57cec5SDimitry Andric fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
28070b57cec5SDimitry Andric
280881ad6265SDimitry Andric if (op_name.equals_insensitive("BC1ANY2F")) {
28090b57cec5SDimitry Andric /* if any one bit is 0 */
28100b57cec5SDimitry Andric if (((fcsr >> cc) & 3) != 3)
28110b57cec5SDimitry Andric target = pc + offset;
28120b57cec5SDimitry Andric else
28130b57cec5SDimitry Andric target = pc + 8;
281481ad6265SDimitry Andric } else if (op_name.equals_insensitive("BC1ANY2T")) {
28150b57cec5SDimitry Andric /* if any one bit is 1 */
28160b57cec5SDimitry Andric if (((fcsr >> cc) & 3) != 0)
28170b57cec5SDimitry Andric target = pc + offset;
28180b57cec5SDimitry Andric else
28190b57cec5SDimitry Andric target = pc + 8;
282081ad6265SDimitry Andric } else if (op_name.equals_insensitive("BC1ANY4F")) {
28210b57cec5SDimitry Andric /* if any one bit is 0 */
28220b57cec5SDimitry Andric if (((fcsr >> cc) & 0xf) != 0xf)
28230b57cec5SDimitry Andric target = pc + offset;
28240b57cec5SDimitry Andric else
28250b57cec5SDimitry Andric target = pc + 8;
282681ad6265SDimitry Andric } else if (op_name.equals_insensitive("BC1ANY4T")) {
28270b57cec5SDimitry Andric /* if any one bit is 1 */
28280b57cec5SDimitry Andric if (((fcsr >> cc) & 0xf) != 0)
28290b57cec5SDimitry Andric target = pc + offset;
28300b57cec5SDimitry Andric else
28310b57cec5SDimitry Andric target = pc + 8;
28320b57cec5SDimitry Andric }
28330b57cec5SDimitry Andric Context context;
28340b57cec5SDimitry Andric
28350b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
28360b57cec5SDimitry Andric target);
28370b57cec5SDimitry Andric }
28380b57cec5SDimitry Andric
Emulate_BNZB(llvm::MCInst & insn)28390b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BNZB(llvm::MCInst &insn) {
28400b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 1, true);
28410b57cec5SDimitry Andric }
28420b57cec5SDimitry Andric
Emulate_BNZH(llvm::MCInst & insn)28430b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BNZH(llvm::MCInst &insn) {
28440b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 2, true);
28450b57cec5SDimitry Andric }
28460b57cec5SDimitry Andric
Emulate_BNZW(llvm::MCInst & insn)28470b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BNZW(llvm::MCInst &insn) {
28480b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 4, true);
28490b57cec5SDimitry Andric }
28500b57cec5SDimitry Andric
Emulate_BNZD(llvm::MCInst & insn)28510b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BNZD(llvm::MCInst &insn) {
28520b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 8, true);
28530b57cec5SDimitry Andric }
28540b57cec5SDimitry Andric
Emulate_BZB(llvm::MCInst & insn)28550b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BZB(llvm::MCInst &insn) {
28560b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 1, false);
28570b57cec5SDimitry Andric }
28580b57cec5SDimitry Andric
Emulate_BZH(llvm::MCInst & insn)28590b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BZH(llvm::MCInst &insn) {
28600b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 2, false);
28610b57cec5SDimitry Andric }
28620b57cec5SDimitry Andric
Emulate_BZW(llvm::MCInst & insn)28630b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BZW(llvm::MCInst &insn) {
28640b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 4, false);
28650b57cec5SDimitry Andric }
28660b57cec5SDimitry Andric
Emulate_BZD(llvm::MCInst & insn)28670b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BZD(llvm::MCInst &insn) {
28680b57cec5SDimitry Andric return Emulate_MSA_Branch_DF(insn, 8, false);
28690b57cec5SDimitry Andric }
28700b57cec5SDimitry Andric
Emulate_MSA_Branch_DF(llvm::MCInst & insn,int element_byte_size,bool bnz)28710b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_MSA_Branch_DF(llvm::MCInst &insn,
28720b57cec5SDimitry Andric int element_byte_size,
28730b57cec5SDimitry Andric bool bnz) {
28740b57cec5SDimitry Andric bool success = false, branch_hit = true;
28750b57cec5SDimitry Andric int32_t target = 0;
28760b57cec5SDimitry Andric RegisterValue reg_value;
28770b57cec5SDimitry Andric const uint8_t *ptr = nullptr;
28780b57cec5SDimitry Andric
28790b57cec5SDimitry Andric uint32_t wt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
28800b57cec5SDimitry Andric int32_t offset = insn.getOperand(1).getImm();
28810b57cec5SDimitry Andric
28820b57cec5SDimitry Andric int32_t pc =
28830b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
28840b57cec5SDimitry Andric if (!success)
28850b57cec5SDimitry Andric return false;
28860b57cec5SDimitry Andric
28870b57cec5SDimitry Andric if (ReadRegister(eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value))
28880b57cec5SDimitry Andric ptr = (const uint8_t *)reg_value.GetBytes();
28890b57cec5SDimitry Andric else
28900b57cec5SDimitry Andric return false;
28910b57cec5SDimitry Andric
28920b57cec5SDimitry Andric for (int i = 0; i < 16 / element_byte_size; i++) {
28930b57cec5SDimitry Andric switch (element_byte_size) {
28940b57cec5SDimitry Andric case 1:
28950b57cec5SDimitry Andric if ((*ptr == 0 && bnz) || (*ptr != 0 && !bnz))
28960b57cec5SDimitry Andric branch_hit = false;
28970b57cec5SDimitry Andric break;
28980b57cec5SDimitry Andric case 2:
28990b57cec5SDimitry Andric if ((*(const uint16_t *)ptr == 0 && bnz) ||
29000b57cec5SDimitry Andric (*(const uint16_t *)ptr != 0 && !bnz))
29010b57cec5SDimitry Andric branch_hit = false;
29020b57cec5SDimitry Andric break;
29030b57cec5SDimitry Andric case 4:
29040b57cec5SDimitry Andric if ((*(const uint32_t *)ptr == 0 && bnz) ||
29050b57cec5SDimitry Andric (*(const uint32_t *)ptr != 0 && !bnz))
29060b57cec5SDimitry Andric branch_hit = false;
29070b57cec5SDimitry Andric break;
29080b57cec5SDimitry Andric case 8:
29090b57cec5SDimitry Andric if ((*(const uint64_t *)ptr == 0 && bnz) ||
29100b57cec5SDimitry Andric (*(const uint64_t *)ptr != 0 && !bnz))
29110b57cec5SDimitry Andric branch_hit = false;
29120b57cec5SDimitry Andric break;
29130b57cec5SDimitry Andric }
29140b57cec5SDimitry Andric if (!branch_hit)
29150b57cec5SDimitry Andric break;
29160b57cec5SDimitry Andric ptr = ptr + element_byte_size;
29170b57cec5SDimitry Andric }
29180b57cec5SDimitry Andric
29190b57cec5SDimitry Andric if (branch_hit)
29200b57cec5SDimitry Andric target = pc + offset;
29210b57cec5SDimitry Andric else
29220b57cec5SDimitry Andric target = pc + 8;
29230b57cec5SDimitry Andric
29240b57cec5SDimitry Andric Context context;
29250b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
29260b57cec5SDimitry Andric
29270b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
29280b57cec5SDimitry Andric target);
29290b57cec5SDimitry Andric }
29300b57cec5SDimitry Andric
Emulate_BNZV(llvm::MCInst & insn)29310b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BNZV(llvm::MCInst &insn) {
29320b57cec5SDimitry Andric return Emulate_MSA_Branch_V(insn, true);
29330b57cec5SDimitry Andric }
29340b57cec5SDimitry Andric
Emulate_BZV(llvm::MCInst & insn)29350b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_BZV(llvm::MCInst &insn) {
29360b57cec5SDimitry Andric return Emulate_MSA_Branch_V(insn, false);
29370b57cec5SDimitry Andric }
29380b57cec5SDimitry Andric
Emulate_MSA_Branch_V(llvm::MCInst & insn,bool bnz)29390b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_MSA_Branch_V(llvm::MCInst &insn,
29400b57cec5SDimitry Andric bool bnz) {
29410b57cec5SDimitry Andric bool success = false;
29420b57cec5SDimitry Andric int32_t target = 0;
2943349cc55cSDimitry Andric llvm::APInt wr_val = llvm::APInt::getZero(128);
29440b57cec5SDimitry Andric llvm::APInt fail_value = llvm::APInt::getMaxValue(128);
2945349cc55cSDimitry Andric llvm::APInt zero_value = llvm::APInt::getZero(128);
29460b57cec5SDimitry Andric RegisterValue reg_value;
29470b57cec5SDimitry Andric
29480b57cec5SDimitry Andric uint32_t wt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
29490b57cec5SDimitry Andric int32_t offset = insn.getOperand(1).getImm();
29500b57cec5SDimitry Andric
29510b57cec5SDimitry Andric int32_t pc =
29520b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
29530b57cec5SDimitry Andric if (!success)
29540b57cec5SDimitry Andric return false;
29550b57cec5SDimitry Andric
29560b57cec5SDimitry Andric if (ReadRegister(eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value))
29570b57cec5SDimitry Andric wr_val = reg_value.GetAsUInt128(fail_value);
29580b57cec5SDimitry Andric else
29590b57cec5SDimitry Andric return false;
29600b57cec5SDimitry Andric
29610b57cec5SDimitry Andric if ((llvm::APInt::isSameValue(zero_value, wr_val) && !bnz) ||
29620b57cec5SDimitry Andric (!llvm::APInt::isSameValue(zero_value, wr_val) && bnz))
29630b57cec5SDimitry Andric target = pc + offset;
29640b57cec5SDimitry Andric else
29650b57cec5SDimitry Andric target = pc + 8;
29660b57cec5SDimitry Andric
29670b57cec5SDimitry Andric Context context;
29680b57cec5SDimitry Andric context.type = eContextRelativeBranchImmediate;
29690b57cec5SDimitry Andric
29700b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
29710b57cec5SDimitry Andric target);
29720b57cec5SDimitry Andric }
29730b57cec5SDimitry Andric
Emulate_LDST_Imm(llvm::MCInst & insn)29740b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LDST_Imm(llvm::MCInst &insn) {
29750b57cec5SDimitry Andric bool success = false;
29760b57cec5SDimitry Andric uint32_t base;
29770b57cec5SDimitry Andric int32_t imm, address;
29780b57cec5SDimitry Andric Context bad_vaddr_context;
29790b57cec5SDimitry Andric
29800b57cec5SDimitry Andric uint32_t num_operands = insn.getNumOperands();
29810b57cec5SDimitry Andric base =
29820b57cec5SDimitry Andric m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
29830b57cec5SDimitry Andric imm = insn.getOperand(num_operands - 1).getImm();
29840b57cec5SDimitry Andric
2985bdd1243dSDimitry Andric if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
29860b57cec5SDimitry Andric return false;
29870b57cec5SDimitry Andric
29880b57cec5SDimitry Andric /* read base register */
29890b57cec5SDimitry Andric address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
29900b57cec5SDimitry Andric dwarf_zero_mips + base, 0, &success);
29910b57cec5SDimitry Andric if (!success)
29920b57cec5SDimitry Andric return false;
29930b57cec5SDimitry Andric
29940b57cec5SDimitry Andric /* destination address */
29950b57cec5SDimitry Andric address = address + imm;
29960b57cec5SDimitry Andric
29970b57cec5SDimitry Andric /* Set the bad_vaddr register with base address used in the instruction */
29980b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
29990b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
30000b57cec5SDimitry Andric address);
30010b57cec5SDimitry Andric
30020b57cec5SDimitry Andric return true;
30030b57cec5SDimitry Andric }
30040b57cec5SDimitry Andric
Emulate_LDST_Reg(llvm::MCInst & insn)30050b57cec5SDimitry Andric bool EmulateInstructionMIPS::Emulate_LDST_Reg(llvm::MCInst &insn) {
30060b57cec5SDimitry Andric bool success = false;
30070b57cec5SDimitry Andric uint32_t base, index;
30080b57cec5SDimitry Andric int32_t address, index_address;
30090b57cec5SDimitry Andric Context bad_vaddr_context;
30100b57cec5SDimitry Andric
30110b57cec5SDimitry Andric uint32_t num_operands = insn.getNumOperands();
30120b57cec5SDimitry Andric base =
30130b57cec5SDimitry Andric m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
30140b57cec5SDimitry Andric index =
30150b57cec5SDimitry Andric m_reg_info->getEncodingValue(insn.getOperand(num_operands - 1).getReg());
30160b57cec5SDimitry Andric
3017bdd1243dSDimitry Andric if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
30180b57cec5SDimitry Andric return false;
30190b57cec5SDimitry Andric
3020bdd1243dSDimitry Andric if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + index))
30210b57cec5SDimitry Andric return false;
30220b57cec5SDimitry Andric
30230b57cec5SDimitry Andric /* read base register */
30240b57cec5SDimitry Andric address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
30250b57cec5SDimitry Andric dwarf_zero_mips + base, 0, &success);
30260b57cec5SDimitry Andric if (!success)
30270b57cec5SDimitry Andric return false;
30280b57cec5SDimitry Andric
30290b57cec5SDimitry Andric /* read index register */
30300b57cec5SDimitry Andric index_address = (int32_t)ReadRegisterUnsigned(
30310b57cec5SDimitry Andric eRegisterKindDWARF, dwarf_zero_mips + index, 0, &success);
30320b57cec5SDimitry Andric if (!success)
30330b57cec5SDimitry Andric return false;
30340b57cec5SDimitry Andric
30350b57cec5SDimitry Andric /* destination address */
30360b57cec5SDimitry Andric address = address + index_address;
30370b57cec5SDimitry Andric
30380b57cec5SDimitry Andric /* Set the bad_vaddr register with base address used in the instruction */
30390b57cec5SDimitry Andric bad_vaddr_context.type = eContextInvalid;
30400b57cec5SDimitry Andric WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
30410b57cec5SDimitry Andric address);
30420b57cec5SDimitry Andric
30430b57cec5SDimitry Andric return true;
30440b57cec5SDimitry Andric }
3045