37 changed files with 23 additions and 28101 deletions
-
46src/citra_qt/debugger/registers.cpp
-
25src/core/CMakeLists.txt
-
30src/core/arm/arm_interface.h
-
26src/core/arm/dynarmic/arm_dynarmic.cpp
-
7src/core/arm/dynarmic/arm_dynarmic.h
-
88src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
-
32src/core/arm/dynarmic/arm_dynarmic_cp15.h
-
132src/core/arm/dyncom/arm_dyncom.cpp
-
46src/core/arm/dyncom/arm_dyncom.h
-
478src/core/arm/dyncom/arm_dyncom_dec.cpp
-
36src/core/arm/dyncom/arm_dyncom_dec.h
-
4578src/core/arm/dyncom/arm_dyncom_interpreter.cpp
-
9src/core/arm/dyncom/arm_dyncom_interpreter.h
-
48src/core/arm/dyncom/arm_dyncom_run.h
-
390src/core/arm/dyncom/arm_dyncom_thumb.cpp
-
49src/core/arm/dyncom/arm_dyncom_thumb.h
-
1887src/core/arm/dyncom/arm_dyncom_trans.cpp
-
494src/core/arm/dyncom/arm_dyncom_trans.h
-
187src/core/arm/skyeye_common/arm_regformat.h
-
597src/core/arm/skyeye_common/armstate.cpp
-
245src/core/arm/skyeye_common/armstate.h
-
189src/core/arm/skyeye_common/armsupp.cpp
-
32src/core/arm/skyeye_common/armsupp.h
-
83src/core/arm/skyeye_common/vfp/asm_vfp.h
-
137src/core/arm/skyeye_common/vfp/vfp.cpp
-
43src/core/arm/skyeye_common/vfp/vfp.h
-
433src/core/arm/skyeye_common/vfp/vfp_helper.h
-
1247src/core/arm/skyeye_common/vfp/vfpdouble.cpp
-
1703src/core/arm/skyeye_common/vfp/vfpinstr.cpp
-
1272src/core/arm/skyeye_common/vfp/vfpsingle.cpp
-
5src/core/core.cpp
-
9src/core/gdbstub/gdbstub.cpp
-
26src/core/hle/kernel/svc.cpp
-
6src/core/hle/kernel/thread.cpp
-
1src/tests/CMakeLists.txt
-
50src/tests/core/arm/dyncom/arm_dyncom_vfp_tests.cpp
-
13456src/tests/core/arm/dyncom/vfp_vadd_f32.inc
@ -1,88 +0,0 @@ |
|||
// Copyright 2017 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
|||
#include "core/arm/skyeye_common/arm_regformat.h"
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
|||
|
|||
using Callback = Dynarmic::Coprocessor::Callback; |
|||
using CallbackOrAccessOneWord = Dynarmic::Coprocessor::CallbackOrAccessOneWord; |
|||
using CallbackOrAccessTwoWords = Dynarmic::Coprocessor::CallbackOrAccessTwoWords; |
|||
|
|||
DynarmicCP15::DynarmicCP15(const std::shared_ptr<ARMul_State>& state) : interpreter_state(state) {} |
|||
|
|||
DynarmicCP15::~DynarmicCP15() = default; |
|||
|
|||
boost::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, |
|||
CoprocReg CRd, CoprocReg CRn, |
|||
CoprocReg CRm, unsigned opc2) { |
|||
return boost::none; |
|||
} |
|||
|
|||
CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, |
|||
CoprocReg CRm, unsigned opc2) { |
|||
// TODO(merry): Privileged CP15 registers
|
|||
|
|||
if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { |
|||
// This is a dummy write, we ignore the value written here.
|
|||
return &interpreter_state->CP15[CP15_FLUSH_PREFETCH_BUFFER]; |
|||
} |
|||
|
|||
if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { |
|||
switch (opc2) { |
|||
case 4: |
|||
// This is a dummy write, we ignore the value written here.
|
|||
return &interpreter_state->CP15[CP15_DATA_SYNC_BARRIER]; |
|||
case 5: |
|||
// This is a dummy write, we ignore the value written here.
|
|||
return &interpreter_state->CP15[CP15_DATA_MEMORY_BARRIER]; |
|||
default: |
|||
return boost::blank{}; |
|||
} |
|||
} |
|||
|
|||
if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { |
|||
return &interpreter_state->CP15[CP15_THREAD_UPRW]; |
|||
} |
|||
|
|||
return boost::blank{}; |
|||
} |
|||
|
|||
CallbackOrAccessTwoWords DynarmicCP15::CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) { |
|||
return boost::blank{}; |
|||
} |
|||
|
|||
CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, |
|||
CoprocReg CRm, unsigned opc2) { |
|||
// TODO(merry): Privileged CP15 registers
|
|||
|
|||
if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) { |
|||
switch (opc2) { |
|||
case 2: |
|||
return &interpreter_state->CP15[CP15_THREAD_UPRW]; |
|||
case 3: |
|||
return &interpreter_state->CP15[CP15_THREAD_URO]; |
|||
default: |
|||
return boost::blank{}; |
|||
} |
|||
} |
|||
|
|||
return boost::blank{}; |
|||
} |
|||
|
|||
CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { |
|||
return boost::blank{}; |
|||
} |
|||
|
|||
boost::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, |
|||
CoprocReg CRd, |
|||
boost::optional<u8> option) { |
|||
return boost::none; |
|||
} |
|||
|
|||
boost::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, |
|||
CoprocReg CRd, |
|||
boost::optional<u8> option) { |
|||
return boost::none; |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// Copyright 2017 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#include <memory> |
|||
#include <dynarmic/coprocessor.h> |
|||
#include "common/common_types.h" |
|||
|
|||
struct ARMul_State; |
|||
|
|||
class DynarmicCP15 final : public Dynarmic::Coprocessor { |
|||
public: |
|||
explicit DynarmicCP15(const std::shared_ptr<ARMul_State>&); |
|||
~DynarmicCP15() override; |
|||
|
|||
boost::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, |
|||
CoprocReg CRn, CoprocReg CRm, |
|||
unsigned opc2) override; |
|||
CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, |
|||
CoprocReg CRm, unsigned opc2) override; |
|||
CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override; |
|||
CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, |
|||
unsigned opc2) override; |
|||
CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override; |
|||
boost::optional<Callback> CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, |
|||
boost::optional<u8> option) override; |
|||
boost::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, |
|||
boost::optional<u8> option) override; |
|||
|
|||
private: |
|||
std::shared_ptr<ARMul_State> interpreter_state; |
|||
}; |
|||
@ -1,132 +0,0 @@ |
|||
// Copyright 2014 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <cstring>
|
|||
#include <memory>
|
|||
#include "core/arm/dyncom/arm_dyncom.h"
|
|||
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
|
|||
#include "core/arm/dyncom/arm_dyncom_run.h"
|
|||
#include "core/arm/dyncom/arm_dyncom_trans.h"
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
|||
#include "core/arm/skyeye_common/armsupp.h"
|
|||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
|||
#include "core/core.h"
|
|||
#include "core/core_timing.h"
|
|||
|
|||
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { |
|||
state = std::make_unique<ARMul_State>(initial_mode); |
|||
} |
|||
|
|||
ARM_DynCom::~ARM_DynCom() {} |
|||
|
|||
void ARM_DynCom::ClearInstructionCache() { |
|||
state->instruction_cache.clear(); |
|||
trans_cache_buf_top = 0; |
|||
} |
|||
|
|||
void ARM_DynCom::SetPC(u64 pc) { |
|||
state->Reg[15] = pc; |
|||
} |
|||
|
|||
void ARM_DynCom::PageTableChanged() { |
|||
ClearInstructionCache(); |
|||
} |
|||
|
|||
u64 ARM_DynCom::GetPC() const { |
|||
return state->Reg[15]; |
|||
} |
|||
|
|||
u64 ARM_DynCom::GetReg(int index) const { |
|||
return state->Reg[index]; |
|||
} |
|||
|
|||
void ARM_DynCom::SetReg(int index, u64 value) { |
|||
state->Reg[index] = value; |
|||
} |
|||
|
|||
const u128& ARM_DynCom::GetExtReg(int index) const { |
|||
return {}; |
|||
} |
|||
|
|||
void ARM_DynCom::SetExtReg(int index, u128& value) { |
|||
} |
|||
|
|||
u32 ARM_DynCom::GetVFPReg(int index) const { |
|||
return state->ExtReg[index]; |
|||
} |
|||
|
|||
void ARM_DynCom::SetVFPReg(int index, u32 value) { |
|||
state->ExtReg[index] = value; |
|||
} |
|||
|
|||
u32 ARM_DynCom::GetVFPSystemReg(VFPSystemRegister reg) const { |
|||
return state->VFP[reg]; |
|||
} |
|||
|
|||
void ARM_DynCom::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { |
|||
state->VFP[reg] = value; |
|||
} |
|||
|
|||
u32 ARM_DynCom::GetCPSR() const { |
|||
return state->Cpsr; |
|||
} |
|||
|
|||
void ARM_DynCom::SetCPSR(u32 cpsr) { |
|||
state->Cpsr = cpsr; |
|||
} |
|||
|
|||
u32 ARM_DynCom::GetCP15Register(CP15Register reg) { |
|||
return state->CP15[reg]; |
|||
} |
|||
|
|||
void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) { |
|||
state->CP15[reg] = value; |
|||
} |
|||
|
|||
VAddr ARM_DynCom::GetTlsAddress() const { |
|||
return {}; |
|||
} |
|||
|
|||
void ARM_DynCom::SetTlsAddress(VAddr /*address*/) { |
|||
} |
|||
|
|||
void ARM_DynCom::ExecuteInstructions(int num_instructions) { |
|||
state->NumInstrsToExecute = num_instructions; |
|||
|
|||
// Dyncom only breaks on instruction dispatch. This only happens on every instruction when
|
|||
// executing one instruction at a time. Otherwise, if a block is being executed, more
|
|||
// instructions may actually be executed than specified.
|
|||
unsigned ticks_executed = InterpreterMainLoop(state.get()); |
|||
CoreTiming::AddTicks(ticks_executed); |
|||
} |
|||
|
|||
void ARM_DynCom::SaveContext(ThreadContext& ctx) { |
|||
memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); |
|||
memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); |
|||
|
|||
ctx.sp = state->Reg[13]; |
|||
ctx.lr = state->Reg[14]; |
|||
ctx.pc = state->Reg[15]; |
|||
ctx.cpsr = state->Cpsr; |
|||
|
|||
ctx.fpscr = state->VFP[VFP_FPSCR]; |
|||
ctx.fpexc = state->VFP[VFP_FPEXC]; |
|||
} |
|||
|
|||
void ARM_DynCom::LoadContext(const ThreadContext& ctx) { |
|||
memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); |
|||
memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); |
|||
|
|||
state->Reg[13] = ctx.sp; |
|||
state->Reg[14] = ctx.lr; |
|||
state->Reg[15] = ctx.pc; |
|||
state->Cpsr = ctx.cpsr; |
|||
|
|||
state->VFP[VFP_FPSCR] = ctx.fpscr; |
|||
state->VFP[VFP_FPEXC] = ctx.fpexc; |
|||
} |
|||
|
|||
void ARM_DynCom::PrepareReschedule() { |
|||
state->NumInstrsToExecute = 0; |
|||
} |
|||
@ -1,46 +0,0 @@ |
|||
// Copyright 2014 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include "common/common_types.h" |
|||
#include "core/arm/arm_interface.h" |
|||
#include "core/arm/skyeye_common/arm_regformat.h" |
|||
#include "core/arm/skyeye_common/armstate.h" |
|||
|
|||
class ARM_DynCom final : public ARM_Interface { |
|||
public: |
|||
ARM_DynCom(PrivilegeMode initial_mode); |
|||
~ARM_DynCom(); |
|||
|
|||
void ClearInstructionCache() override; |
|||
void PageTableChanged() override; |
|||
|
|||
void SetPC(u64 pc) override; |
|||
u64 GetPC() const override; |
|||
u64 GetReg(int index) const override; |
|||
void SetReg(int index, u64 value) override; |
|||
const u128& GetExtReg(int index) const override; |
|||
void SetExtReg(int index, u128& value) override; |
|||
u32 GetVFPReg(int index) const override; |
|||
void SetVFPReg(int index, u32 value) override; |
|||
u32 GetVFPSystemReg(VFPSystemRegister reg) const override; |
|||
void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override; |
|||
u32 GetCPSR() const override; |
|||
void SetCPSR(u32 cpsr) override; |
|||
u32 GetCP15Register(CP15Register reg) override; |
|||
void SetCP15Register(CP15Register reg, u32 value) override; |
|||
VAddr GetTlsAddress() const override; |
|||
void SetTlsAddress(VAddr address) override; |
|||
|
|||
void SaveContext(ThreadContext& ctx) override; |
|||
void LoadContext(const ThreadContext& ctx) override; |
|||
|
|||
void PrepareReschedule() override; |
|||
void ExecuteInstructions(int num_instructions) override; |
|||
|
|||
private: |
|||
std::unique_ptr<ARMul_State> state; |
|||
}; |
|||
@ -1,478 +0,0 @@ |
|||
// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "core/arm/dyncom/arm_dyncom_dec.h"
|
|||
#include "core/arm/skyeye_common/armsupp.h"
|
|||
|
|||
// clang-format off
|
|||
const InstructionSetEncodingItem arm_instruction[] = { |
|||
{ "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
|||
{ "vmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vnmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vnmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
|||
{ "vnmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
|||
{ "vadd", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
|||
{ "vsub", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vdiv", 5, ARMVFP2, { 23, 27, 0x1D, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
|||
{ "vmov(i)", 4, ARMVFP3, { 23, 27, 0x1D, 20, 21, 0x3, 9, 11, 0x5, 4, 7, 0 }}, |
|||
{ "vmov(r)", 5, ARMVFP3, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }}, |
|||
{ "vabs", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, |
|||
{ "vneg", 5, ARMVFP2, { 23, 27, 0x1D, 17, 21, 0x18, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }}, |
|||
{ "vsqrt", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x31, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, |
|||
{ "vcmp", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x34, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vcmp2", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x35, 9, 11, 0x5, 0, 6, 0x40 }}, |
|||
{ "vcvt(bds)", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x37, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, |
|||
{ "vcvt(bff)", 6, ARMVFP3, { 23, 27, 0x1D, 19, 21, 0x7, 17, 17, 0x1, 9, 11, 5, 6, 6, 1 }}, |
|||
{ "vcvt(bfi)", 5, ARMVFP2, { 23, 27, 0x1D, 19, 21, 0x7, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
|||
{ "vmovbrs", 3, ARMVFP2, { 21, 27, 0x70, 8, 11, 0xA, 0, 6, 0x10 }}, |
|||
{ "vmsr", 2, ARMVFP2, { 20, 27, 0xEE, 0, 11, 0xA10 }}, |
|||
{ "vmovbrc", 4, ARMVFP2, { 23, 27, 0x1C, 20, 20, 0x0, 8, 11, 0xB, 0, 4, 0x10 }}, |
|||
{ "vmrs", 2, ARMVFP2, { 20, 27, 0xEF, 0, 11, 0xA10 }}, |
|||
{ "vmovbcr", 4, ARMVFP2, { 24, 27, 0xE, 20, 20, 1, 8, 11, 0xB, 0, 4, 0x10 }}, |
|||
{ "vmovbrrss", 3, ARMVFP2, { 21, 27, 0x62, 8, 11, 0xA, 4, 4, 1 }}, |
|||
{ "vmovbrrd", 3, ARMVFP2, { 21, 27, 0x62, 6, 11, 0x2C, 4, 4, 1 }}, |
|||
{ "vstr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 0, 9, 11, 5 }}, |
|||
{ "vpush", 3, ARMVFP2, { 23, 27, 0x1A, 16, 21, 0x2D, 9, 11, 5 }}, |
|||
{ "vstm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 0, 9, 11, 5 }}, |
|||
{ "vpop", 3, ARMVFP2, { 23, 27, 0x19, 16, 21, 0x3D, 9, 11, 5 }}, |
|||
{ "vldr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 1, 9, 11, 5 }}, |
|||
{ "vldm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 1, 9, 11, 5 }}, |
|||
|
|||
{ "srs", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005 }}, |
|||
{ "rfe", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a }}, |
|||
{ "bkpt", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000007 }}, |
|||
{ "blx", 1, 3, { 25, 31, 0x0000007d }}, |
|||
{ "cps", 3, 6, { 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000 }}, |
|||
{ "pld", 4, 4, { 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f }}, |
|||
{ "setend", 2, 6, { 16, 31, 0x0000f101, 4, 7, 0x00000000 }}, |
|||
{ "clrex", 1, 6, { 0, 31, 0xf57ff01f }}, |
|||
{ "rev16", 2, 6, { 16, 27, 0x000006bf, 4, 11, 0x000000fb }}, |
|||
{ "usad8", 3, 6, { 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001 }}, |
|||
{ "sxtb", 2, 6, { 16, 27, 0x000006af, 4, 7, 0x00000007 }}, |
|||
{ "uxtb", 2, 6, { 16, 27, 0x000006ef, 4, 7, 0x00000007 }}, |
|||
{ "sxth", 2, 6, { 16, 27, 0x000006bf, 4, 7, 0x00000007 }}, |
|||
{ "sxtb16", 2, 6, { 16, 27, 0x0000068f, 4, 7, 0x00000007 }}, |
|||
{ "uxth", 2, 6, { 16, 27, 0x000006ff, 4, 7, 0x00000007 }}, |
|||
{ "uxtb16", 2, 6, { 16, 27, 0x000006cf, 4, 7, 0x00000007 }}, |
|||
{ "cpy", 2, 6, { 20, 27, 0x0000001a, 4, 11, 0x00000000 }}, |
|||
{ "uxtab", 2, 6, { 20, 27, 0x0000006e, 4, 9, 0x00000007 }}, |
|||
{ "ssub8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x0000000f }}, |
|||
{ "shsub8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x0000000f }}, |
|||
{ "ssubaddx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000005 }}, |
|||
{ "strex", 2, 6, { 20, 27, 0x00000018, 4, 7, 0x00000009 }}, |
|||
{ "strexb", 2, 7, { 20, 27, 0x0000001c, 4, 7, 0x00000009 }}, |
|||
{ "swp", 2, 0, { 20, 27, 0x00000010, 4, 7, 0x00000009 }}, |
|||
{ "swpb", 2, 0, { 20, 27, 0x00000014, 4, 7, 0x00000009 }}, |
|||
{ "ssub16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000007 }}, |
|||
{ "ssat16", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000003 }}, |
|||
{ "shsubaddx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000005 }}, |
|||
{ "qsubaddx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000005 }}, |
|||
{ "shaddsubx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000003 }}, |
|||
{ "shadd8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000009 }}, |
|||
{ "shadd16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000001 }}, |
|||
{ "sel", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x0000000b }}, |
|||
{ "saddsubx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000003 }}, |
|||
{ "sadd8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000009 }}, |
|||
{ "sadd16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000001 }}, |
|||
{ "shsub16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000007 }}, |
|||
{ "umaal", 2, 6, { 20, 27, 0x00000004, 4, 7, 0x00000009 }}, |
|||
{ "uxtab16", 2, 6, { 20, 27, 0x0000006c, 4, 7, 0x00000007 }}, |
|||
{ "usubaddx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000005 }}, |
|||
{ "usub8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x0000000f }}, |
|||
{ "usub16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000007 }}, |
|||
{ "usat16", 2, 6, { 20, 27, 0x0000006e, 4, 7, 0x00000003 }}, |
|||
{ "usada8", 2, 6, { 20, 27, 0x00000078, 4, 7, 0x00000001 }}, |
|||
{ "uqsubaddx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000005 }}, |
|||
{ "uqsub8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x0000000f }}, |
|||
{ "uqsub16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000007 }}, |
|||
{ "uqaddsubx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000003 }}, |
|||
{ "uqadd8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000009 }}, |
|||
{ "uqadd16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000001 }}, |
|||
{ "sxtab", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000007 }}, |
|||
{ "uhsubaddx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000005 }}, |
|||
{ "uhsub8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x0000000f }}, |
|||
{ "uhsub16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000007 }}, |
|||
{ "uhaddsubx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000003 }}, |
|||
{ "uhadd8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000009 }}, |
|||
{ "uhadd16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000001 }}, |
|||
{ "uaddsubx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000003 }}, |
|||
{ "uadd8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000009 }}, |
|||
{ "uadd16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000001 }}, |
|||
{ "sxtah", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000007 }}, |
|||
{ "sxtab16", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x00000007 }}, |
|||
{ "qadd8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000009 }}, |
|||
{ "bxj", 2, 5, { 20, 27, 0x00000012, 4, 7, 0x00000002 }}, |
|||
{ "clz", 2, 3, { 20, 27, 0x00000016, 4, 7, 0x00000001 }}, |
|||
{ "uxtah", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x00000007 }}, |
|||
{ "bx", 2, 2, { 20, 27, 0x00000012, 4, 7, 0x00000001 }}, |
|||
{ "rev", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000003 }}, |
|||
{ "blx", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000003 }}, |
|||
{ "revsh", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x0000000b }}, |
|||
{ "qadd", 2, 4, { 20, 27, 0x00000010, 4, 7, 0x00000005 }}, |
|||
{ "qadd16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000001 }}, |
|||
{ "qaddsubx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000003 }}, |
|||
{ "ldrex", 2, 0, { 20, 27, 0x00000019, 4, 7, 0x00000009 }}, |
|||
{ "qdadd", 2, 4, { 20, 27, 0x00000014, 4, 7, 0x00000005 }}, |
|||
{ "qdsub", 2, 4, { 20, 27, 0x00000016, 4, 7, 0x00000005 }}, |
|||
{ "qsub", 2, 4, { 20, 27, 0x00000012, 4, 7, 0x00000005 }}, |
|||
{ "ldrexb", 2, 7, { 20, 27, 0x0000001d, 4, 7, 0x00000009 }}, |
|||
{ "qsub8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x0000000f }}, |
|||
{ "qsub16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000007 }}, |
|||
{ "smuad", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "smmul", 4, 6, { 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "smusd", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, |
|||
{ "smlsd", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, |
|||
{ "smlsld", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, |
|||
{ "smmla", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "smmls", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001 }}, |
|||
{ "smlald", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "smlad", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "smlaw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000 }}, |
|||
{ "smulw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002 }}, |
|||
{ "pkhtb", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000005 }}, |
|||
{ "pkhbt", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000001 }}, |
|||
{ "smul", 3, 4, { 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, |
|||
{ "smlalxy", 3, 4, { 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, |
|||
{ "smla", 3, 4, { 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, |
|||
{ "mcrr", 1, 6, { 20, 27, 0x000000c4 }}, |
|||
{ "mrrc", 1, 6, { 20, 27, 0x000000c5 }}, |
|||
{ "cmp", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000015 }}, |
|||
{ "tst", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000011 }}, |
|||
{ "teq", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000013 }}, |
|||
{ "cmn", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000017 }}, |
|||
{ "smull", 2, 0, { 21, 27, 0x00000006, 4, 7, 0x00000009 }}, |
|||
{ "umull", 2, 0, { 21, 27, 0x00000004, 4, 7, 0x00000009 }}, |
|||
{ "umlal", 2, 0, { 21, 27, 0x00000005, 4, 7, 0x00000009 }}, |
|||
{ "smlal", 2, 0, { 21, 27, 0x00000007, 4, 7, 0x00000009 }}, |
|||
{ "mul", 2, 0, { 21, 27, 0x00000000, 4, 7, 0x00000009 }}, |
|||
{ "mla", 2, 0, { 21, 27, 0x00000001, 4, 7, 0x00000009 }}, |
|||
{ "ssat", 2, 6, { 21, 27, 0x00000035, 4, 5, 0x00000001 }}, |
|||
{ "usat", 2, 6, { 21, 27, 0x00000037, 4, 5, 0x00000001 }}, |
|||
{ "mrs", 4, 0, { 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000 }}, |
|||
{ "msr", 3, 0, { 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000 }}, |
|||
{ "and", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000000 }}, |
|||
{ "bic", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000e }}, |
|||
{ "ldm", 3, 0, { 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000 }}, |
|||
{ "eor", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000001 }}, |
|||
{ "add", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000004 }}, |
|||
{ "rsb", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000003 }}, |
|||
{ "rsc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000007 }}, |
|||
{ "sbc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000006 }}, |
|||
{ "adc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000005 }}, |
|||
{ "sub", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000002 }}, |
|||
{ "orr", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000c }}, |
|||
{ "mvn", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000f }}, |
|||
{ "mov", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000d }}, |
|||
{ "stm", 2, 0, { 25, 27, 0x00000004, 20, 22, 0x00000004 }}, |
|||
{ "ldm", 4, 0, { 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001 }}, |
|||
{ "ldrsh", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f }}, |
|||
{ "stm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000 }}, |
|||
{ "ldm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, |
|||
{ "ldrsb", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d }}, |
|||
{ "strd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f }}, |
|||
{ "ldrh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b }}, |
|||
{ "strh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b }}, |
|||
{ "ldrd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d }}, |
|||
{ "strt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002 }}, |
|||
{ "strbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006 }}, |
|||
{ "ldrbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007 }}, |
|||
{ "ldrt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003 }}, |
|||
{ "mrc", 3, 6, { 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001 }}, |
|||
{ "mcr", 3, 0, { 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001 }}, |
|||
{ "msr", 3, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000001 }}, |
|||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 19, 0x00000004 }}, |
|||
{ "msr", 5, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 19, 19, 0x00000001, 16, 17, 0x00000000 }}, |
|||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 17, 0x00000001 }}, |
|||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 17, 17, 0x00000001 }}, |
|||
{ "ldrb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001 }}, |
|||
{ "strb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000 }}, |
|||
{ "ldr", 4, 0, { 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, |
|||
{ "ldrcond", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, |
|||
{ "str", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000 }}, |
|||
{ "cdp", 2, 0, { 24, 27, 0x0000000e, 4, 4, 0x00000000 }}, |
|||
{ "stc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000000 }}, |
|||
{ "ldc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000001 }}, |
|||
{ "ldrexd", 2, ARMV6K, { 20, 27, 0x0000001B, 4, 7, 0x00000009 }}, |
|||
{ "strexd", 2, ARMV6K, { 20, 27, 0x0000001A, 4, 7, 0x00000009 }}, |
|||
{ "ldrexh", 2, ARMV6K, { 20, 27, 0x0000001F, 4, 7, 0x00000009 }}, |
|||
{ "strexh", 2, ARMV6K, { 20, 27, 0x0000001E, 4, 7, 0x00000009 }}, |
|||
{ "nop", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000000 }}, |
|||
{ "yield", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000001 }}, |
|||
{ "wfe", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000002 }}, |
|||
{ "wfi", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000003 }}, |
|||
{ "sev", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000004 }}, |
|||
{ "swi", 1, 0, { 24, 27, 0x0000000f }}, |
|||
{ "bbl", 1, 0, { 25, 27, 0x00000005 }}, |
|||
}; |
|||
|
|||
|
|||
const InstructionSetEncodingItem arm_exclusion_code[] = { |
|||
{ "vmla", 0, ARMVFP2, { 0 }}, |
|||
{ "vmls", 0, ARMVFP2, { 0 }}, |
|||
{ "vnmla", 0, ARMVFP2, { 0 }}, |
|||
{ "vnmls", 0, ARMVFP2, { 0 }}, |
|||
{ "vnmul", 0, ARMVFP2, { 0 }}, |
|||
{ "vmul", 0, ARMVFP2, { 0 }}, |
|||
{ "vadd", 0, ARMVFP2, { 0 }}, |
|||
{ "vsub", 0, ARMVFP2, { 0 }}, |
|||
{ "vdiv", 0, ARMVFP2, { 0 }}, |
|||
{ "vmov(i)", 0, ARMVFP3, { 0 }}, |
|||
{ "vmov(r)", 0, ARMVFP3, { 0 }}, |
|||
{ "vabs", 0, ARMVFP2, { 0 }}, |
|||
{ "vneg", 0, ARMVFP2, { 0 }}, |
|||
{ "vsqrt", 0, ARMVFP2, { 0 }}, |
|||
{ "vcmp", 0, ARMVFP2, { 0 }}, |
|||
{ "vcmp2", 0, ARMVFP2, { 0 }}, |
|||
{ "vcvt(bff)", 0, ARMVFP3, { 4, 4, 1 }}, |
|||
{ "vcvt(bds)", 0, ARMVFP2, { 0 }}, |
|||
{ "vcvt(bfi)", 0, ARMVFP2, { 0 }}, |
|||
{ "vmovbrs", 0, ARMVFP2, { 0 }}, |
|||
{ "vmsr", 0, ARMVFP2, { 0 }}, |
|||
{ "vmovbrc", 0, ARMVFP2, { 0 }}, |
|||
{ "vmrs", 0, ARMVFP2, { 0 }}, |
|||
{ "vmovbcr", 0, ARMVFP2, { 0 }}, |
|||
{ "vmovbrrss", 0, ARMVFP2, { 0 }}, |
|||
{ "vmovbrrd", 0, ARMVFP2, { 0 }}, |
|||
{ "vstr", 0, ARMVFP2, { 0 }}, |
|||
{ "vpush", 0, ARMVFP2, { 0 }}, |
|||
{ "vstm", 0, ARMVFP2, { 0 }}, |
|||
{ "vpop", 0, ARMVFP2, { 0 }}, |
|||
{ "vldr", 0, ARMVFP2, { 0 }}, |
|||
{ "vldm", 0, ARMVFP2, { 0 }}, |
|||
|
|||
{ "srs", 0, 6, { 0 }}, |
|||
{ "rfe", 0, 6, { 0 }}, |
|||
{ "bkpt", 0, 3, { 0 }}, |
|||
{ "blx", 0, 3, { 0 }}, |
|||
{ "cps", 0, 6, { 0 }}, |
|||
{ "pld", 0, 4, { 0 }}, |
|||
{ "setend", 0, 6, { 0 }}, |
|||
{ "clrex", 0, 6, { 0 }}, |
|||
{ "rev16", 0, 6, { 0 }}, |
|||
{ "usad8", 0, 6, { 0 }}, |
|||
{ "sxtb", 0, 6, { 0 }}, |
|||
{ "uxtb", 0, 6, { 0 }}, |
|||
{ "sxth", 0, 6, { 0 }}, |
|||
{ "sxtb16", 0, 6, { 0 }}, |
|||
{ "uxth", 0, 6, { 0 }}, |
|||
{ "uxtb16", 0, 6, { 0 }}, |
|||
{ "cpy", 0, 6, { 0 }}, |
|||
{ "uxtab", 0, 6, { 0 }}, |
|||
{ "ssub8", 0, 6, { 0 }}, |
|||
{ "shsub8", 0, 6, { 0 }}, |
|||
{ "ssubaddx", 0, 6, { 0 }}, |
|||
{ "strex", 0, 6, { 0 }}, |
|||
{ "strexb", 0, 7, { 0 }}, |
|||
{ "swp", 0, 0, { 0 }}, |
|||
{ "swpb", 0, 0, { 0 }}, |
|||
{ "ssub16", 0, 6, { 0 }}, |
|||
{ "ssat16", 0, 6, { 0 }}, |
|||
{ "shsubaddx", 0, 6, { 0 }}, |
|||
{ "qsubaddx", 0, 6, { 0 }}, |
|||
{ "shaddsubx", 0, 6, { 0 }}, |
|||
{ "shadd8", 0, 6, { 0 }}, |
|||
{ "shadd16", 0, 6, { 0 }}, |
|||
{ "sel", 0, 6, { 0 }}, |
|||
{ "saddsubx", 0, 6, { 0 }}, |
|||
{ "sadd8", 0, 6, { 0 }}, |
|||
{ "sadd16", 0, 6, { 0 }}, |
|||
{ "shsub16", 0, 6, { 0 }}, |
|||
{ "umaal", 0, 6, { 0 }}, |
|||
{ "uxtab16", 0, 6, { 0 }}, |
|||
{ "usubaddx", 0, 6, { 0 }}, |
|||
{ "usub8", 0, 6, { 0 }}, |
|||
{ "usub16", 0, 6, { 0 }}, |
|||
{ "usat16", 0, 6, { 0 }}, |
|||
{ "usada8", 0, 6, { 0 }}, |
|||
{ "uqsubaddx", 0, 6, { 0 }}, |
|||
{ "uqsub8", 0, 6, { 0 }}, |
|||
{ "uqsub16", 0, 6, { 0 }}, |
|||
{ "uqaddsubx", 0, 6, { 0 }}, |
|||
{ "uqadd8", 0, 6, { 0 }}, |
|||
{ "uqadd16", 0, 6, { 0 }}, |
|||
{ "sxtab", 0, 6, { 0 }}, |
|||
{ "uhsubaddx", 0, 6, { 0 }}, |
|||
{ "uhsub8", 0, 6, { 0 }}, |
|||
{ "uhsub16", 0, 6, { 0 }}, |
|||
{ "uhaddsubx", 0, 6, { 0 }}, |
|||
{ "uhadd8", 0, 6, { 0 }}, |
|||
{ "uhadd16", 0, 6, { 0 }}, |
|||
{ "uaddsubx", 0, 6, { 0 }}, |
|||
{ "uadd8", 0, 6, { 0 }}, |
|||
{ "uadd16", 0, 6, { 0 }}, |
|||
{ "sxtah", 0, 6, { 0 }}, |
|||
{ "sxtab16", 0, 6, { 0 }}, |
|||
{ "qadd8", 0, 6, { 0 }}, |
|||
{ "bxj", 0, 5, { 0 }}, |
|||
{ "clz", 0, 3, { 0 }}, |
|||
{ "uxtah", 0, 6, { 0 }}, |
|||
{ "bx", 0, 2, { 0 }}, |
|||
{ "rev", 0, 6, { 0 }}, |
|||
{ "blx", 0, 3, { 0 }}, |
|||
{ "revsh", 0, 6, { 0 }}, |
|||
{ "qadd", 0, 4, { 0 }}, |
|||
{ "qadd16", 0, 6, { 0 }}, |
|||
{ "qaddsubx", 0, 6, { 0 }}, |
|||
{ "ldrex", 0, 0, { 0 }}, |
|||
{ "qdadd", 0, 4, { 0 }}, |
|||
{ "qdsub", 0, 4, { 0 }}, |
|||
{ "qsub", 0, 4, { 0 }}, |
|||
{ "ldrexb", 0, 7, { 0 }}, |
|||
{ "qsub8", 0, 6, { 0 }}, |
|||
{ "qsub16", 0, 6, { 0 }}, |
|||
{ "smuad", 0, 6, { 0 }}, |
|||
{ "smmul", 0, 6, { 0 }}, |
|||
{ "smusd", 0, 6, { 0 }}, |
|||
{ "smlsd", 0, 6, { 0 }}, |
|||
{ "smlsld", 0, 6, { 0 }}, |
|||
{ "smmla", 0, 6, { 0 }}, |
|||
{ "smmls", 0, 6, { 0 }}, |
|||
{ "smlald", 0, 6, { 0 }}, |
|||
{ "smlad", 0, 6, { 0 }}, |
|||
{ "smlaw", 0, 4, { 0 }}, |
|||
{ "smulw", 0, 4, { 0 }}, |
|||
{ "pkhtb", 0, 6, { 0 }}, |
|||
{ "pkhbt", 0, 6, { 0 }}, |
|||
{ "smul", 0, 4, { 0 }}, |
|||
{ "smlal", 0, 4, { 0 }}, |
|||
{ "smla", 0, 4, { 0 }}, |
|||
{ "mcrr", 0, 6, { 0 }}, |
|||
{ "mrrc", 0, 6, { 0 }}, |
|||
{ "cmp", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "tst", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "teq", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "cmn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "smull", 0, 0, { 0 }}, |
|||
{ "umull", 0, 0, { 0 }}, |
|||
{ "umlal", 0, 0, { 0 }}, |
|||
{ "smlal", 0, 0, { 0 }}, |
|||
{ "mul", 0, 0, { 0 }}, |
|||
{ "mla", 0, 0, { 0 }}, |
|||
{ "ssat", 0, 6, { 0 }}, |
|||
{ "usat", 0, 6, { 0 }}, |
|||
{ "mrs", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "and", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "bic", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "ldm", 0, 0, { 0 }}, |
|||
{ "eor", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "add", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "rsb", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "rsc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "sbc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "adc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "sub", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "orr", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "mvn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "mov", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, |
|||
{ "stm", 0, 0, { 0 }}, |
|||
{ "ldm", 0, 0, { 0 }}, |
|||
{ "ldrsh", 0, 2, { 0 }}, |
|||
{ "stm", 0, 0, { 0 }}, |
|||
{ "ldm", 0, 0, { 0 }}, |
|||
{ "ldrsb", 0, 2, { 0 }}, |
|||
{ "strd", 0, 4, { 0 }}, |
|||
{ "ldrh", 0, 0, { 0 }}, |
|||
{ "strh", 0, 0, { 0 }}, |
|||
{ "ldrd", 0, 4, { 0 }}, |
|||
{ "strt", 0, 0, { 0 }}, |
|||
{ "strbt", 0, 0, { 0 }}, |
|||
{ "ldrbt", 0, 0, { 0 }}, |
|||
{ "ldrt", 0, 0, { 0 }}, |
|||
{ "mrc", 0, 6, { 0 }}, |
|||
{ "mcr", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "msr", 0, 0, { 0 }}, |
|||
{ "ldrb", 0, 0, { 0 }}, |
|||
{ "strb", 0, 0, { 0 }}, |
|||
{ "ldr", 0, 0, { 0 }}, |
|||
{ "ldrcond", 1, 0, { 28, 31, 0x0000000e }}, |
|||
{ "str", 0, 0, { 0 }}, |
|||
{ "cdp", 0, 0, { 0 }}, |
|||
{ "stc", 0, 0, { 0 }}, |
|||
{ "ldc", 0, 0, { 0 }}, |
|||
{ "ldrexd", 0, ARMV6K, { 0 }}, |
|||
{ "strexd", 0, ARMV6K, { 0 }}, |
|||
{ "ldrexh", 0, ARMV6K, { 0 }}, |
|||
{ "strexh", 0, ARMV6K, { 0 }}, |
|||
{ "nop", 0, ARMV6K, { 0 }}, |
|||
{ "yield", 0, ARMV6K, { 0 }}, |
|||
{ "wfe", 0, ARMV6K, { 0 }}, |
|||
{ "wfi", 0, ARMV6K, { 0 }}, |
|||
{ "sev", 0, ARMV6K, { 0 }}, |
|||
{ "swi", 0, 0, { 0 }}, |
|||
{ "bbl", 0, 0, { 0 }}, |
|||
|
|||
{ "bl_1_thumb", 0, INVALID, { 0 }}, // Should be table[-4]
|
|||
{ "bl_2_thumb", 0, INVALID, { 0 }}, // Should be located at the end of the table[-3]
|
|||
{ "blx_1_thumb", 0, INVALID, { 0 }}, // Should be located at table[-2]
|
|||
{ "invalid", 0, INVALID, { 0 }} |
|||
}; |
|||
// clang-format on
|
|||
|
|||
ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx) { |
|||
int n = 0; |
|||
int base = 0; |
|||
int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); |
|||
ARMDecodeStatus ret = ARMDecodeStatus::FAILURE; |
|||
|
|||
for (int i = 0; i < instr_slots; i++) { |
|||
n = arm_instruction[i].attribute_value; |
|||
base = 0; |
|||
|
|||
// 3DS has no VFP3 support
|
|||
if (arm_instruction[i].version == ARMVFP3) |
|||
continue; |
|||
|
|||
while (n) { |
|||
if (arm_instruction[i].content[base + 1] == 31 && |
|||
arm_instruction[i].content[base] == 0) { |
|||
// clrex
|
|||
if (instr != arm_instruction[i].content[base + 2]) { |
|||
break; |
|||
} |
|||
} else if (BITS(instr, arm_instruction[i].content[base], |
|||
arm_instruction[i].content[base + 1]) != |
|||
arm_instruction[i].content[base + 2]) { |
|||
break; |
|||
} |
|||
base += 3; |
|||
n--; |
|||
} |
|||
|
|||
// All conditions are satisfied.
|
|||
if (n == 0) |
|||
ret = ARMDecodeStatus::SUCCESS; |
|||
|
|||
if (ret == ARMDecodeStatus::SUCCESS) { |
|||
n = arm_exclusion_code[i].attribute_value; |
|||
if (n != 0) { |
|||
base = 0; |
|||
while (n) { |
|||
if (BITS(instr, arm_exclusion_code[i].content[base], |
|||
arm_exclusion_code[i].content[base + 1]) != |
|||
arm_exclusion_code[i].content[base + 2]) { |
|||
break; |
|||
} |
|||
base += 3; |
|||
n--; |
|||
} |
|||
|
|||
// All conditions are satisfied.
|
|||
if (n == 0) |
|||
ret = ARMDecodeStatus::FAILURE; |
|||
} |
|||
} |
|||
|
|||
if (ret == ARMDecodeStatus::SUCCESS) { |
|||
*idx = i; |
|||
return ret; |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
@ -1,36 +0,0 @@ |
|||
// Copyright 2012 Michael Kang, 2015 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
enum class ARMDecodeStatus { SUCCESS, FAILURE }; |
|||
|
|||
ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx); |
|||
|
|||
struct InstructionSetEncodingItem { |
|||
const char* name; |
|||
int attribute_value; |
|||
int version; |
|||
u32 content[21]; |
|||
}; |
|||
|
|||
// ARM versions |
|||
enum { |
|||
INVALID = 0, |
|||
ARMALL, |
|||
ARMV4, |
|||
ARMV4T, |
|||
ARMV5T, |
|||
ARMV5TE, |
|||
ARMV5TEJ, |
|||
ARMV6, |
|||
ARM1176JZF_S, |
|||
ARMVFP2, |
|||
ARMVFP3, |
|||
ARMV6K, |
|||
}; |
|||
|
|||
extern const InstructionSetEncodingItem arm_instruction[]; |
|||
4578
src/core/arm/dyncom/arm_dyncom_interpreter.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,9 +0,0 @@ |
|||
// Copyright 2014 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
struct ARMul_State; |
|||
|
|||
unsigned InterpreterMainLoop(ARMul_State* state); |
|||
@ -1,48 +0,0 @@ |
|||
/* Copyright (C) |
|||
* 2011 - Michael.Kang blackfin.kang@gmail.com |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|||
* |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/arm/skyeye_common/armstate.h" |
|||
|
|||
/** |
|||
* Checks if the PC is being read, and if so, word-aligns it. |
|||
* Used with address calculations. |
|||
* |
|||
* @param cpu The ARM CPU state instance. |
|||
* @param Rn The register being read. |
|||
* |
|||
* @return If the PC is being read, then the word-aligned PC value is returned. |
|||
* If the PC is not being read, then the value stored in the register is returned. |
|||
*/ |
|||
inline u32 CHECK_READ_REG15_WA(const ARMul_State* cpu, int Rn) { |
|||
return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
|||
} |
|||
|
|||
/** |
|||
* Reads the PC. Used for data processing operations that use the PC. |
|||
* |
|||
* @param cpu The ARM CPU state instance. |
|||
* @param Rn The register being read. |
|||
* |
|||
* @return If the PC is being read, then the incremented PC value is returned. |
|||
* If the PC is not being read, then the values stored in the register is returned. |
|||
*/ |
|||
inline u32 CHECK_READ_REG15(const ARMul_State* cpu, int Rn) { |
|||
return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
|||
} |
|||
@ -1,390 +0,0 @@ |
|||
// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <cstddef>
|
|||
|
|||
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
|
|||
// ARM instruction, and using the existing ARM simulator.
|
|||
|
|||
#include "core/arm/dyncom/arm_dyncom_thumb.h"
|
|||
#include "core/arm/skyeye_common/armsupp.h"
|
|||
|
|||
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
|
|||
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
|
|||
// allows easier simulation of the special dual BL instruction.
|
|||
|
|||
ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { |
|||
ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED; |
|||
u32 tinstr = GetThumbInstruction(instr, addr); |
|||
|
|||
*ainstr = 0xDEADC0DE; // Debugging to catch non updates
|
|||
|
|||
switch ((tinstr & 0xF800) >> 11) { |
|||
case 0: // LSL
|
|||
case 1: // LSR
|
|||
case 2: // ASR
|
|||
*ainstr = 0xE1B00000 // base opcode
|
|||
| ((tinstr & 0x1800) >> (11 - 5)) // shift type
|
|||
| ((tinstr & 0x07C0) << (7 - 6)) // imm5
|
|||
| ((tinstr & 0x0038) >> 3) // Rs
|
|||
| ((tinstr & 0x0007) << 12); // Rd
|
|||
break; |
|||
|
|||
case 3: // ADD/SUB
|
|||
{ |
|||
static const u32 subset[4] = { |
|||
0xE0900000, // ADDS Rd,Rs,Rn
|
|||
0xE0500000, // SUBS Rd,Rs,Rn
|
|||
0xE2900000, // ADDS Rd,Rs,#imm3
|
|||
0xE2500000 // SUBS Rd,Rs,#imm3
|
|||
}; |
|||
// It is quicker indexing into a table, than performing switch or conditionals:
|
|||
*ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
|
|||
| ((tinstr & 0x01C0) >> 6) // Rn or imm3
|
|||
| ((tinstr & 0x0038) << (16 - 3)) // Rs
|
|||
| ((tinstr & 0x0007) << (12 - 0)); // Rd
|
|||
} break; |
|||
|
|||
case 4: // MOV
|
|||
case 5: // CMP
|
|||
case 6: // ADD
|
|||
case 7: // SUB
|
|||
{ |
|||
static const u32 subset[4] = { |
|||
0xE3B00000, // MOVS Rd,#imm8
|
|||
0xE3500000, // CMP Rd,#imm8
|
|||
0xE2900000, // ADDS Rd,Rd,#imm8
|
|||
0xE2500000, // SUBS Rd,Rd,#imm8
|
|||
}; |
|||
|
|||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
|
|||
| ((tinstr & 0x00FF) >> 0) // imm8
|
|||
| ((tinstr & 0x0700) << (16 - 8)) // Rn
|
|||
| ((tinstr & 0x0700) << (12 - 8)); // Rd
|
|||
} break; |
|||
|
|||
case 8: // Arithmetic and high register transfers
|
|||
|
|||
// TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of
|
|||
// different ARM encodings, we could save the following conditional, and just have one
|
|||
// large subset
|
|||
|
|||
if ((tinstr & (1 << 10)) == 0) { |
|||
enum otype { t_norm, t_shift, t_neg, t_mul }; |
|||
|
|||
static const struct { |
|||
u32 opcode; |
|||
otype type; |
|||
} subset[16] = { |
|||
{0xE0100000, t_norm}, // ANDS Rd,Rd,Rs
|
|||
{0xE0300000, t_norm}, // EORS Rd,Rd,Rs
|
|||
{0xE1B00010, t_shift}, // MOVS Rd,Rd,LSL Rs
|
|||
{0xE1B00030, t_shift}, // MOVS Rd,Rd,LSR Rs
|
|||
{0xE1B00050, t_shift}, // MOVS Rd,Rd,ASR Rs
|
|||
{0xE0B00000, t_norm}, // ADCS Rd,Rd,Rs
|
|||
{0xE0D00000, t_norm}, // SBCS Rd,Rd,Rs
|
|||
{0xE1B00070, t_shift}, // MOVS Rd,Rd,ROR Rs
|
|||
{0xE1100000, t_norm}, // TST Rd,Rs
|
|||
{0xE2700000, t_neg}, // RSBS Rd,Rs,#0
|
|||
{0xE1500000, t_norm}, // CMP Rd,Rs
|
|||
{0xE1700000, t_norm}, // CMN Rd,Rs
|
|||
{0xE1900000, t_norm}, // ORRS Rd,Rd,Rs
|
|||
{0xE0100090, t_mul}, // MULS Rd,Rd,Rs
|
|||
{0xE1D00000, t_norm}, // BICS Rd,Rd,Rs
|
|||
{0xE1F00000, t_norm} // MVNS Rd,Rs
|
|||
}; |
|||
|
|||
*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base
|
|||
|
|||
switch (subset[(tinstr & 0x03C0) >> 6].type) { |
|||
case t_norm: |
|||
*ainstr |= ((tinstr & 0x0007) << 16) // Rn
|
|||
| ((tinstr & 0x0007) << 12) // Rd
|
|||
| ((tinstr & 0x0038) >> 3); // Rs
|
|||
break; |
|||
case t_shift: |
|||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
|||
| ((tinstr & 0x0007) >> 0) // Rm
|
|||
| ((tinstr & 0x0038) << (8 - 3)); // Rs
|
|||
break; |
|||
case t_neg: |
|||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
|||
| ((tinstr & 0x0038) << (16 - 3)); // Rn
|
|||
break; |
|||
case t_mul: |
|||
*ainstr |= ((tinstr & 0x0007) << 16) // Rd
|
|||
| ((tinstr & 0x0007) << 8) // Rs
|
|||
| ((tinstr & 0x0038) >> 3); // Rm
|
|||
break; |
|||
} |
|||
} else { |
|||
u32 Rd = ((tinstr & 0x0007) >> 0); |
|||
u32 Rs = ((tinstr & 0x0078) >> 3); |
|||
|
|||
if (tinstr & (1 << 7)) |
|||
Rd += 8; |
|||
|
|||
switch ((tinstr & 0x03C0) >> 6) { |
|||
case 0x0: // ADD Rd,Rd,Rs
|
|||
case 0x1: // ADD Rd,Rd,Hs
|
|||
case 0x2: // ADD Hd,Hd,Rs
|
|||
case 0x3: // ADD Hd,Hd,Hs
|
|||
*ainstr = 0xE0800000 // base
|
|||
| (Rd << 16) // Rn
|
|||
| (Rd << 12) // Rd
|
|||
| (Rs << 0); // Rm
|
|||
break; |
|||
case 0x4: // CMP Rd,Rs
|
|||
case 0x5: // CMP Rd,Hs
|
|||
case 0x6: // CMP Hd,Rs
|
|||
case 0x7: // CMP Hd,Hs
|
|||
*ainstr = 0xE1500000 // base
|
|||
| (Rd << 16) // Rn
|
|||
| (Rs << 0); // Rm
|
|||
break; |
|||
case 0x8: // MOV Rd,Rs
|
|||
case 0x9: // MOV Rd,Hs
|
|||
case 0xA: // MOV Hd,Rs
|
|||
case 0xB: // MOV Hd,Hs
|
|||
*ainstr = 0xE1A00000 // base
|
|||
| (Rd << 12) // Rd
|
|||
| (Rs << 0); // Rm
|
|||
break; |
|||
case 0xC: // BX Rs
|
|||
case 0xD: // BX Hs
|
|||
*ainstr = 0xE12FFF10 // base
|
|||
| ((tinstr & 0x0078) >> 3); // Rd
|
|||
break; |
|||
case 0xE: // BLX
|
|||
case 0xF: // BLX
|
|||
*ainstr = 0xE1200030 // base
|
|||
| (Rs << 0); // Rm
|
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case 9: // LDR Rd,[PC,#imm8]
|
|||
*ainstr = 0xE59F0000 // base
|
|||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
|||
| ((tinstr & 0x00FF) << (2 - 0)); // off8
|
|||
break; |
|||
|
|||
case 10: |
|||
case 11: { |
|||
static const u32 subset[8] = { |
|||
0xE7800000, // STR Rd,[Rb,Ro]
|
|||
0xE18000B0, // STRH Rd,[Rb,Ro]
|
|||
0xE7C00000, // STRB Rd,[Rb,Ro]
|
|||
0xE19000D0, // LDRSB Rd,[Rb,Ro]
|
|||
0xE7900000, // LDR Rd,[Rb,Ro]
|
|||
0xE19000B0, // LDRH Rd,[Rb,Ro]
|
|||
0xE7D00000, // LDRB Rd,[Rb,Ro]
|
|||
0xE19000F0 // LDRSH Rd,[Rb,Ro]
|
|||
}; |
|||
|
|||
*ainstr = subset[(tinstr & 0xE00) >> 9] // base
|
|||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
|||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
|||
| ((tinstr & 0x01C0) >> 6); // Ro
|
|||
} break; |
|||
|
|||
case 12: // STR Rd,[Rb,#imm5]
|
|||
case 13: // LDR Rd,[Rb,#imm5]
|
|||
case 14: // STRB Rd,[Rb,#imm5]
|
|||
case 15: // LDRB Rd,[Rb,#imm5]
|
|||
{ |
|||
static const u32 subset[4] = { |
|||
0xE5800000, // STR Rd,[Rb,#imm5]
|
|||
0xE5900000, // LDR Rd,[Rb,#imm5]
|
|||
0xE5C00000, // STRB Rd,[Rb,#imm5]
|
|||
0xE5D00000 // LDRB Rd,[Rb,#imm5]
|
|||
}; |
|||
// The offset range defends on whether we are transferring a byte or word value:
|
|||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base
|
|||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
|||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
|||
| ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
|
|||
} break; |
|||
|
|||
case 16: // STRH Rd,[Rb,#imm5]
|
|||
case 17: // LDRH Rd,[Rb,#imm5]
|
|||
*ainstr = ((tinstr & (1 << 11)) // base
|
|||
? 0xE1D000B0 // LDRH
|
|||
: 0xE1C000B0) // STRH
|
|||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
|||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
|||
| ((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
|
|||
| ((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
|
|||
break; |
|||
|
|||
case 18: // STR Rd,[SP,#imm8]
|
|||
case 19: // LDR Rd,[SP,#imm8]
|
|||
*ainstr = ((tinstr & (1 << 11)) // base
|
|||
? 0xE59D0000 // LDR
|
|||
: 0xE58D0000) // STR
|
|||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
|||
| ((tinstr & 0x00FF) << 2); // off8
|
|||
break; |
|||
|
|||
case 20: // ADD Rd,PC,#imm8
|
|||
case 21: // ADD Rd,SP,#imm8
|
|||
|
|||
if ((tinstr & (1 << 11)) == 0) { |
|||
|
|||
// NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the
|
|||
// rotate immediate field, so no shift of off8 is needed.
|
|||
|
|||
*ainstr = 0xE28F0F00 // base
|
|||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
|||
| (tinstr & 0x00FF); // off8
|
|||
} else { |
|||
// We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is
|
|||
// needed.
|
|||
*ainstr = 0xE28D0F00 // base
|
|||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
|||
| (tinstr & 0x00FF); // off8
|
|||
} |
|||
break; |
|||
|
|||
case 22: |
|||
case 23: |
|||
if ((tinstr & 0x0F00) == 0x0000) { |
|||
// NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30):
|
|||
*ainstr = ((tinstr & (1 << 7)) // base
|
|||
? 0xE24DDF00 // SUB
|
|||
: 0xE28DDF00) // ADD
|
|||
| (tinstr & 0x007F); // off7
|
|||
} else if ((tinstr & 0x0F00) == 0x0e00) { |
|||
// BKPT
|
|||
*ainstr = 0xEF000000 // base
|
|||
| BITS(tinstr, 0, 3) // imm4 field;
|
|||
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
|
|||
} else if ((tinstr & 0x0F00) == 0x0200) { |
|||
static const u32 subset[4] = { |
|||
0xE6BF0070, // SXTH
|
|||
0xE6AF0070, // SXTB
|
|||
0xE6FF0070, // UXTH
|
|||
0xE6EF0070, // UXTB
|
|||
}; |
|||
|
|||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
|||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
|||
| BITS(tinstr, 3, 5); // Rm
|
|||
} else if ((tinstr & 0x0F00) == 0x600) { |
|||
if (BIT(tinstr, 5) == 0) { |
|||
// SETEND
|
|||
*ainstr = 0xF1010000 // base
|
|||
| (BIT(tinstr, 3) << 9); // endian specifier
|
|||
} else { |
|||
// CPS
|
|||
*ainstr = 0xF1080000 // base
|
|||
| (BIT(tinstr, 0) << 6) // fiq bit
|
|||
| (BIT(tinstr, 1) << 7) // irq bit
|
|||
| (BIT(tinstr, 2) << 8) // abort bit
|
|||
| (BIT(tinstr, 4) << 18); // enable bit
|
|||
} |
|||
} else if ((tinstr & 0x0F00) == 0x0a00) { |
|||
static const u32 subset[4] = { |
|||
0xE6BF0F30, // REV
|
|||
0xE6BF0FB0, // REV16
|
|||
0, // undefined
|
|||
0xE6FF0FB0, // REVSH
|
|||
}; |
|||
|
|||
size_t subset_index = BITS(tinstr, 6, 7); |
|||
|
|||
if (subset_index == 2) { |
|||
valid = ThumbDecodeStatus::UNDEFINED; |
|||
} else { |
|||
*ainstr = subset[subset_index] // base
|
|||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
|||
| BITS(tinstr, 3, 5); // Rm
|
|||
} |
|||
} else { |
|||
static const u32 subset[4] = { |
|||
0xE92D0000, // STMDB sp!,{rlist}
|
|||
0xE92D4000, // STMDB sp!,{rlist,lr}
|
|||
0xE8BD0000, // LDMIA sp!,{rlist}
|
|||
0xE8BD8000 // LDMIA sp!,{rlist,pc}
|
|||
}; |
|||
*ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
|
|||
| (tinstr & 0x00FF); // mask8
|
|||
} |
|||
break; |
|||
|
|||
case 24: // STMIA
|
|||
case 25: // LDMIA
|
|||
if (tinstr & (1 << 11)) { |
|||
unsigned int base = 0xE8900000; |
|||
unsigned int rn = BITS(tinstr, 8, 10); |
|||
|
|||
// Writeback
|
|||
if ((tinstr & (1 << rn)) == 0) |
|||
base |= (1 << 21); |
|||
|
|||
*ainstr = base // base (LDMIA)
|
|||
| (rn << 16) // Rn
|
|||
| (tinstr & 0x00FF); // Register list
|
|||
} else { |
|||
*ainstr = 0xE8A00000 // base (STMIA)
|
|||
| (BITS(tinstr, 8, 10) << 16) // Rn
|
|||
| (tinstr & 0x00FF); // Register list
|
|||
} |
|||
break; |
|||
|
|||
case 26: // Bcc
|
|||
case 27: // Bcc/SWI
|
|||
if ((tinstr & 0x0F00) == 0x0F00) { |
|||
// Format 17 : SWI
|
|||
*ainstr = 0xEF000000; |
|||
// Breakpoint must be handled specially.
|
|||
if ((tinstr & 0x00FF) == 0x18) |
|||
*ainstr |= ((tinstr & 0x00FF) << 16); |
|||
// New breakpoint value. See gdb/arm-tdep.c
|
|||
else if ((tinstr & 0x00FF) == 0xFE) |
|||
*ainstr |= 0x180000; // base |= BKPT mask
|
|||
else |
|||
*ainstr |= (tinstr & 0x00FF); |
|||
} else if ((tinstr & 0x0F00) != 0x0E00) |
|||
valid = ThumbDecodeStatus::BRANCH; |
|||
else // UNDEFINED : cc=1110(AL) uses different format
|
|||
valid = ThumbDecodeStatus::UNDEFINED; |
|||
|
|||
break; |
|||
|
|||
case 28: // B
|
|||
valid = ThumbDecodeStatus::BRANCH; |
|||
break; |
|||
|
|||
case 29: |
|||
if (tinstr & 0x1) |
|||
valid = ThumbDecodeStatus::UNDEFINED; |
|||
else |
|||
valid = ThumbDecodeStatus::BRANCH; |
|||
break; |
|||
|
|||
case 30: // BL instruction 1
|
|||
|
|||
// There is no single ARM instruction equivalent for this Thumb instruction. To keep the
|
|||
// simulation simple (from the user perspective) we check if the following instruction is
|
|||
// the second half of this BL, and if it is we simulate it immediately
|
|||
|
|||
valid = ThumbDecodeStatus::BRANCH; |
|||
break; |
|||
|
|||
case 31: // BL instruction 2
|
|||
|
|||
// There is no single ARM instruction equivalent for this instruction. Also, it should only
|
|||
// ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
|
|||
// simulation of it on its own, with undefined results if r14 is not suitably initialised.
|
|||
|
|||
valid = ThumbDecodeStatus::BRANCH; |
|||
break; |
|||
} |
|||
|
|||
*inst_size = 2; |
|||
|
|||
return valid; |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
/* Copyright (C) |
|||
* 2011 - Michael.Kang blackfin.kang@gmail.com |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|||
* |
|||
*/ |
|||
|
|||
/** |
|||
* @file arm_dyncom_thumb.h |
|||
* @brief The thumb dyncom |
|||
* @author Michael.Kang blackfin.kang@gmail.com |
|||
* @version 78.77 |
|||
* @date 2011-11-07 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
enum class ThumbDecodeStatus { |
|||
UNDEFINED, // Undefined Thumb instruction |
|||
DECODED, // Instruction decoded to ARM equivalent |
|||
BRANCH, // Thumb branch (already processed) |
|||
UNINITIALIZED, |
|||
}; |
|||
|
|||
// Translates a Thumb mode instruction into its ARM equivalent. |
|||
ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); |
|||
|
|||
inline u32 GetThumbInstruction(u32 instr, u32 address) { |
|||
// Normally you would need to handle instruction endianness, |
|||
// however, it is fixed to little-endian on the MPCore, so |
|||
// there's no need to check for this beforehand. |
|||
if ((address & 0x3) != 0) |
|||
return instr >> 16; |
|||
|
|||
return instr & 0xFFFF; |
|||
} |
|||
1887
src/core/arm/dyncom/arm_dyncom_trans.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,494 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <cstddef> |
|||
#include "common/common_types.h" |
|||
|
|||
struct ARMul_State; |
|||
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); |
|||
|
|||
enum class TransExtData { |
|||
COND = (1 << 0), |
|||
NON_BRANCH = (1 << 1), |
|||
DIRECT_BRANCH = (1 << 2), |
|||
INDIRECT_BRANCH = (1 << 3), |
|||
CALL = (1 << 4), |
|||
RET = (1 << 5), |
|||
END_OF_PAGE = (1 << 6), |
|||
THUMB = (1 << 7), |
|||
SINGLE_STEP = (1 << 8) |
|||
}; |
|||
|
|||
struct arm_inst { |
|||
unsigned int idx; |
|||
unsigned int cond; |
|||
TransExtData br; |
|||
char component[0]; |
|||
}; |
|||
|
|||
struct generic_arm_inst { |
|||
u32 Ra; |
|||
u32 Rm; |
|||
u32 Rn; |
|||
u32 Rd; |
|||
u8 op1; |
|||
u8 op2; |
|||
}; |
|||
|
|||
struct adc_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct add_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct orr_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct and_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct eor_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct bbl_inst { |
|||
unsigned int L; |
|||
int signed_immed_24; |
|||
unsigned int next_addr; |
|||
unsigned int jmp_addr; |
|||
}; |
|||
|
|||
struct bx_inst { |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct blx_inst { |
|||
union { |
|||
s32 signed_immed_24; |
|||
u32 Rm; |
|||
} val; |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct clz_inst { |
|||
unsigned int Rm; |
|||
unsigned int Rd; |
|||
}; |
|||
|
|||
struct cps_inst { |
|||
unsigned int imod0; |
|||
unsigned int imod1; |
|||
unsigned int mmod; |
|||
unsigned int A, I, F; |
|||
unsigned int mode; |
|||
}; |
|||
|
|||
struct clrex_inst {}; |
|||
|
|||
struct cpy_inst { |
|||
unsigned int Rm; |
|||
unsigned int Rd; |
|||
}; |
|||
|
|||
struct bic_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct sub_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct tst_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct cmn_inst { |
|||
unsigned int I; |
|||
unsigned int Rn; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct teq_inst { |
|||
unsigned int I; |
|||
unsigned int Rn; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct stm_inst { |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct bkpt_inst { |
|||
u32 imm; |
|||
}; |
|||
|
|||
struct stc_inst {}; |
|||
|
|||
struct ldc_inst {}; |
|||
|
|||
struct swi_inst { |
|||
unsigned int num; |
|||
}; |
|||
|
|||
struct cmp_inst { |
|||
unsigned int I; |
|||
unsigned int Rn; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct mov_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct mvn_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct rev_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
unsigned int op1; |
|||
unsigned int op2; |
|||
}; |
|||
|
|||
struct rsb_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct rsc_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct sbc_inst { |
|||
unsigned int I; |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int shifter_operand; |
|||
shtop_fp_t shtop_func; |
|||
}; |
|||
|
|||
struct mul_inst { |
|||
unsigned int S; |
|||
unsigned int Rd; |
|||
unsigned int Rs; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct smul_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rs; |
|||
unsigned int Rm; |
|||
unsigned int x; |
|||
unsigned int y; |
|||
}; |
|||
|
|||
struct umull_inst { |
|||
unsigned int S; |
|||
unsigned int RdHi; |
|||
unsigned int RdLo; |
|||
unsigned int Rs; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct smlad_inst { |
|||
unsigned int m; |
|||
unsigned int Rm; |
|||
unsigned int Rd; |
|||
unsigned int Ra; |
|||
unsigned int Rn; |
|||
unsigned int op1; |
|||
unsigned int op2; |
|||
}; |
|||
|
|||
struct smla_inst { |
|||
unsigned int x; |
|||
unsigned int y; |
|||
unsigned int Rm; |
|||
unsigned int Rd; |
|||
unsigned int Rs; |
|||
unsigned int Rn; |
|||
}; |
|||
|
|||
struct smlalxy_inst { |
|||
unsigned int x; |
|||
unsigned int y; |
|||
unsigned int RdLo; |
|||
unsigned int RdHi; |
|||
unsigned int Rm; |
|||
unsigned int Rn; |
|||
}; |
|||
|
|||
struct ssat_inst { |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int imm5; |
|||
unsigned int sat_imm; |
|||
unsigned int shift_type; |
|||
}; |
|||
|
|||
struct umaal_inst { |
|||
unsigned int Rn; |
|||
unsigned int Rm; |
|||
unsigned int RdHi; |
|||
unsigned int RdLo; |
|||
}; |
|||
|
|||
struct umlal_inst { |
|||
unsigned int S; |
|||
unsigned int Rm; |
|||
unsigned int Rs; |
|||
unsigned int RdHi; |
|||
unsigned int RdLo; |
|||
}; |
|||
|
|||
struct smlal_inst { |
|||
unsigned int S; |
|||
unsigned int Rm; |
|||
unsigned int Rs; |
|||
unsigned int RdHi; |
|||
unsigned int RdLo; |
|||
}; |
|||
|
|||
struct smlald_inst { |
|||
unsigned int RdLo; |
|||
unsigned int RdHi; |
|||
unsigned int Rm; |
|||
unsigned int Rn; |
|||
unsigned int swap; |
|||
unsigned int op1; |
|||
unsigned int op2; |
|||
}; |
|||
|
|||
struct mla_inst { |
|||
unsigned int S; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int Rs; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct mrc_inst { |
|||
unsigned int opcode_1; |
|||
unsigned int opcode_2; |
|||
unsigned int cp_num; |
|||
unsigned int crn; |
|||
unsigned int crm; |
|||
unsigned int Rd; |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct mcr_inst { |
|||
unsigned int opcode_1; |
|||
unsigned int opcode_2; |
|||
unsigned int cp_num; |
|||
unsigned int crn; |
|||
unsigned int crm; |
|||
unsigned int Rd; |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct mcrr_inst { |
|||
unsigned int opcode_1; |
|||
unsigned int cp_num; |
|||
unsigned int crm; |
|||
unsigned int rt; |
|||
unsigned int rt2; |
|||
}; |
|||
|
|||
struct mrs_inst { |
|||
unsigned int R; |
|||
unsigned int Rd; |
|||
}; |
|||
|
|||
struct msr_inst { |
|||
unsigned int field_mask; |
|||
unsigned int R; |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct pld_inst {}; |
|||
|
|||
struct sxtb_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
unsigned int rotate; |
|||
}; |
|||
|
|||
struct sxtab_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rn; |
|||
unsigned int Rm; |
|||
unsigned rotate; |
|||
}; |
|||
|
|||
struct sxtah_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rn; |
|||
unsigned int Rm; |
|||
unsigned int rotate; |
|||
}; |
|||
|
|||
struct sxth_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
unsigned int rotate; |
|||
}; |
|||
|
|||
struct uxtab_inst { |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int rotate; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct uxtah_inst { |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int rotate; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct uxth_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
unsigned int rotate; |
|||
}; |
|||
|
|||
struct cdp_inst { |
|||
unsigned int opcode_1; |
|||
unsigned int CRn; |
|||
unsigned int CRd; |
|||
unsigned int cp_num; |
|||
unsigned int opcode_2; |
|||
unsigned int CRm; |
|||
unsigned int inst; |
|||
}; |
|||
|
|||
struct uxtb_inst { |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
unsigned int rotate; |
|||
}; |
|||
|
|||
struct swp_inst { |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned int Rm; |
|||
}; |
|||
|
|||
struct setend_inst { |
|||
unsigned int set_bigend; |
|||
}; |
|||
|
|||
struct b_2_thumb { |
|||
unsigned int imm; |
|||
}; |
|||
struct b_cond_thumb { |
|||
unsigned int imm; |
|||
unsigned int cond; |
|||
}; |
|||
|
|||
struct bl_1_thumb { |
|||
unsigned int imm; |
|||
}; |
|||
struct bl_2_thumb { |
|||
unsigned int imm; |
|||
}; |
|||
struct blx_1_thumb { |
|||
unsigned int imm; |
|||
unsigned int instr; |
|||
}; |
|||
|
|||
struct pkh_inst { |
|||
unsigned int Rm; |
|||
unsigned int Rn; |
|||
unsigned int Rd; |
|||
unsigned char imm; |
|||
}; |
|||
|
|||
// Floating point VFPv3 structures |
|||
#define VFP_INTERPRETER_STRUCT |
|||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" |
|||
#undef VFP_INTERPRETER_STRUCT |
|||
|
|||
typedef void (*get_addr_fp_t)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr); |
|||
|
|||
struct ldst_inst { |
|||
unsigned int inst; |
|||
get_addr_fp_t get_addr; |
|||
}; |
|||
|
|||
typedef arm_inst* ARM_INST_PTR; |
|||
typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); |
|||
|
|||
extern const transop_fp_t arm_instruction_trans[]; |
|||
extern const size_t arm_instruction_trans_len; |
|||
|
|||
#define TRANS_CACHE_SIZE (64 * 1024 * 2000) |
|||
extern char trans_cache_buf[TRANS_CACHE_SIZE]; |
|||
extern size_t trans_cache_buf_top; |
|||
@ -1,187 +0,0 @@ |
|||
#pragma once |
|||
|
|||
enum { |
|||
R0 = 0, |
|||
R1, |
|||
R2, |
|||
R3, |
|||
R4, |
|||
R5, |
|||
R6, |
|||
R7, |
|||
R8, |
|||
R9, |
|||
R10, |
|||
R11, |
|||
R12, |
|||
R13, |
|||
LR, |
|||
R15, // PC, |
|||
CPSR_REG, |
|||
SPSR_REG, |
|||
|
|||
PHYS_PC, |
|||
R13_USR, |
|||
R14_USR, |
|||
R13_SVC, |
|||
R14_SVC, |
|||
R13_ABORT, |
|||
R14_ABORT, |
|||
R13_UNDEF, |
|||
R14_UNDEF, |
|||
R13_IRQ, |
|||
R14_IRQ, |
|||
R8_FIRQ, |
|||
R9_FIRQ, |
|||
R10_FIRQ, |
|||
R11_FIRQ, |
|||
R12_FIRQ, |
|||
R13_FIRQ, |
|||
R14_FIRQ, |
|||
SPSR_INVALID1, |
|||
SPSR_INVALID2, |
|||
SPSR_SVC, |
|||
SPSR_ABORT, |
|||
SPSR_UNDEF, |
|||
SPSR_IRQ, |
|||
SPSR_FIRQ, |
|||
MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */ |
|||
BANK_REG, |
|||
EXCLUSIVE_TAG, |
|||
EXCLUSIVE_STATE, |
|||
EXCLUSIVE_RESULT, |
|||
|
|||
MAX_REG_NUM, |
|||
}; |
|||
|
|||
// VFP system registers |
|||
enum VFPSystemRegister { |
|||
VFP_FPSID, |
|||
VFP_FPSCR, |
|||
VFP_FPEXC, |
|||
VFP_FPINST, |
|||
VFP_FPINST2, |
|||
VFP_MVFR0, |
|||
VFP_MVFR1, |
|||
|
|||
// Not an actual register. |
|||
// All VFP system registers should be defined above this. |
|||
VFP_SYSTEM_REGISTER_COUNT |
|||
}; |
|||
|
|||
enum CP15Register { |
|||
// c0 - Information registers |
|||
CP15_MAIN_ID, |
|||
CP15_CACHE_TYPE, |
|||
CP15_TCM_STATUS, |
|||
CP15_TLB_TYPE, |
|||
CP15_CPU_ID, |
|||
CP15_PROCESSOR_FEATURE_0, |
|||
CP15_PROCESSOR_FEATURE_1, |
|||
CP15_DEBUG_FEATURE_0, |
|||
CP15_AUXILIARY_FEATURE_0, |
|||
CP15_MEMORY_MODEL_FEATURE_0, |
|||
CP15_MEMORY_MODEL_FEATURE_1, |
|||
CP15_MEMORY_MODEL_FEATURE_2, |
|||
CP15_MEMORY_MODEL_FEATURE_3, |
|||
CP15_ISA_FEATURE_0, |
|||
CP15_ISA_FEATURE_1, |
|||
CP15_ISA_FEATURE_2, |
|||
CP15_ISA_FEATURE_3, |
|||
CP15_ISA_FEATURE_4, |
|||
|
|||
// c1 - Control registers |
|||
CP15_CONTROL, |
|||
CP15_AUXILIARY_CONTROL, |
|||
CP15_COPROCESSOR_ACCESS_CONTROL, |
|||
|
|||
// c2 - Translation table registers |
|||
CP15_TRANSLATION_BASE_TABLE_0, |
|||
CP15_TRANSLATION_BASE_TABLE_1, |
|||
CP15_TRANSLATION_BASE_CONTROL, |
|||
CP15_DOMAIN_ACCESS_CONTROL, |
|||
CP15_RESERVED, |
|||
|
|||
// c5 - Fault status registers |
|||
CP15_FAULT_STATUS, |
|||
CP15_INSTR_FAULT_STATUS, |
|||
CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, |
|||
CP15_INST_FSR, |
|||
|
|||
// c6 - Fault Address registers |
|||
CP15_FAULT_ADDRESS, |
|||
CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, |
|||
CP15_WFAR, |
|||
CP15_IFAR, |
|||
|
|||
// c7 - Cache operation registers |
|||
CP15_WAIT_FOR_INTERRUPT, |
|||
CP15_PHYS_ADDRESS, |
|||
CP15_INVALIDATE_INSTR_CACHE, |
|||
CP15_INVALIDATE_INSTR_CACHE_USING_MVA, |
|||
CP15_INVALIDATE_INSTR_CACHE_USING_INDEX, |
|||
CP15_FLUSH_PREFETCH_BUFFER, |
|||
CP15_FLUSH_BRANCH_TARGET_CACHE, |
|||
CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY, |
|||
CP15_INVALIDATE_DATA_CACHE, |
|||
CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA, |
|||
CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, |
|||
CP15_INVALIDATE_DATA_AND_INSTR_CACHE, |
|||
CP15_CLEAN_DATA_CACHE, |
|||
CP15_CLEAN_DATA_CACHE_LINE_USING_MVA, |
|||
CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX, |
|||
CP15_DATA_SYNC_BARRIER, |
|||
CP15_DATA_MEMORY_BARRIER, |
|||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE, |
|||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA, |
|||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, |
|||
|
|||
// c8 - TLB operations |
|||
CP15_INVALIDATE_ITLB, |
|||
CP15_INVALIDATE_ITLB_SINGLE_ENTRY, |
|||
CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH, |
|||
CP15_INVALIDATE_ITLB_ENTRY_ON_MVA, |
|||
CP15_INVALIDATE_DTLB, |
|||
CP15_INVALIDATE_DTLB_SINGLE_ENTRY, |
|||
CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH, |
|||
CP15_INVALIDATE_DTLB_ENTRY_ON_MVA, |
|||
CP15_INVALIDATE_UTLB, |
|||
CP15_INVALIDATE_UTLB_SINGLE_ENTRY, |
|||
CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH, |
|||
CP15_INVALIDATE_UTLB_ENTRY_ON_MVA, |
|||
|
|||
// c9 - Data cache lockdown register |
|||
CP15_DATA_CACHE_LOCKDOWN, |
|||
|
|||
// c10 - TLB/Memory map registers |
|||
CP15_TLB_LOCKDOWN, |
|||
CP15_PRIMARY_REGION_REMAP, |
|||
CP15_NORMAL_REGION_REMAP, |
|||
|
|||
// c13 - Thread related registers |
|||
CP15_PID, |
|||
CP15_CONTEXT_ID, |
|||
CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write |
|||
CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) |
|||
CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. |
|||
|
|||
// c15 - Performance and TLB lockdown registers |
|||
CP15_PERFORMANCE_MONITOR_CONTROL, |
|||
CP15_CYCLE_COUNTER, |
|||
CP15_COUNT_0, |
|||
CP15_COUNT_1, |
|||
CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY, |
|||
CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY, |
|||
CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS, |
|||
CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS, |
|||
CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE, |
|||
CP15_TLB_DEBUG_CONTROL, |
|||
|
|||
// Skyeye defined |
|||
CP15_TLB_FAULT_ADDR, |
|||
CP15_TLB_FAULT_STATUS, |
|||
|
|||
// Not an actual register. |
|||
// All registers should be defined above this. |
|||
CP15_REGISTER_COUNT, |
|||
}; |
|||
@ -1,597 +0,0 @@ |
|||
// Copyright 2015 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <algorithm>
|
|||
#include "common/logging/log.h"
|
|||
#include "common/swap.h"
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
|||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
|||
#include "core/gdbstub/gdbstub.h"
|
|||
#include "core/memory.h"
|
|||
|
|||
ARMul_State::ARMul_State(PrivilegeMode initial_mode) { |
|||
Reset(); |
|||
ChangePrivilegeMode(initial_mode); |
|||
} |
|||
|
|||
void ARMul_State::ChangePrivilegeMode(u32 new_mode) { |
|||
if (Mode == new_mode) |
|||
return; |
|||
|
|||
if (new_mode != USERBANK) { |
|||
switch (Mode) { |
|||
case SYSTEM32MODE: // Shares registers with user mode
|
|||
case USER32MODE: |
|||
Reg_usr[0] = Reg[13]; |
|||
Reg_usr[1] = Reg[14]; |
|||
break; |
|||
case IRQ32MODE: |
|||
Reg_irq[0] = Reg[13]; |
|||
Reg_irq[1] = Reg[14]; |
|||
Spsr[IRQBANK] = Spsr_copy; |
|||
break; |
|||
case SVC32MODE: |
|||
Reg_svc[0] = Reg[13]; |
|||
Reg_svc[1] = Reg[14]; |
|||
Spsr[SVCBANK] = Spsr_copy; |
|||
break; |
|||
case ABORT32MODE: |
|||
Reg_abort[0] = Reg[13]; |
|||
Reg_abort[1] = Reg[14]; |
|||
Spsr[ABORTBANK] = Spsr_copy; |
|||
break; |
|||
case UNDEF32MODE: |
|||
Reg_undef[0] = Reg[13]; |
|||
Reg_undef[1] = Reg[14]; |
|||
Spsr[UNDEFBANK] = Spsr_copy; |
|||
break; |
|||
case FIQ32MODE: |
|||
std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin()); |
|||
Spsr[FIQBANK] = Spsr_copy; |
|||
break; |
|||
} |
|||
|
|||
switch (new_mode) { |
|||
case USER32MODE: |
|||
Reg[13] = Reg_usr[0]; |
|||
Reg[14] = Reg_usr[1]; |
|||
Bank = USERBANK; |
|||
break; |
|||
case IRQ32MODE: |
|||
Reg[13] = Reg_irq[0]; |
|||
Reg[14] = Reg_irq[1]; |
|||
Spsr_copy = Spsr[IRQBANK]; |
|||
Bank = IRQBANK; |
|||
break; |
|||
case SVC32MODE: |
|||
Reg[13] = Reg_svc[0]; |
|||
Reg[14] = Reg_svc[1]; |
|||
Spsr_copy = Spsr[SVCBANK]; |
|||
Bank = SVCBANK; |
|||
break; |
|||
case ABORT32MODE: |
|||
Reg[13] = Reg_abort[0]; |
|||
Reg[14] = Reg_abort[1]; |
|||
Spsr_copy = Spsr[ABORTBANK]; |
|||
Bank = ABORTBANK; |
|||
break; |
|||
case UNDEF32MODE: |
|||
Reg[13] = Reg_undef[0]; |
|||
Reg[14] = Reg_undef[1]; |
|||
Spsr_copy = Spsr[UNDEFBANK]; |
|||
Bank = UNDEFBANK; |
|||
break; |
|||
case FIQ32MODE: |
|||
std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8); |
|||
Spsr_copy = Spsr[FIQBANK]; |
|||
Bank = FIQBANK; |
|||
break; |
|||
case SYSTEM32MODE: // Shares registers with user mode.
|
|||
Reg[13] = Reg_usr[0]; |
|||
Reg[14] = Reg_usr[1]; |
|||
Bank = SYSTEMBANK; |
|||
break; |
|||
} |
|||
|
|||
// Set the mode bits in the APSR
|
|||
Cpsr = (Cpsr & ~Mode) | new_mode; |
|||
Mode = new_mode; |
|||
} |
|||
} |
|||
|
|||
// Performs a reset
|
|||
void ARMul_State::Reset() { |
|||
VFPInit(this); |
|||
|
|||
// Set stack pointer to the top of the stack
|
|||
Reg[13] = 0x10000000; |
|||
Reg[15] = 0; |
|||
|
|||
Cpsr = INTBITS | SVC32MODE; |
|||
Mode = SVC32MODE; |
|||
Bank = SVCBANK; |
|||
|
|||
ResetMPCoreCP15Registers(); |
|||
|
|||
NresetSig = HIGH; |
|||
NfiqSig = HIGH; |
|||
NirqSig = HIGH; |
|||
NtransSig = (Mode & 3) ? HIGH : LOW; |
|||
abortSig = LOW; |
|||
|
|||
NumInstrs = 0; |
|||
Emulate = RUN; |
|||
} |
|||
|
|||
// Resets certain MPCore CP15 values to their ARM-defined reset values.
|
|||
void ARMul_State::ResetMPCoreCP15Registers() { |
|||
// c0
|
|||
CP15[CP15_MAIN_ID] = 0x410FB024; |
|||
CP15[CP15_TLB_TYPE] = 0x00000800; |
|||
CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; |
|||
CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; |
|||
CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; |
|||
CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; |
|||
CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; |
|||
CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; |
|||
CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; |
|||
CP15[CP15_ISA_FEATURE_0] = 0x00100011; |
|||
CP15[CP15_ISA_FEATURE_1] = 0x12002111; |
|||
CP15[CP15_ISA_FEATURE_2] = 0x11221011; |
|||
CP15[CP15_ISA_FEATURE_3] = 0x01102131; |
|||
CP15[CP15_ISA_FEATURE_4] = 0x00000141; |
|||
|
|||
// c1
|
|||
CP15[CP15_CONTROL] = 0x00054078; |
|||
CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; |
|||
CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; |
|||
|
|||
// c2
|
|||
CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; |
|||
CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; |
|||
CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; |
|||
|
|||
// c3
|
|||
CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; |
|||
|
|||
// c7
|
|||
CP15[CP15_PHYS_ADDRESS] = 0x00000000; |
|||
|
|||
// c9
|
|||
CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; |
|||
|
|||
// c10
|
|||
CP15[CP15_TLB_LOCKDOWN] = 0x00000000; |
|||
CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; |
|||
CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; |
|||
|
|||
// c13
|
|||
CP15[CP15_PID] = 0x00000000; |
|||
CP15[CP15_CONTEXT_ID] = 0x00000000; |
|||
CP15[CP15_THREAD_UPRW] = 0x00000000; |
|||
CP15[CP15_THREAD_URO] = 0x00000000; |
|||
CP15[CP15_THREAD_PRW] = 0x00000000; |
|||
|
|||
// c15
|
|||
CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; |
|||
CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; |
|||
} |
|||
|
|||
static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { |
|||
if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { |
|||
LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address); |
|||
GDBStub::Break(true); |
|||
} |
|||
} |
|||
|
|||
u8 ARMul_State::ReadMemory8(u32 address) const { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); |
|||
|
|||
return Memory::Read8(address); |
|||
} |
|||
|
|||
u16 ARMul_State::ReadMemory16(u32 address) const { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); |
|||
|
|||
u16 data = Memory::Read16(address); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap16(data); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
u32 ARMul_State::ReadMemory32(u32 address) const { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); |
|||
|
|||
u32 data = Memory::Read32(address); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap32(data); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
u64 ARMul_State::ReadMemory64(u32 address) const { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); |
|||
|
|||
u64 data = Memory::Read64(address); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap64(data); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
void ARMul_State::WriteMemory8(u32 address, u8 data) { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); |
|||
|
|||
Memory::Write8(address, data); |
|||
} |
|||
|
|||
void ARMul_State::WriteMemory16(u32 address, u16 data) { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap16(data); |
|||
|
|||
Memory::Write16(address, data); |
|||
} |
|||
|
|||
void ARMul_State::WriteMemory32(u32 address, u32 data) { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap32(data); |
|||
|
|||
Memory::Write32(address, data); |
|||
} |
|||
|
|||
void ARMul_State::WriteMemory64(u32 address, u64 data) { |
|||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); |
|||
|
|||
if (InBigEndianMode()) |
|||
data = Common::swap64(data); |
|||
|
|||
Memory::Write64(address, data); |
|||
} |
|||
|
|||
// Reads from the CP15 registers. Used with implementation of the MRC instruction.
|
|||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
|||
// are not implemented.
|
|||
u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const { |
|||
// Unprivileged registers
|
|||
if (crn == 13 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_THREAD_UPRW]; |
|||
|
|||
if (opcode_2 == 3) |
|||
return CP15[CP15_THREAD_URO]; |
|||
} |
|||
|
|||
if (InAPrivilegedMode()) { |
|||
if (crn == 0 && opcode_1 == 0) { |
|||
if (crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_MAIN_ID]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_CACHE_TYPE]; |
|||
|
|||
if (opcode_2 == 3) |
|||
return CP15[CP15_TLB_TYPE]; |
|||
|
|||
if (opcode_2 == 5) |
|||
return CP15[CP15_CPU_ID]; |
|||
} else if (crm == 1) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_PROCESSOR_FEATURE_0]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_PROCESSOR_FEATURE_1]; |
|||
|
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_DEBUG_FEATURE_0]; |
|||
|
|||
if (opcode_2 == 4) |
|||
return CP15[CP15_MEMORY_MODEL_FEATURE_0]; |
|||
|
|||
if (opcode_2 == 5) |
|||
return CP15[CP15_MEMORY_MODEL_FEATURE_1]; |
|||
|
|||
if (opcode_2 == 6) |
|||
return CP15[CP15_MEMORY_MODEL_FEATURE_2]; |
|||
|
|||
if (opcode_2 == 7) |
|||
return CP15[CP15_MEMORY_MODEL_FEATURE_3]; |
|||
} else if (crm == 2) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_ISA_FEATURE_0]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_ISA_FEATURE_1]; |
|||
|
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_ISA_FEATURE_2]; |
|||
|
|||
if (opcode_2 == 3) |
|||
return CP15[CP15_ISA_FEATURE_3]; |
|||
|
|||
if (opcode_2 == 4) |
|||
return CP15[CP15_ISA_FEATURE_4]; |
|||
} |
|||
} |
|||
|
|||
if (crn == 1 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_CONTROL]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_AUXILIARY_CONTROL]; |
|||
|
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; |
|||
} |
|||
|
|||
if (crn == 2 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_TRANSLATION_BASE_TABLE_0]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_TRANSLATION_BASE_TABLE_1]; |
|||
|
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_TRANSLATION_BASE_CONTROL]; |
|||
} |
|||
|
|||
if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |
|||
return CP15[CP15_DOMAIN_ACCESS_CONTROL]; |
|||
|
|||
if (crn == 5 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_FAULT_STATUS]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_INSTR_FAULT_STATUS]; |
|||
} |
|||
|
|||
if (crn == 6 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_FAULT_ADDRESS]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_WFAR]; |
|||
} |
|||
|
|||
if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) |
|||
return CP15[CP15_PHYS_ADDRESS]; |
|||
|
|||
if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |
|||
return CP15[CP15_DATA_CACHE_LOCKDOWN]; |
|||
|
|||
if (crn == 10 && opcode_1 == 0) { |
|||
if (crm == 0 && opcode_2 == 0) |
|||
return CP15[CP15_TLB_LOCKDOWN]; |
|||
|
|||
if (crm == 2) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_PRIMARY_REGION_REMAP]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_NORMAL_REGION_REMAP]; |
|||
} |
|||
} |
|||
|
|||
if (crn == 13 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_PID]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_CONTEXT_ID]; |
|||
|
|||
if (opcode_2 == 4) |
|||
return CP15[CP15_THREAD_PRW]; |
|||
} |
|||
|
|||
if (crn == 15) { |
|||
if (opcode_1 == 0 && crm == 12) { |
|||
if (opcode_2 == 0) |
|||
return CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; |
|||
|
|||
if (opcode_2 == 1) |
|||
return CP15[CP15_CYCLE_COUNTER]; |
|||
|
|||
if (opcode_2 == 2) |
|||
return CP15[CP15_COUNT_0]; |
|||
|
|||
if (opcode_2 == 3) |
|||
return CP15[CP15_COUNT_1]; |
|||
} |
|||
|
|||
if (opcode_1 == 5 && opcode_2 == 2) { |
|||
if (crm == 5) |
|||
return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; |
|||
|
|||
if (crm == 6) |
|||
return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; |
|||
|
|||
if (crm == 7) |
|||
return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; |
|||
} |
|||
|
|||
if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) |
|||
return CP15[CP15_TLB_DEBUG_CONTROL]; |
|||
} |
|||
} |
|||
|
|||
LOG_ERROR(Core_ARM, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", |
|||
crn, crm, opcode_1, opcode_2); |
|||
return 0; |
|||
} |
|||
|
|||
// Write to the CP15 registers. Used with implementation of the MCR instruction.
|
|||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
|||
// are not implemented.
|
|||
void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) { |
|||
if (InAPrivilegedMode()) { |
|||
if (crn == 1 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_CONTROL] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_AUXILIARY_CONTROL] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; |
|||
} else if (crn == 2 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_TRANSLATION_BASE_CONTROL] = value; |
|||
} else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { |
|||
CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; |
|||
} else if (crn == 5 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_FAULT_STATUS] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INSTR_FAULT_STATUS] = value; |
|||
} else if (crn == 6 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_FAULT_ADDRESS] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_WFAR] = value; |
|||
} else if (crn == 7 && opcode_1 == 0) { |
|||
if (crm == 0 && opcode_2 == 4) { |
|||
CP15[CP15_WAIT_FOR_INTERRUPT] = value; |
|||
} else if (crm == 4 && opcode_2 == 0) { |
|||
// NOTE: Not entirely accurate. This should do permission checks.
|
|||
CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); |
|||
} else if (crm == 5) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_INVALIDATE_INSTR_CACHE] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; |
|||
else if (opcode_2 == 6) |
|||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; |
|||
else if (opcode_2 == 7) |
|||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; |
|||
} else if (crm == 6) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_INVALIDATE_DATA_CACHE] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; |
|||
} else if (crm == 7 && opcode_2 == 0) { |
|||
CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; |
|||
} else if (crm == 10) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_CLEAN_DATA_CACHE] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; |
|||
} else if (crm == 14) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; |
|||
} |
|||
} else if (crn == 8 && opcode_1 == 0) { |
|||
if (crm == 5) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_INVALIDATE_ITLB] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; |
|||
else if (opcode_2 == 3) |
|||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; |
|||
} else if (crm == 6) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_INVALIDATE_DTLB] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; |
|||
else if (opcode_2 == 3) |
|||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; |
|||
} else if (crm == 7) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_INVALIDATE_UTLB] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; |
|||
else if (opcode_2 == 3) |
|||
CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; |
|||
} |
|||
} else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { |
|||
CP15[CP15_DATA_CACHE_LOCKDOWN] = value; |
|||
} else if (crn == 10 && opcode_1 == 0) { |
|||
if (crm == 0 && opcode_2 == 0) { |
|||
CP15[CP15_TLB_LOCKDOWN] = value; |
|||
} else if (crm == 2) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_PRIMARY_REGION_REMAP] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_NORMAL_REGION_REMAP] = value; |
|||
} |
|||
} else if (crn == 13 && opcode_1 == 0 && crm == 0) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_PID] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_CONTEXT_ID] = value; |
|||
else if (opcode_2 == 3) |
|||
CP15[CP15_THREAD_URO] = value; |
|||
else if (opcode_2 == 4) |
|||
CP15[CP15_THREAD_PRW] = value; |
|||
} else if (crn == 15) { |
|||
if (opcode_1 == 0 && crm == 12) { |
|||
if (opcode_2 == 0) |
|||
CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; |
|||
else if (opcode_2 == 1) |
|||
CP15[CP15_CYCLE_COUNTER] = value; |
|||
else if (opcode_2 == 2) |
|||
CP15[CP15_COUNT_0] = value; |
|||
else if (opcode_2 == 3) |
|||
CP15[CP15_COUNT_1] = value; |
|||
} else if (opcode_1 == 5) { |
|||
if (crm == 4) { |
|||
if (opcode_2 == 2) |
|||
CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; |
|||
else if (opcode_2 == 4) |
|||
CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; |
|||
} else if (crm == 5 && opcode_2 == 2) { |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; |
|||
} else if (crm == 6 && opcode_2 == 2) { |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; |
|||
} else if (crm == 7 && opcode_2 == 2) { |
|||
CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; |
|||
} |
|||
} else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) { |
|||
CP15[CP15_TLB_DEBUG_CONTROL] = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Unprivileged registers
|
|||
if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) { |
|||
CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; |
|||
} else if (crn == 7 && opcode_1 == 0 && crm == 10) { |
|||
if (opcode_2 == 4) |
|||
CP15[CP15_DATA_SYNC_BARRIER] = value; |
|||
else if (opcode_2 == 5) |
|||
CP15[CP15_DATA_MEMORY_BARRIER] = value; |
|||
} else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) { |
|||
CP15[CP15_THREAD_UPRW] = value; |
|||
} |
|||
} |
|||
@ -1,245 +0,0 @@ |
|||
/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. |
|||
Copyright (C) 1994 Advanced RISC Machines Ltd. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <unordered_map> |
|||
#include "common/common_types.h" |
|||
#include "core/arm/skyeye_common/arm_regformat.h" |
|||
|
|||
// Signal levels |
|||
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 }; |
|||
|
|||
// Cache types |
|||
enum { |
|||
NONCACHE = 0, |
|||
DATACACHE = 1, |
|||
INSTCACHE = 2, |
|||
}; |
|||
|
|||
// ARM privilege modes |
|||
enum PrivilegeMode { |
|||
USER32MODE = 16, |
|||
FIQ32MODE = 17, |
|||
IRQ32MODE = 18, |
|||
SVC32MODE = 19, |
|||
ABORT32MODE = 23, |
|||
UNDEF32MODE = 27, |
|||
SYSTEM32MODE = 31 |
|||
}; |
|||
|
|||
// ARM privilege mode register banks |
|||
enum { |
|||
USERBANK = 0, |
|||
FIQBANK = 1, |
|||
IRQBANK = 2, |
|||
SVCBANK = 3, |
|||
ABORTBANK = 4, |
|||
UNDEFBANK = 5, |
|||
DUMMYBANK = 6, |
|||
SYSTEMBANK = 7 |
|||
}; |
|||
|
|||
// Hardware vector addresses |
|||
enum { |
|||
ARMResetV = 0, |
|||
ARMUndefinedInstrV = 4, |
|||
ARMSWIV = 8, |
|||
ARMPrefetchAbortV = 12, |
|||
ARMDataAbortV = 16, |
|||
ARMAddrExceptnV = 20, |
|||
ARMIRQV = 24, |
|||
ARMFIQV = 28, |
|||
ARMErrorV = 32, // This is an offset, not an address! |
|||
|
|||
ARMul_ResetV = ARMResetV, |
|||
ARMul_UndefinedInstrV = ARMUndefinedInstrV, |
|||
ARMul_SWIV = ARMSWIV, |
|||
ARMul_PrefetchAbortV = ARMPrefetchAbortV, |
|||
ARMul_DataAbortV = ARMDataAbortV, |
|||
ARMul_AddrExceptnV = ARMAddrExceptnV, |
|||
ARMul_IRQV = ARMIRQV, |
|||
ARMul_FIQV = ARMFIQV |
|||
}; |
|||
|
|||
// Coprocessor status values |
|||
enum { |
|||
ARMul_FIRST = 0, |
|||
ARMul_TRANSFER = 1, |
|||
ARMul_BUSY = 2, |
|||
ARMul_DATA = 3, |
|||
ARMul_INTERRUPT = 4, |
|||
ARMul_DONE = 0, |
|||
ARMul_CANT = 1, |
|||
ARMul_INC = 3 |
|||
}; |
|||
|
|||
// Instruction condition codes |
|||
enum ConditionCode { |
|||
EQ = 0, |
|||
NE = 1, |
|||
CS = 2, |
|||
CC = 3, |
|||
MI = 4, |
|||
PL = 5, |
|||
VS = 6, |
|||
VC = 7, |
|||
HI = 8, |
|||
LS = 9, |
|||
GE = 10, |
|||
LT = 11, |
|||
GT = 12, |
|||
LE = 13, |
|||
AL = 14, |
|||
NV = 15, |
|||
}; |
|||
|
|||
// Flags for use with the APSR. |
|||
enum : u32 { |
|||
NBIT = (1U << 31U), |
|||
ZBIT = (1 << 30), |
|||
CBIT = (1 << 29), |
|||
VBIT = (1 << 28), |
|||
QBIT = (1 << 27), |
|||
JBIT = (1 << 24), |
|||
EBIT = (1 << 9), |
|||
ABIT = (1 << 8), |
|||
IBIT = (1 << 7), |
|||
FBIT = (1 << 6), |
|||
TBIT = (1 << 5), |
|||
|
|||
// Masks for groups of bits in the APSR. |
|||
MODEBITS = 0x1F, |
|||
INTBITS = 0x1C0, |
|||
}; |
|||
|
|||
// Values for Emulate. |
|||
enum { |
|||
STOP = 0, // Stop |
|||
CHANGEMODE = 1, // Change mode |
|||
ONCE = 2, // Execute just one iteration |
|||
RUN = 3 // Continuous execution |
|||
}; |
|||
|
|||
struct ARMul_State final { |
|||
public: |
|||
explicit ARMul_State(PrivilegeMode initial_mode); |
|||
|
|||
void ChangePrivilegeMode(u32 new_mode); |
|||
void Reset(); |
|||
|
|||
// Reads/writes data in big/little endian format based on the |
|||
// state of the E (endian) bit in the APSR. |
|||
u8 ReadMemory8(u32 address) const; |
|||
u16 ReadMemory16(u32 address) const; |
|||
u32 ReadMemory32(u32 address) const; |
|||
u64 ReadMemory64(u32 address) const; |
|||
void WriteMemory8(u32 address, u8 data); |
|||
void WriteMemory16(u32 address, u16 data); |
|||
void WriteMemory32(u32 address, u32 data); |
|||
void WriteMemory64(u32 address, u64 data); |
|||
|
|||
u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; |
|||
void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); |
|||
|
|||
// Exclusive memory access functions |
|||
bool IsExclusiveMemoryAccess(u32 address) const { |
|||
return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK); |
|||
} |
|||
void SetExclusiveMemoryAddress(u32 address) { |
|||
exclusive_tag = address & RESERVATION_GRANULE_MASK; |
|||
exclusive_state = true; |
|||
} |
|||
void UnsetExclusiveMemoryAddress() { |
|||
exclusive_tag = 0xFFFFFFFF; |
|||
exclusive_state = false; |
|||
} |
|||
|
|||
// Whether or not the given CPU is in big endian mode (E bit is set) |
|||
bool InBigEndianMode() const { |
|||
return (Cpsr & (1 << 9)) != 0; |
|||
} |
|||
// Whether or not the given CPU is in a mode other than user mode. |
|||
bool InAPrivilegedMode() const { |
|||
return (Mode != USER32MODE); |
|||
} |
|||
// Note that for the 3DS, a Thumb instruction will only ever be |
|||
// two bytes in size. Thus we don't need to worry about ThumbEE |
|||
// or Thumb-2 where instructions can be 4 bytes in length. |
|||
u32 GetInstructionSize() const { |
|||
return TFlag ? 2 : 4; |
|||
} |
|||
|
|||
std::array<u32, 16> Reg{}; // The current register file |
|||
std::array<u32, 2> Reg_usr{}; |
|||
std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC |
|||
std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT |
|||
std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF |
|||
std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ |
|||
std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ |
|||
std::array<u32, 7> Spsr{}; // The exception psr's |
|||
std::array<u32, CP15_REGISTER_COUNT> CP15{}; |
|||
|
|||
// FPSID, FPSCR, and FPEXC |
|||
std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{}; |
|||
|
|||
// VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). |
|||
// VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), |
|||
// and only 32 singleword registers are accessible (S0-S31). |
|||
std::array<u32, 64> ExtReg{}; |
|||
|
|||
u32 Emulate; // To start and stop emulation |
|||
u32 Cpsr; // The current PSR |
|||
u32 Spsr_copy; |
|||
u32 phys_pc; |
|||
|
|||
u32 Mode; // The current mode |
|||
u32 Bank; // The current register bank |
|||
|
|||
u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed |
|||
unsigned int shifter_carry_out; |
|||
|
|||
u32 TFlag; // Thumb state |
|||
|
|||
unsigned long long NumInstrs; // The number of instructions executed |
|||
unsigned NumInstrsToExecute; |
|||
|
|||
unsigned NresetSig; // Reset the processor |
|||
unsigned NfiqSig; |
|||
unsigned NirqSig; |
|||
|
|||
unsigned abortSig; |
|||
unsigned NtransSig; |
|||
unsigned bigendSig; |
|||
unsigned syscallSig; |
|||
|
|||
// TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per |
|||
// process for our purposes), not per ARMul_State (which tracks CPU core state). |
|||
std::unordered_map<u32, std::size_t> instruction_cache; |
|||
|
|||
private: |
|||
void ResetMPCoreCP15Registers(); |
|||
|
|||
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the |
|||
// tag. This is the smallest granule allowed by the v7 spec, and is coincidentally just large |
|||
// enough to support LDR/STREXD. |
|||
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; |
|||
|
|||
u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode |
|||
bool exclusive_state; |
|||
}; |
|||
@ -1,189 +0,0 @@ |
|||
/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
|
|||
Copyright (C) 1994 Advanced RISC Machines Ltd. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|||
|
|||
#include "common/logging/log.h"
|
|||
#include "core/arm/skyeye_common/arm_regformat.h"
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
|||
#include "core/arm/skyeye_common/armsupp.h"
|
|||
|
|||
// Unsigned sum of absolute difference
|
|||
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) { |
|||
if (left > right) |
|||
return left - right; |
|||
|
|||
return right - left; |
|||
} |
|||
|
|||
// Add with carry, indicates if a carry-out or signed overflow occurred.
|
|||
u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, |
|||
bool* overflow_occurred) { |
|||
u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in; |
|||
s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in; |
|||
u64 result = (unsigned_sum & 0xFFFFFFFF); |
|||
|
|||
if (carry_out_occurred) |
|||
*carry_out_occurred = (result != unsigned_sum); |
|||
|
|||
if (overflow_occurred) |
|||
*overflow_occurred = ((s64)(s32)result != signed_sum); |
|||
|
|||
return (u32)result; |
|||
} |
|||
|
|||
// Compute whether an addition of A and B, giving RESULT, overflowed.
|
|||
bool AddOverflow(u32 a, u32 b, u32 result) { |
|||
return ((NEG(a) && NEG(b) && POS(result)) || (POS(a) && POS(b) && NEG(result))); |
|||
} |
|||
|
|||
// Compute whether a subtraction of A and B, giving RESULT, overflowed.
|
|||
bool SubOverflow(u32 a, u32 b, u32 result) { |
|||
return ((NEG(a) && POS(b) && POS(result)) || (POS(a) && NEG(b) && NEG(result))); |
|||
} |
|||
|
|||
// Returns true if the Q flag should be set as a result of overflow.
|
|||
bool ARMul_AddOverflowQ(u32 a, u32 b) { |
|||
u32 result = a + b; |
|||
if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) |
|||
return true; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
// 8-bit signed saturated addition
|
|||
u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) { |
|||
u8 result = left + right; |
|||
|
|||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) { |
|||
if (left & 0x80) |
|||
result = 0x80; |
|||
else |
|||
result = 0x7F; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 8-bit signed saturated subtraction
|
|||
u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) { |
|||
u8 result = left - right; |
|||
|
|||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) { |
|||
if (left & 0x80) |
|||
result = 0x80; |
|||
else |
|||
result = 0x7F; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 16-bit signed saturated addition
|
|||
u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) { |
|||
u16 result = left + right; |
|||
|
|||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) { |
|||
if (left & 0x8000) |
|||
result = 0x8000; |
|||
else |
|||
result = 0x7FFF; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 16-bit signed saturated subtraction
|
|||
u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) { |
|||
u16 result = left - right; |
|||
|
|||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) { |
|||
if (left & 0x8000) |
|||
result = 0x8000; |
|||
else |
|||
result = 0x7FFF; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 8-bit unsigned saturated addition
|
|||
u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) { |
|||
u8 result = left + right; |
|||
|
|||
if (result < left) |
|||
result = 0xFF; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 16-bit unsigned saturated addition
|
|||
u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) { |
|||
u16 result = left + right; |
|||
|
|||
if (result < left) |
|||
result = 0xFFFF; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// 8-bit unsigned saturated subtraction
|
|||
u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) { |
|||
if (left <= right) |
|||
return 0; |
|||
|
|||
return left - right; |
|||
} |
|||
|
|||
// 16-bit unsigned saturated subtraction
|
|||
u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) { |
|||
if (left <= right) |
|||
return 0; |
|||
|
|||
return left - right; |
|||
} |
|||
|
|||
// Signed saturation.
|
|||
u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { |
|||
const u32 max = (1 << shift) - 1; |
|||
const s32 top = (value >> shift); |
|||
|
|||
if (top > 0) { |
|||
*saturation_occurred = true; |
|||
return max; |
|||
} else if (top < -1) { |
|||
*saturation_occurred = true; |
|||
return ~max; |
|||
} |
|||
|
|||
*saturation_occurred = false; |
|||
return (u32)value; |
|||
} |
|||
|
|||
// Unsigned saturation
|
|||
u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { |
|||
const u32 max = (1 << shift) - 1; |
|||
|
|||
if (value < 0) { |
|||
*saturation_occurred = true; |
|||
return 0; |
|||
} else if ((u32)value > max) { |
|||
*saturation_occurred = true; |
|||
return max; |
|||
} |
|||
|
|||
*saturation_occurred = false; |
|||
return (u32)value; |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// Copyright 2014 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) |
|||
#define BIT(s, n) ((s >> (n)) & 1) |
|||
|
|||
#define POS(i) ((~(i)) >> 31) |
|||
#define NEG(i) ((i) >> 31) |
|||
|
|||
bool AddOverflow(u32, u32, u32); |
|||
bool SubOverflow(u32, u32, u32); |
|||
|
|||
u32 AddWithCarry(u32, u32, u32, bool*, bool*); |
|||
bool ARMul_AddOverflowQ(u32, u32); |
|||
|
|||
u8 ARMul_SignedSaturatedAdd8(u8, u8); |
|||
u8 ARMul_SignedSaturatedSub8(u8, u8); |
|||
u16 ARMul_SignedSaturatedAdd16(u16, u16); |
|||
u16 ARMul_SignedSaturatedSub16(u16, u16); |
|||
|
|||
u8 ARMul_UnsignedSaturatedAdd8(u8, u8); |
|||
u16 ARMul_UnsignedSaturatedAdd16(u16, u16); |
|||
u8 ARMul_UnsignedSaturatedSub8(u8, u8); |
|||
u16 ARMul_UnsignedSaturatedSub16(u16, u16); |
|||
u8 ARMul_UnsignedAbsoluteDifference(u8, u8); |
|||
u32 ARMul_SignedSatQ(s32, u8, bool*); |
|||
u32 ARMul_UnsignedSatQ(s32, u8, bool*); |
|||
@ -1,83 +0,0 @@ |
|||
/* |
|||
* arch/arm/include/asm/vfp.h |
|||
* |
|||
* VFP register definitions. |
|||
* First, the standard VFP set. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
// ARM11 MPCore FPSID Information |
|||
// Note that these are used as values and not as flags. |
|||
enum : u32 { |
|||
VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0 |
|||
VFP_FPSID_SW = 0, // Software emulation bit value |
|||
VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number |
|||
VFP_FPSID_PARTNUM = 0x20, // Part number |
|||
VFP_FPSID_VARIANT = 0xB, // Variant number |
|||
VFP_FPSID_REVISION = 0x4 // Revision number |
|||
}; |
|||
|
|||
// FPEXC bits |
|||
enum : u32 { |
|||
FPEXC_EX = (1U << 31U), |
|||
FPEXC_EN = (1 << 30), |
|||
FPEXC_DEX = (1 << 29), |
|||
FPEXC_FP2V = (1 << 28), |
|||
FPEXC_VV = (1 << 27), |
|||
FPEXC_TFV = (1 << 26), |
|||
FPEXC_LENGTH_BIT = (8), |
|||
FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT), |
|||
FPEXC_IDF = (1 << 7), |
|||
FPEXC_IXF = (1 << 4), |
|||
FPEXC_UFF = (1 << 3), |
|||
FPEXC_OFF = (1 << 2), |
|||
FPEXC_DZF = (1 << 1), |
|||
FPEXC_IOF = (1 << 0), |
|||
FPEXC_TRAP_MASK = (FPEXC_IDF | FPEXC_IXF | FPEXC_UFF | FPEXC_OFF | FPEXC_DZF | FPEXC_IOF) |
|||
}; |
|||
|
|||
// FPSCR Flags |
|||
enum : u32 { |
|||
FPSCR_NFLAG = (1U << 31U), // Negative condition flag |
|||
FPSCR_ZFLAG = (1 << 30), // Zero condition flag |
|||
FPSCR_CFLAG = (1 << 29), // Carry condition flag |
|||
FPSCR_VFLAG = (1 << 28), // Overflow condition flag |
|||
|
|||
FPSCR_QC = (1 << 27), // Cumulative saturation bit |
|||
FPSCR_AHP = (1 << 26), // Alternative half-precision control bit |
|||
FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit |
|||
FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit |
|||
FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask |
|||
FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask |
|||
FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask |
|||
|
|||
FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable. |
|||
FPSCR_IXE = (1 << 12), // Inexact exception trap enable |
|||
FPSCR_UFE = (1 << 11), // Undeflow exception trap enable |
|||
FPSCR_OFE = (1 << 10), // Overflow exception trap enable |
|||
FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable |
|||
FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable |
|||
|
|||
FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit |
|||
FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit |
|||
FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit |
|||
FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit |
|||
FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit |
|||
FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit |
|||
}; |
|||
|
|||
// FPSCR bit offsets |
|||
enum : u32 { |
|||
FPSCR_RMODE_BIT = 22, |
|||
FPSCR_STRIDE_BIT = 20, |
|||
FPSCR_LENGTH_BIT = 16, |
|||
}; |
|||
|
|||
// FPSCR rounding modes |
|||
enum : u32 { |
|||
FPSCR_ROUND_NEAREST = (0 << 22), |
|||
FPSCR_ROUND_PLUSINF = (1 << 22), |
|||
FPSCR_ROUND_MINUSINF = (2 << 22), |
|||
FPSCR_ROUND_TOZERO = (3 << 22) |
|||
}; |
|||
@ -1,137 +0,0 @@ |
|||
/*
|
|||
armvfp.c - ARM VFPv3 emulation unit |
|||
Copyright (C) 2003 Skyeye Develop Group |
|||
for help please send mail to <skyeye-developer@lists.gro.clinux.org> |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
*/ |
|||
|
|||
/* Note: this file handles interface with arm core and vfp registers */ |
|||
|
|||
#include "common/common_funcs.h"
|
|||
#include "common/common_types.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
|||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
|||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
|||
|
|||
void VFPInit(ARMul_State* state) { |
|||
state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN << 24 | VFP_FPSID_SW << 23 | VFP_FPSID_SUBARCH << 16 | |
|||
VFP_FPSID_PARTNUM << 8 | VFP_FPSID_VARIANT << 4 | VFP_FPSID_REVISION; |
|||
state->VFP[VFP_FPEXC] = 0; |
|||
state->VFP[VFP_FPSCR] = 0; |
|||
|
|||
// ARM11 MPCore instruction register reset values.
|
|||
state->VFP[VFP_FPINST] = 0xEE000A00; |
|||
state->VFP[VFP_FPINST2] = 0; |
|||
|
|||
// ARM11 MPCore feature register values.
|
|||
state->VFP[VFP_MVFR0] = 0x11111111; |
|||
state->VFP[VFP_MVFR1] = 0; |
|||
} |
|||
|
|||
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) { |
|||
if (to_arm) { |
|||
*value = state->ExtReg[n]; |
|||
} else { |
|||
state->ExtReg[n] = *value; |
|||
} |
|||
} |
|||
|
|||
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { |
|||
if (to_arm) { |
|||
*value2 = state->ExtReg[n * 2 + 1]; |
|||
*value1 = state->ExtReg[n * 2]; |
|||
} else { |
|||
state->ExtReg[n * 2 + 1] = *value2; |
|||
state->ExtReg[n * 2] = *value1; |
|||
} |
|||
} |
|||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { |
|||
if (to_arm) { |
|||
*value1 = state->ExtReg[n + 0]; |
|||
*value2 = state->ExtReg[n + 1]; |
|||
} else { |
|||
state->ExtReg[n + 0] = *value1; |
|||
state->ExtReg[n + 1] = *value2; |
|||
} |
|||
} |
|||
|
|||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) { |
|||
if (single) { |
|||
state->ExtReg[d] = imm; |
|||
} else { |
|||
/* Check endian please */ |
|||
state->ExtReg[d * 2 + 1] = imm; |
|||
state->ExtReg[d * 2] = 0; |
|||
} |
|||
} |
|||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) { |
|||
if (single) { |
|||
state->ExtReg[d] = state->ExtReg[m]; |
|||
} else { |
|||
/* Check endian please */ |
|||
state->ExtReg[d * 2 + 1] = state->ExtReg[m * 2 + 1]; |
|||
state->ExtReg[d * 2] = state->ExtReg[m * 2]; |
|||
} |
|||
} |
|||
|
|||
/* Miscellaneous functions */ |
|||
s32 vfp_get_float(ARMul_State* state, unsigned int reg) { |
|||
LOG_TRACE(Core_ARM, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]); |
|||
return state->ExtReg[reg]; |
|||
} |
|||
|
|||
void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) { |
|||
LOG_TRACE(Core_ARM, "VFP put float: s%d <= [%08x]", reg, val); |
|||
state->ExtReg[reg] = val; |
|||
} |
|||
|
|||
u64 vfp_get_double(ARMul_State* state, unsigned int reg) { |
|||
u64 result = ((u64)state->ExtReg[reg * 2 + 1]) << 32 | state->ExtReg[reg * 2]; |
|||
LOG_TRACE(Core_ARM, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result); |
|||
return result; |
|||
} |
|||
|
|||
void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) { |
|||
LOG_TRACE(Core_ARM, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, |
|||
(u32)(val >> 32), (u32)(val & 0xffffffff)); |
|||
state->ExtReg[reg * 2] = (u32)(val & 0xffffffff); |
|||
state->ExtReg[reg * 2 + 1] = (u32)(val >> 32); |
|||
} |
|||
|
|||
/*
|
|||
* Process bitmask of exception conditions. (from vfpmodule.c) |
|||
*/ |
|||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) { |
|||
LOG_TRACE(Core_ARM, "VFP: raising exceptions %08x", exceptions); |
|||
|
|||
if (exceptions == VFP_EXCEPTION_ERROR) { |
|||
LOG_CRITICAL(Core_ARM, "unhandled bounce %x", inst); |
|||
Crash(); |
|||
} |
|||
|
|||
/*
|
|||
* If any of the status flags are set, update the FPSCR. |
|||
* Comparison instructions always return at least one of |
|||
* these flags set. |
|||
*/ |
|||
if (exceptions & (FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG)) |
|||
fpscr &= ~(FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG); |
|||
|
|||
fpscr |= exceptions; |
|||
|
|||
state->VFP[VFP_FPSCR] = fpscr; |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
/* |
|||
vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface |
|||
Copyright (C) 2003 Skyeye Develop Group |
|||
for help please send mail to <skyeye-developer@lists.gro.clinux.org> |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ |
|||
|
|||
#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM, "in func %s, " #x " untested", __FUNCTION__); |
|||
#define CHECK_VFP_ENABLED |
|||
#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); |
|||
|
|||
void VFPInit(ARMul_State* state); |
|||
|
|||
s32 vfp_get_float(ARMul_State* state, u32 reg); |
|||
void vfp_put_float(ARMul_State* state, s32 val, u32 reg); |
|||
u64 vfp_get_double(ARMul_State* state, u32 reg); |
|||
void vfp_put_double(ARMul_State* state, u64 val, u32 reg); |
|||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr); |
|||
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); |
|||
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); |
|||
|
|||
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value); |
|||
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); |
|||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); |
|||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm); |
|||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm); |
|||
@ -1,433 +0,0 @@ |
|||
/* |
|||
vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper |
|||
Copyright (C) 2003 Skyeye Develop Group |
|||
for help please send mail to <skyeye-developer@lists.gro.clinux.org> |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
*/ |
|||
|
|||
/* |
|||
* The following code is derivative from Linux Android kernel vfp |
|||
* floating point support. |
|||
* |
|||
* Copyright (C) 2004 ARM Limited. |
|||
* Written by Deep Blue Solutions Limited. |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License version 2 as |
|||
* published by the Free Software Foundation. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdio> |
|||
#include "common/common_types.h" |
|||
#include "core/arm/skyeye_common/armstate.h" |
|||
#include "core/arm/skyeye_common/vfp/asm_vfp.h" |
|||
|
|||
#define do_div(n, base) \ |
|||
{ n /= base; } |
|||
|
|||
enum : u32 { |
|||
FOP_MASK = 0x00b00040, |
|||
FOP_FMAC = 0x00000000, |
|||
FOP_FNMAC = 0x00000040, |
|||
FOP_FMSC = 0x00100000, |
|||
FOP_FNMSC = 0x00100040, |
|||
FOP_FMUL = 0x00200000, |
|||
FOP_FNMUL = 0x00200040, |
|||
FOP_FADD = 0x00300000, |
|||
FOP_FSUB = 0x00300040, |
|||
FOP_FDIV = 0x00800000, |
|||
FOP_EXT = 0x00b00040 |
|||
}; |
|||
|
|||
#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) |
|||
|
|||
enum : u32 { |
|||
FEXT_MASK = 0x000f0080, |
|||
FEXT_FCPY = 0x00000000, |
|||
FEXT_FABS = 0x00000080, |
|||
FEXT_FNEG = 0x00010000, |
|||
FEXT_FSQRT = 0x00010080, |
|||
FEXT_FCMP = 0x00040000, |
|||
FEXT_FCMPE = 0x00040080, |
|||
FEXT_FCMPZ = 0x00050000, |
|||
FEXT_FCMPEZ = 0x00050080, |
|||
FEXT_FCVT = 0x00070080, |
|||
FEXT_FUITO = 0x00080000, |
|||
FEXT_FSITO = 0x00080080, |
|||
FEXT_FTOUI = 0x000c0000, |
|||
FEXT_FTOUIZ = 0x000c0080, |
|||
FEXT_FTOSI = 0x000d0000, |
|||
FEXT_FTOSIZ = 0x000d0080 |
|||
}; |
|||
|
|||
#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) |
|||
|
|||
#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) |
|||
#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) |
|||
#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) |
|||
#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) |
|||
#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) |
|||
#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) |
|||
|
|||
#define vfp_single(inst) (((inst)&0x0000f00) == 0xa00) |
|||
|
|||
inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) { |
|||
if (shift) { |
|||
if (shift < 32) |
|||
val = val >> shift | ((val << (32 - shift)) != 0); |
|||
else |
|||
val = val != 0; |
|||
} |
|||
return val; |
|||
} |
|||
|
|||
inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) { |
|||
if (shift) { |
|||
if (shift < 64) |
|||
val = val >> shift | ((val << (64 - shift)) != 0); |
|||
else |
|||
val = val != 0; |
|||
} |
|||
return val; |
|||
} |
|||
|
|||
inline u32 vfp_hi64to32jamming(u64 val) { |
|||
u32 v; |
|||
u32 highval = val >> 32; |
|||
u32 lowval = val & 0xffffffff; |
|||
|
|||
if (lowval >= 1) |
|||
v = highval | 1; |
|||
else |
|||
v = highval; |
|||
|
|||
return v; |
|||
} |
|||
|
|||
inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { |
|||
*resl = nl + ml; |
|||
*resh = nh + mh; |
|||
if (*resl < nl) |
|||
*resh += 1; |
|||
} |
|||
|
|||
inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { |
|||
*resl = nl - ml; |
|||
*resh = nh - mh; |
|||
if (*resl > nl) |
|||
*resh -= 1; |
|||
} |
|||
|
|||
inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) { |
|||
u32 nh, nl, mh, ml; |
|||
u64 rh, rma, rmb, rl; |
|||
|
|||
nl = static_cast<u32>(n); |
|||
ml = static_cast<u32>(m); |
|||
rl = (u64)nl * ml; |
|||
|
|||
nh = n >> 32; |
|||
rma = (u64)nh * ml; |
|||
|
|||
mh = m >> 32; |
|||
rmb = (u64)nl * mh; |
|||
rma += rmb; |
|||
|
|||
rh = (u64)nh * mh; |
|||
rh += ((u64)(rma < rmb) << 32) + (rma >> 32); |
|||
|
|||
rma <<= 32; |
|||
rl += rma; |
|||
rh += (rl < rma); |
|||
|
|||
*resl = rl; |
|||
*resh = rh; |
|||
} |
|||
|
|||
inline void shift64left(u64* resh, u64* resl, u64 n) { |
|||
*resh = n >> 63; |
|||
*resl = n << 1; |
|||
} |
|||
|
|||
inline u64 vfp_hi64multiply64(u64 n, u64 m) { |
|||
u64 rh, rl; |
|||
mul64to128(&rh, &rl, n, m); |
|||
return rh | (rl != 0); |
|||
} |
|||
|
|||
inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) { |
|||
u64 mh, ml, remh, reml, termh, terml, z; |
|||
|
|||
if (nh >= m) |
|||
return ~0ULL; |
|||
mh = m >> 32; |
|||
if (mh << 32 <= nh) { |
|||
z = 0xffffffff00000000ULL; |
|||
} else { |
|||
z = nh; |
|||
do_div(z, mh); |
|||
z <<= 32; |
|||
} |
|||
mul64to128(&termh, &terml, m, z); |
|||
sub128(&remh, &reml, nh, nl, termh, terml); |
|||
ml = m << 32; |
|||
while ((s64)remh < 0) { |
|||
z -= 0x100000000ULL; |
|||
add128(&remh, &reml, remh, reml, mh, ml); |
|||
} |
|||
remh = (remh << 32) | (reml >> 32); |
|||
if (mh << 32 <= remh) { |
|||
z |= 0xffffffff; |
|||
} else { |
|||
do_div(remh, mh); |
|||
z |= remh; |
|||
} |
|||
return z; |
|||
} |
|||
|
|||
// Operations on unpacked elements |
|||
#define vfp_sign_negate(sign) (sign ^ 0x8000) |
|||
|
|||
// Single-precision |
|||
struct vfp_single { |
|||
s16 exponent; |
|||
u16 sign; |
|||
u32 significand; |
|||
}; |
|||
|
|||
// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa |
|||
// VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent |
|||
// VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand |
|||
// which are not propagated to the float upon packing. |
|||
#define VFP_SINGLE_MANTISSA_BITS (23) |
|||
#define VFP_SINGLE_EXPONENT_BITS (8) |
|||
#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) |
|||
#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) |
|||
|
|||
// The bit in an unpacked float which indicates that it is a quiet NaN |
|||
#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS)) |
|||
|
|||
// Operations on packed single-precision numbers |
|||
#define vfp_single_packed_sign(v) ((v)&0x80000000) |
|||
#define vfp_single_packed_negate(v) ((v) ^ 0x80000000) |
|||
#define vfp_single_packed_abs(v) ((v) & ~0x80000000) |
|||
#define vfp_single_packed_exponent(v) \ |
|||
(((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) |
|||
#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) |
|||
|
|||
enum : u32 { |
|||
VFP_NUMBER = (1 << 0), |
|||
VFP_ZERO = (1 << 1), |
|||
VFP_DENORMAL = (1 << 2), |
|||
VFP_INFINITY = (1 << 3), |
|||
VFP_NAN = (1 << 4), |
|||
VFP_NAN_SIGNAL = (1 << 5), |
|||
|
|||
VFP_QNAN = (VFP_NAN), |
|||
VFP_SNAN = (VFP_NAN | VFP_NAN_SIGNAL) |
|||
}; |
|||
|
|||
inline int vfp_single_type(const vfp_single* s) { |
|||
int type = VFP_NUMBER; |
|||
if (s->exponent == 255) { |
|||
if (s->significand == 0) |
|||
type = VFP_INFINITY; |
|||
else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) |
|||
type = VFP_QNAN; |
|||
else |
|||
type = VFP_SNAN; |
|||
} else if (s->exponent == 0) { |
|||
if (s->significand == 0) |
|||
type |= VFP_ZERO; |
|||
else |
|||
type |= VFP_DENORMAL; |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
// Unpack a single-precision float. Note that this returns the magnitude |
|||
// of the single-precision float mantissa with the 1. if necessary, |
|||
// aligned to bit 30. |
|||
inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) { |
|||
u32 exceptions = 0; |
|||
s->sign = vfp_single_packed_sign(val) >> 16, s->exponent = vfp_single_packed_exponent(val); |
|||
|
|||
u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; |
|||
if (s->exponent && s->exponent != 255) |
|||
significand |= 0x40000000; |
|||
s->significand = significand; |
|||
|
|||
// If flush-to-zero mode is enabled, turn the denormal into zero. |
|||
// On a VFPv2 architecture, the sign of the zero is always positive. |
|||
if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) { |
|||
s->sign = 0; |
|||
s->exponent = 0; |
|||
s->significand = 0; |
|||
exceptions |= FPSCR_IDC; |
|||
} |
|||
return exceptions; |
|||
} |
|||
|
|||
// Re-pack a single-precision float. This assumes that the float is |
|||
// already normalised such that the MSB is bit 30, _not_ bit 31. |
|||
inline s32 vfp_single_pack(const vfp_single* s) { |
|||
u32 val = (s->sign << 16) + (s->exponent << VFP_SINGLE_MANTISSA_BITS) + |
|||
(s->significand >> VFP_SINGLE_LOW_BITS); |
|||
return (s32)val; |
|||
} |
|||
|
|||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, |
|||
const char* func); |
|||
|
|||
// Double-precision |
|||
struct vfp_double { |
|||
s16 exponent; |
|||
u16 sign; |
|||
u64 significand; |
|||
}; |
|||
|
|||
// VFP_REG_ZERO is a special register number for vfp_get_double |
|||
// which returns (double)0.0. This is useful for the compare with |
|||
// zero instructions. |
|||
#ifdef CONFIG_VFPv3 |
|||
#define VFP_REG_ZERO 32 |
|||
#else |
|||
#define VFP_REG_ZERO 16 |
|||
#endif |
|||
|
|||
#define VFP_DOUBLE_MANTISSA_BITS (52) |
|||
#define VFP_DOUBLE_EXPONENT_BITS (11) |
|||
#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) |
|||
#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) |
|||
|
|||
// The bit in an unpacked double which indicates that it is a quiet NaN |
|||
#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) |
|||
|
|||
// Operations on packed single-precision numbers |
|||
#define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) |
|||
#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) |
|||
#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) |
|||
#define vfp_double_packed_exponent(v) \ |
|||
(((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) |
|||
#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) |
|||
|
|||
inline int vfp_double_type(const vfp_double* s) { |
|||
int type = VFP_NUMBER; |
|||
if (s->exponent == 2047) { |
|||
if (s->significand == 0) |
|||
type = VFP_INFINITY; |
|||
else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) |
|||
type = VFP_QNAN; |
|||
else |
|||
type = VFP_SNAN; |
|||
} else if (s->exponent == 0) { |
|||
if (s->significand == 0) |
|||
type |= VFP_ZERO; |
|||
else |
|||
type |= VFP_DENORMAL; |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
// Unpack a double-precision float. Note that this returns the magnitude |
|||
// of the double-precision float mantissa with the 1. if necessary, |
|||
// aligned to bit 62. |
|||
inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) { |
|||
u32 exceptions = 0; |
|||
s->sign = vfp_double_packed_sign(val) >> 48; |
|||
s->exponent = vfp_double_packed_exponent(val); |
|||
|
|||
u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; |
|||
if (s->exponent && s->exponent != 2047) |
|||
significand |= (1ULL << 62); |
|||
s->significand = significand; |
|||
|
|||
// If flush-to-zero mode is enabled, turn the denormal into zero. |
|||
// On a VFPv2 architecture, the sign of the zero is always positive. |
|||
if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) { |
|||
s->sign = 0; |
|||
s->exponent = 0; |
|||
s->significand = 0; |
|||
exceptions |= FPSCR_IDC; |
|||
} |
|||
return exceptions; |
|||
} |
|||
|
|||
// Re-pack a double-precision float. This assumes that the float is |
|||
// already normalised such that the MSB is bit 30, _not_ bit 31. |
|||
inline s64 vfp_double_pack(const vfp_double* s) { |
|||
u64 val = ((u64)s->sign << 48) + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + |
|||
(s->significand >> VFP_DOUBLE_LOW_BITS); |
|||
return (s64)val; |
|||
} |
|||
|
|||
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); |
|||
|
|||
// A special flag to tell the normalisation code not to normalise. |
|||
#define VFP_NAN_FLAG 0x100 |
|||
|
|||
// A bit pattern used to indicate the initial (unset) value of the |
|||
// exception mask, in case nothing handles an instruction. This |
|||
// doesn't include the NAN flag, which get masked out before |
|||
// we check for an error. |
|||
#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) |
|||
|
|||
// A flag to tell vfp instruction type. |
|||
// OP_SCALAR - This operation always operates in scalar mode |
|||
// OP_SD - The instruction exceptionally writes to a single precision result. |
|||
// OP_DD - The instruction exceptionally writes to a double precision result. |
|||
// OP_SM - The instruction exceptionally reads from a single precision operand. |
|||
enum : u32 { OP_SCALAR = (1 << 0), OP_SD = (1 << 1), OP_DD = (1 << 1), OP_SM = (1 << 2) }; |
|||
|
|||
struct op { |
|||
u32 (*const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr); |
|||
u32 flags; |
|||
}; |
|||
|
|||
inline u32 fls(u32 x) { |
|||
int r = 32; |
|||
|
|||
if (!x) |
|||
return 0; |
|||
if (!(x & 0xffff0000u)) { |
|||
x <<= 16; |
|||
r -= 16; |
|||
} |
|||
if (!(x & 0xff000000u)) { |
|||
x <<= 8; |
|||
r -= 8; |
|||
} |
|||
if (!(x & 0xf0000000u)) { |
|||
x <<= 4; |
|||
r -= 4; |
|||
} |
|||
if (!(x & 0xc0000000u)) { |
|||
x <<= 2; |
|||
r -= 2; |
|||
} |
|||
if (!(x & 0x80000000u)) { |
|||
x <<= 1; |
|||
r -= 1; |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); |
|||
u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); |
|||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions, |
|||
const char* func); |
|||
1247
src/core/arm/skyeye_common/vfp/vfpdouble.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1703
src/core/arm/skyeye_common/vfp/vfpinstr.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1272
src/core/arm/skyeye_common/vfp/vfpsingle.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,50 +0,0 @@ |
|||
// Copyright 2016 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <catch.hpp>
|
|||
|
|||
#include "core/arm/dyncom/arm_dyncom.h"
|
|||
#include "core/core_timing.h"
|
|||
#include "tests/core/arm/arm_test_common.h"
|
|||
|
|||
namespace ArmTests { |
|||
|
|||
struct VfpTestCase { |
|||
u32 initial_fpscr; |
|||
u32 a; |
|||
u32 b; |
|||
u32 result; |
|||
u32 final_fpscr; |
|||
}; |
|||
|
|||
TEST_CASE("ARM_DynCom (vfp): vadd", "[arm_dyncom]") { |
|||
TestEnvironment test_env(false); |
|||
test_env.SetMemory32(0, 0xEE321A03); // vadd.f32 s2, s4, s6
|
|||
test_env.SetMemory32(4, 0xEAFFFFFE); // b +#0
|
|||
|
|||
ARM_DynCom dyncom(USER32MODE); |
|||
|
|||
std::vector<VfpTestCase> test_cases{{ |
|||
#include "vfp_vadd_f32.inc"
|
|||
}}; |
|||
|
|||
for (const auto& test_case : test_cases) { |
|||
dyncom.SetPC(0); |
|||
dyncom.SetVFPSystemReg(VFP_FPSCR, test_case.initial_fpscr); |
|||
dyncom.SetVFPReg(4, test_case.a); |
|||
dyncom.SetVFPReg(6, test_case.b); |
|||
dyncom.ExecuteInstructions(1); |
|||
if (dyncom.GetVFPReg(2) != test_case.result || |
|||
dyncom.GetVFPSystemReg(VFP_FPSCR) != test_case.final_fpscr) { |
|||
printf("f: %x\n", test_case.initial_fpscr); |
|||
printf("a: %x\n", test_case.a); |
|||
printf("b: %x\n", test_case.b); |
|||
printf("c: %x (%x)\n", dyncom.GetVFPReg(2), test_case.result); |
|||
printf("f: %x (%x)\n", dyncom.GetVFPSystemReg(VFP_FPSCR), test_case.final_fpscr); |
|||
FAIL(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} // namespace ArmTests
|
|||
13456
src/tests/core/arm/dyncom/vfp_vadd_f32.inc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue