diff options
-rw-r--r-- | src/citra_qt/debugger/callstack.cpp | 3 | ||||
-rw-r--r-- | src/citra_qt/debugger/disassembler.cpp | 5 | ||||
-rw-r--r-- | src/common/break_points.cpp | 4 | ||||
-rw-r--r-- | src/common/break_points.h | 4 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_dec.cpp | 4 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_dec.h | 37 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 205 | ||||
-rw-r--r-- | src/core/arm/interpreter/armsupp.cpp | 431 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/arm_regformat.h | 90 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 4 | ||||
-rw-r--r-- | src/core/hle/config_mem.cpp | 4 |
11 files changed, 597 insertions, 194 deletions
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 9bb22ca2e..3742c2d38 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -27,7 +27,6 @@ CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) void CallstackWidget::OnDebugModeEntered() { - ARM_Disasm* disasm = new ARM_Disasm(); ARM_Interface* app_core = Core::g_app_core; u32 sp = app_core->GetReg(13); //stack pointer @@ -46,7 +45,7 @@ void CallstackWidget::OnDebugModeEntered() /* TODO (mattvail) clean me, move to debugger interface */ u32 insn = Memory::Read32(call_addr); - if (disasm->Decode(insn) == OP_BL) + if (ARM_Disasm::Decode(insn) == OP_BL) { std::string name; // ripped from disasm diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 54d21dc90..f620687ae 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -232,11 +232,8 @@ void DisassemblerWidget::OnDebugModeEntered() { ARMword next_instr = Core::g_app_core->GetPC(); - // TODO: Make BreakPoints less crappy (i.e. const-correct) so that this doesn't need a const_cast. - if (const_cast<BreakPoints&>(model->GetBreakPoints()).IsAddressBreakPoint(next_instr)) - { + if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) emu_thread.SetCpuRunning(false); - } model->SetNextInstruction(next_instr); diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp index 2655d3ce9..15055bd4e 100644 --- a/src/common/break_points.cpp +++ b/src/common/break_points.cpp @@ -10,14 +10,14 @@ #include <sstream> #include <algorithm> -bool BreakPoints::IsAddressBreakPoint(u32 iAddress) +bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const { auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); return it != m_BreakPoints.end(); } -bool BreakPoints::IsTempBreakPoint(u32 iAddress) +bool BreakPoints::IsTempBreakPoint(u32 iAddress) const { auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; }; auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); diff --git a/src/common/break_points.h b/src/common/break_points.h index 5557cd50e..4b26cf90d 100644 --- a/src/common/break_points.h +++ b/src/common/break_points.h @@ -56,8 +56,8 @@ public: void AddFromStrings(const TBreakPointsStr& bps); // is address breakpoint - bool IsAddressBreakPoint(u32 iAddress); - bool IsTempBreakPoint(u32 iAddress); + bool IsAddressBreakPoint(u32 iAddress) const; + bool IsTempBreakPoint(u32 iAddress) const; // Add BreakPoint void Add(u32 em_address, bool temp=false); diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 9f3b90fd0..12181d0ec 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp @@ -413,7 +413,7 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) { if (instr != arm_instruction[i].content[base + 2]) { break; } - } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) { + } else if (BITS(instr, arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) { break; } base += 3; @@ -429,7 +429,7 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) { if (n != 0) { base = 0; while (n) { - if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) { + 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; diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h index ee8ff5992..4b5f5ad7e 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ b/src/core/arm/dyncom/arm_dyncom_dec.h @@ -4,43 +4,6 @@ #pragma once -#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1)) -#define BIT(n) ((instr >> (n)) & 1) - -// For MUL instructions -#define RDHi ((instr >> 16) & 0xF) -#define RDLo ((instr >> 12) & 0xF) -#define MUL_RD ((instr >> 16) & 0xF) -#define MUL_RN ((instr >> 12) & 0xF) -#define RS ((instr >> 8) & 0xF) -#define RD ((instr >> 12) & 0xF) -#define RN ((instr >> 16) & 0xF) -#define RM (instr & 0xF) - -// CP15 registers -#define OPCODE_1 BITS(21, 23) -#define CRn BITS(16, 19) -#define CRm BITS(0, 3) -#define OPCODE_2 BITS(5, 7) - -#define I BIT(25) -#define S BIT(20) - -#define SHIFT BITS(5,6) -#define SHIFT_IMM BITS(7,11) -#define IMMH BITS(8,11) -#define IMML BITS(0,3) - -#define LSPBIT BIT(24) -#define LSUBIT BIT(23) -#define LSBBIT BIT(22) -#define LSWBIT BIT(21) -#define LSLBIT BIT(20) -#define LSSHBITS BITS(5,6) -#define OFFSET12 BITS(0,11) -#define SBIT BIT(20) -#define DESTReg (BITS (12, 15)) - int decode_arm_instr(uint32_t instr, int32_t *idx); enum DECODE_STATUS { diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index cfa6de8fc..b0efd7194 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -2156,7 +2156,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index) return INTERPRETER_TRANSLATE(rev)(inst, index); } -static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("RFE"); } +static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} + static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) { arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); @@ -2570,7 +2585,23 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) inst_base->load_r15 = 1; return inst_base; } -static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SRS"); } + +static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} + static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) { arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); @@ -3659,10 +3690,6 @@ static int clz(unsigned int x) { return n; } -static bool InAPrivilegedMode(ARMul_State* core) { - return (core->Mode != USER32MODE); -} - unsigned InterpreterMainLoop(ARMul_State* state) { Common::Profiling::ScopeTimer timer_execute(profile_execute); @@ -3670,6 +3697,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { #undef RS #define CRn inst_cream->crn + #define OPCODE_1 inst_cream->opcode_1 #define OPCODE_2 inst_cream->opcode_2 #define CRm inst_cream->crm #define CP15_REG(n) cpu->CP15[CP15(n)] @@ -4733,94 +4761,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (inst_cream->Rd == 15) { DEBUG_MSG; } else { - if (inst_cream->cp_num == 15) { - if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { - CP15_REG(CP15_CONTROL) = RD; - } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { - CP15_REG(CP15_AUXILIARY_CONTROL) = RD; - } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { - CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { - CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { - CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { - CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD; - } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { - CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; - } else if(CRn == MMU_CACHE_OPS){ - //LOG_WARNING(Core_ARM11, "cache operations have not implemented."); - } else if(CRn == MMU_TLB_OPS){ - switch (CRm) { - case 5: // ITLB - switch(OPCODE_2) { - case 0: // Invalidate all - LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate all"); - break; - case 1: // Invalidate by MVA - LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by mva"); - break; - case 2: // Invalidate by asid - LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by asid"); - break; - default: - break; - } - - break; - case 6: // DTLB - switch(OPCODE_2){ - case 0: // Invalidate all - LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate all"); - break; - case 1: // Invalidate by MVA - LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by mva"); - break; - case 2: // Invalidate by asid - LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by asid"); - break; - default: - break; - } - break; - case 7: // UNIFILED TLB - switch(OPCODE_2){ - case 0: // invalidate all - LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate all"); - break; - case 1: // Invalidate by MVA - LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by mva"); - break; - case 2: // Invalidate by asid - LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by asid"); - break; - default: - break; - } - break; - default: - break; - } - } else if(CRn == MMU_PID) { - if(OPCODE_2 == 0) { - CP15_REG(CP15_PID) = RD; - } else if(OPCODE_2 == 1) { - CP15_REG(CP15_CONTEXT_ID) = RD; - } else if (OPCODE_2 == 2) { - CP15_REG(CP15_THREAD_UPRW) = RD; - } else if(OPCODE_2 == 3) { - if (InAPrivilegedMode(cpu)) - CP15_REG(CP15_THREAD_URO) = RD; - } else if (OPCODE_2 == 4) { - if (InAPrivilegedMode(cpu)) - CP15_REG(CP15_THREAD_PRW) = RD; - } else { - LOG_ERROR(Core_ARM11, "mmu_mcr wrote UNKNOWN - reg %d", CRn); - } - } else { - LOG_ERROR(Core_ARM11, "mcr CRn=%d, CRm=%d OP2=%d is not implemented", CRn, CRm, OPCODE_2); - } - } + if (inst_cream->cp_num == 15) + WriteCP15Register(cpu, RD, CRn, OPCODE_1, CRm, OPCODE_2); } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -4895,50 +4837,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { CITRA_IGNORE_EXIT(-1); goto END; } else { - if (inst_cream->cp_num == 15) { - if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { - RD = cpu->CP15[CP15(CP15_MAIN_ID)]; - } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { - RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; - } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_CONTROL)]; - } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { - RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; - } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { - RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { - RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)]; - } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { - RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)]; - } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; - } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_FAULT_STATUS)]; - } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) { - RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; - } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; - } else if (CRn == 13) { - if(OPCODE_2 == 0) { - RD = CP15_REG(CP15_PID); - } else if(OPCODE_2 == 1) { - RD = CP15_REG(CP15_CONTEXT_ID); - } else if (OPCODE_2 == 2) { - RD = CP15_REG(CP15_THREAD_UPRW); - } else if(OPCODE_2 == 3) { - RD = Memory::KERNEL_MEMORY_VADDR; - } else if (OPCODE_2 == 4) { - if (InAPrivilegedMode(cpu)) - RD = CP15_REG(CP15_THREAD_PRW); - } else { - LOG_ERROR(Core_ARM11, "mmu_mrr wrote UNKNOWN - reg %d", CRn); - } - } else { - LOG_ERROR(Core_ARM11, "mrc CRn=%d, CRm=%d, OP2=%d is not implemented", CRn, CRm, OPCODE_2); - } - } + if (inst_cream->cp_num == 15) + RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2); } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -5293,6 +5193,20 @@ unsigned InterpreterMainLoop(ARMul_State* state) { } RFE_INST: + { + // RFE is unconditional + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + u32 address = 0; + inst_cream->get_addr(cpu, inst_cream->inst, address, 1); + + cpu->Cpsr = ReadMemory32(cpu, address); + cpu->Reg[15] = ReadMemory32(cpu, address + 4); + + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + RSB_INST: { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { @@ -5934,6 +5848,21 @@ unsigned InterpreterMainLoop(ARMul_State* state) { } SRS_INST: + { + // SRS is unconditional + ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; + + u32 address = 0; + inst_cream->get_addr(cpu, inst_cream->inst, address, 1); + + WriteMemory32(cpu, address + 0, cpu->Reg[14]); + WriteMemory32(cpu, address + 4, cpu->Spsr_copy); + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } SSAT_INST: { diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index aca2bfbbd..6a11a5804 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -15,7 +15,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "core/mem_map.h" #include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/arm_regformat.h" // Unsigned sum of absolute difference u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) @@ -207,3 +209,432 @@ bool InBigEndianMode(ARMul_State* cpu) { return (cpu->Cpsr & (1 << 9)) != 0; } + +// Whether or not the given CPU is in a mode other than user mode. +bool InAPrivilegedMode(ARMul_State* cpu) +{ + return (cpu->Mode != USER32MODE); +} + +// 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 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) +{ + // Unprivileged registers + if (crn == 13 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_THREAD_UPRW)]; + + // TODO: Whenever TLS is implemented, this should return + // "cpu->CP15[CP15(CP15_THREAD_URO)];" + // which contains the address of the 0x200-byte TLS + if (opcode_2 == 3) + return Memory::KERNEL_MEMORY_VADDR; + } + + if (InAPrivilegedMode(cpu)) + { + if (crn == 0 && opcode_1 == 0) + { + if (crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_MAIN_ID)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_CACHE_TYPE)]; + + if (opcode_2 == 3) + return cpu->CP15[CP15(CP15_TLB_TYPE)]; + + if (opcode_2 == 5) + return cpu->CP15[CP15(CP15_CPU_ID)]; + } + else if (crm == 1) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_PROCESSOR_FEATURE_0)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_PROCESSOR_FEATURE_1)]; + + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_DEBUG_FEATURE_0)]; + + if (opcode_2 == 4) + return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_0)]; + + if (opcode_2 == 5) + return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_1)]; + + if (opcode_2 == 6) + return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_2)]; + + if (opcode_2 == 7) + return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_3)]; + } + else if (crm == 2) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_ISA_FEATURE_0)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_ISA_FEATURE_1)]; + + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_ISA_FEATURE_2)]; + + if (opcode_2 == 3) + return cpu->CP15[CP15(CP15_ISA_FEATURE_3)]; + + if (opcode_2 == 4) + return cpu->CP15[CP15(CP15_ISA_FEATURE_4)]; + } + } + + if (crn == 1 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_CONTROL)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; + + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; + } + + if (crn == 2 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)]; + + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)]; + } + + if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) + return cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; + + if (crn == 5 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_FAULT_STATUS)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; + } + + if (crn == 6 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_WFAR)]; + } + + if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) + return cpu->CP15[CP15(CP15_PHYS_ADDRESS)]; + + if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) + return cpu->CP15[CP15(CP15_DATA_CACHE_LOCKDOWN)]; + + if (crn == 10 && opcode_1 == 0) + { + if (crm == 0 && opcode_2 == 0) + return cpu->CP15[CP15(CP15_TLB_LOCKDOWN)]; + + if (crm == 2) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_PRIMARY_REGION_REMAP)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_NORMAL_REGION_REMAP)]; + } + } + + if (crn == 13 && crm == 0) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_PID)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_CONTEXT_ID)]; + + if (opcode_2 == 4) + return cpu->CP15[CP15(CP15_THREAD_PRW)]; + } + + if (crn == 15) + { + if (opcode_1 == 0 && crm == 12) + { + if (opcode_2 == 0) + return cpu->CP15[CP15(CP15_PERFORMANCE_MONITOR_CONTROL)]; + + if (opcode_2 == 1) + return cpu->CP15[CP15(CP15_CYCLE_COUNTER)]; + + if (opcode_2 == 2) + return cpu->CP15[CP15(CP15_COUNT_0)]; + + if (opcode_2 == 3) + return cpu->CP15[CP15(CP15_COUNT_1)]; + } + + if (opcode_1 == 5 && opcode_2 == 2) + { + if (crm == 5) + return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS)]; + + if (crm == 6) + return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS)]; + + if (crm == 7) + return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE)]; + } + + if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) + return cpu->CP15[CP15(CP15_TLB_DEBUG_CONTROL)]; + } + } + + LOG_ERROR(Core_ARM11, "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 WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) +{ + if (InAPrivilegedMode(cpu)) + { + if (crn == 1 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_CONTROL)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)] = value; + } + else if (crn == 2 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)] = value; + } + else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) + { + cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)] = value; + } + else if (crn == 5 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_FAULT_STATUS)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = value; + } + else if (crn == 6 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_WFAR)] = value; + } + else if (crn == 7 && opcode_1 == 0) + { + LOG_WARNING(Core_ARM11, "Cache operations are not fully implemented."); + + if (crm == 0 && opcode_2 == 4) + { + cpu->CP15[CP15(CP15_WAIT_FOR_INTERRUPT)] = value; + } + else if (crm == 4 && opcode_2 == 0) + { + // NOTE: Not entirely accurate. This should do permission checks. + cpu->CP15[CP15(CP15_PHYS_ADDRESS)] = Memory::VirtualToPhysicalAddress(value); + } + else if (crm == 5) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_INVALIDATE_INSTR_CACHE)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INVALIDATE_INSTR_CACHE_USING_MVA)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_INVALIDATE_INSTR_CACHE_USING_INDEX)] = value; + else if (opcode_2 == 6) + cpu->CP15[CP15(CP15_FLUSH_BRANCH_TARGET_CACHE)] = value; + else if (opcode_2 == 7) + cpu->CP15[CP15(CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY)] = value; + } + else if (crm == 6) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_INVALIDATE_DATA_CACHE)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX)] = value; + } + else if (crm == 7 && opcode_2 == 0) + { + cpu->CP15[CP15(CP15_INVALIDATE_DATA_AND_INSTR_CACHE)] = value; + } + else if (crm == 10) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_CLEAN_DATA_CACHE)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_CLEAN_DATA_CACHE_LINE_USING_MVA)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX)] = value; + } + else if (crm == 14) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_CLEAN_AND_INVALIDATE_DATA_CACHE)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX)] = value; + } + } + else if (crn == 8 && opcode_1 == 0) + { + LOG_WARNING(Core_ARM11, "TLB operations not fully implemented."); + + if (crm == 5) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_INVALIDATE_ITLB)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INVALIDATE_ITLB_SINGLE_ENTRY)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH)] = value; + else if (opcode_2 == 3) + cpu->CP15[CP15(CP15_INVALIDATE_ITLB_ENTRY_ON_MVA)] = value; + } + else if (crm == 6) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_INVALIDATE_DTLB)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INVALIDATE_DTLB_SINGLE_ENTRY)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH)] = value; + else if (opcode_2 == 3) + cpu->CP15[CP15(CP15_INVALIDATE_DTLB_ENTRY_ON_MVA)] = value; + } + else if (crm == 7) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_INVALIDATE_UTLB)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_INVALIDATE_UTLB_SINGLE_ENTRY)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH)] = value; + else if (opcode_2 == 3) + cpu->CP15[CP15(CP15_INVALIDATE_UTLB_ENTRY_ON_MVA)] = value; + } + } + else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) + { + cpu->CP15[CP15(CP15_DATA_CACHE_LOCKDOWN)] = value; + } + else if (crn == 10 && opcode_1 == 0) + { + if (crm == 0 && opcode_2 == 0) + { + cpu->CP15[CP15(CP15_TLB_LOCKDOWN)] = value; + } + else if (crm == 2) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_PRIMARY_REGION_REMAP)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_NORMAL_REGION_REMAP)] = value; + } + } + else if (crn == 13 && opcode_1 == 0 && crm == 0) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_PID)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_CONTEXT_ID)] = value; + else if (opcode_2 == 3) + cpu->CP15[CP15(CP15_THREAD_URO)] = value; + else if (opcode_2 == 4) + cpu->CP15[CP15(CP15_THREAD_PRW)] = value; + } + else if (crn == 15) + { + if (opcode_1 == 0 && crm == 12) + { + if (opcode_2 == 0) + cpu->CP15[CP15(CP15_PERFORMANCE_MONITOR_CONTROL)] = value; + else if (opcode_2 == 1) + cpu->CP15[CP15(CP15_CYCLE_COUNTER)] = value; + else if (opcode_2 == 2) + cpu->CP15[CP15(CP15_COUNT_0)] = value; + else if (opcode_2 == 3) + cpu->CP15[CP15(CP15_COUNT_1)] = value; + } + else if (opcode_1 == 5) + { + if (crm == 4) + { + if (opcode_2 == 2) + cpu->CP15[CP15(CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY)] = value; + else if (opcode_2 == 4) + cpu->CP15[CP15(CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY)] = value; + } + else if (crm == 5 && opcode_2 == 2) + { + cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS)] = value; + } + else if (crm == 6 && opcode_2 == 2) + { + cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS)] = value; + } + else if (crm == 7 && opcode_2 == 2) + { + cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE)] = value; + } + } + else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) + { + cpu->CP15[CP15(CP15_TLB_DEBUG_CONTROL)] = value; + } + } + } + + // Unprivileged registers + if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) + { + cpu->CP15[CP15(CP15_FLUSH_PREFETCH_BUFFER)] = value; + } + else if (crn == 7 && opcode_1 == 0 && crm == 10) + { + if (opcode_2 == 4) + cpu->CP15[CP15(CP15_DATA_SYNC_BARRIER)] = value; + else if (opcode_2 == 5) + cpu->CP15[CP15(CP15_DATA_MEMORY_BARRIER)] = value; + + } + else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) + { + cpu->CP15[CP15(CP15_THREAD_UPRW)] = value; + } +} diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 5be3a561f..c232376e0 100644 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h @@ -50,6 +50,8 @@ enum { EXCLUSIVE_TAG, EXCLUSIVE_STATE, EXCLUSIVE_RESULT, + + // c0 - Information registers CP15_BASE, CP15_C0 = CP15_BASE, CP15_C0_C0 = CP15_C0, @@ -57,15 +59,30 @@ enum { CP15_CACHE_TYPE, CP15_TCM_STATUS, CP15_TLB_TYPE, + CP15_CPU_ID, CP15_C0_C1, CP15_PROCESSOR_FEATURE_0 = CP15_C0_C1, 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_C0_C2, + CP15_ISA_FEATURE_0 = CP15_C0_C2, + CP15_ISA_FEATURE_1, + CP15_ISA_FEATURE_2, + CP15_ISA_FEATURE_3, + CP15_ISA_FEATURE_4, + + // c1 - Control registers CP15_C1_C0, CP15_CONTROL = CP15_C1_C0, CP15_AUXILIARY_CONTROL, CP15_COPROCESSOR_ACCESS_CONTROL, + + // c2 - Translation table registers CP15_C2, CP15_C2_C0 = CP15_C2, CP15_TRANSLATION_BASE = CP15_C2_C0, @@ -74,24 +91,87 @@ enum { CP15_TRANSLATION_BASE_CONTROL, CP15_DOMAIN_ACCESS_CONTROL, CP15_RESERVED, - /* Fault status */ + + // c5 - Fault status registers CP15_FAULT_STATUS, CP15_INSTR_FAULT_STATUS, CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, CP15_INST_FSR, - /* Fault Address register */ + + // 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. - CP15_TLB_FAULT_ADDR, /* defined by SkyEye */ - CP15_TLB_FAULT_STATUS, /* defined by SkyEye */ - /* VFP registers */ + + // 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, + + // VFP registers VFP_BASE, VFP_FPSID = VFP_BASE, VFP_FPSCR, diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index c1a19fecc..d5b0242c3 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -357,3 +357,7 @@ extern u32 ARMul_SignedSatQ(s32, u8, bool*); extern u32 ARMul_UnsignedSatQ(s32, u8, bool*); extern bool InBigEndianMode(ARMul_State*); +extern bool InAPrivilegedMode(ARMul_State*); + +extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); +extern void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index b10c19d1d..40bae9346 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -65,9 +65,9 @@ void Init() { config_mem.sys_core_ver = 0x2; config_mem.unit_info = 0x1; // Bit 0 set for Retail config_mem.prev_firm = 0; - config_mem.app_mem_type = 0; // Defualt app mem type + config_mem.app_mem_type = 0x2; // Default app mem type is 0 config_mem.unit_info = 0x1; // Bit 0 set for Retail - config_mem.app_mem_alloc = 0x04000000; // Default app memory size is 64MB + config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB) config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc); config_mem.firm_unk = 0; |