diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/arm/arm_interface.h | 6 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 5 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom.h | 1 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 150 | ||||
-rw-r--r-- | src/core/arm/interpreter/armsupp.cpp | 6 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 3 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armmmu.h | 105 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/vfp/vfpinstr.cpp | 102 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.cpp | 38 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.h | 30 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid_spvr.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid_user.cpp | 16 | ||||
-rw-r--r-- | src/core/hle/svc.cpp | 5 | ||||
-rw-r--r-- | src/core/hw/gpu.cpp | 31 | ||||
-rw-r--r-- | src/core/hw/gpu.h | 11 | ||||
-rw-r--r-- | src/core/loader/ncch.h | 25 | ||||
-rw-r--r-- | src/core/mem_map.h | 1 | ||||
-rw-r--r-- | src/core/mem_map_funcs.cpp | 6 |
18 files changed, 383 insertions, 164 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index ef37ee055..fe1e584ad 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -74,12 +74,6 @@ public: virtual void SetCPSR(u32 cpsr) = 0; /** - * Returns the number of clock ticks since the last rese - * @return Returns number of clock ticks - */ - virtual u64 GetTicks() const = 0; - - /** * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) * @param ticks Number of ticks to advance the CPU core */ diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index bbcbbdd2b..cb1a410a0 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -68,11 +68,6 @@ void ARM_DynCom::SetCPSR(u32 cpsr) { state->Cpsr = cpsr; } -u64 ARM_DynCom::GetTicks() const { - // TODO(Subv): Remove ARM_DynCom::GetTicks() and use CoreTiming::GetTicks() directly once ARMemu is gone - return CoreTiming::GetTicks(); -} - void ARM_DynCom::AddTicks(u64 ticks) { down_count -= ticks; if (down_count < 0) diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 213cac1ad..a7f95d307 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -23,7 +23,6 @@ public: u32 GetCPSR() const override; void SetCPSR(u32 cpsr) override; - u64 GetTicks() const override; void AddTicks(u64 ticks) override; void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg); diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index d953adba9..cfa6de8fc 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -1075,6 +1075,10 @@ typedef struct _swp_inst { unsigned int Rm; } swp_inst; +typedef struct setend_inst { + unsigned int set_bigend; +} setend_inst; + typedef struct _b_2_thumb { unsigned int imm; }b_2_thumb; @@ -2283,7 +2287,20 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index) return inst_base; } -static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SETEND"); } +static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst)); + setend_inst* const inst_cream = (setend_inst*)inst_base->component; + + inst_base->cond = AL; + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->set_bigend = BIT(inst, 9); + + return inst_base; +} static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) { @@ -4345,30 +4362,30 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (BIT(inst, 22) && !BIT(inst, 15)) { for (int i = 0; i < 13; i++) { if(BIT(inst, i)) { - cpu->Reg[i] = Memory::Read32(addr); + cpu->Reg[i] = ReadMemory32(cpu, addr); addr += 4; } } if (BIT(inst, 13)) { if (cpu->Mode == USER32MODE) - cpu->Reg[13] = Memory::Read32(addr); + cpu->Reg[13] = ReadMemory32(cpu, addr); else - cpu->Reg_usr[0] = Memory::Read32(addr); + cpu->Reg_usr[0] = ReadMemory32(cpu, addr); addr += 4; } if (BIT(inst, 14)) { if (cpu->Mode == USER32MODE) - cpu->Reg[14] = Memory::Read32(addr); + cpu->Reg[14] = ReadMemory32(cpu, addr); else - cpu->Reg_usr[1] = Memory::Read32(addr); + cpu->Reg_usr[1] = ReadMemory32(cpu, addr); addr += 4; } } else if (!BIT(inst, 22)) { for(int i = 0; i < 16; i++ ){ if(BIT(inst, i)){ - unsigned int ret = Memory::Read32(addr); + unsigned int ret = ReadMemory32(cpu, addr); // For armv5t, should enter thumb when bits[0] is non-zero. if(i == 15){ @@ -4383,7 +4400,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { } else if (BIT(inst, 22) && BIT(inst, 15)) { for(int i = 0; i < 15; i++ ){ if(BIT(inst, i)){ - cpu->Reg[i] = Memory::Read32(addr); + cpu->Reg[i] = ReadMemory32(cpu, addr); addr += 4; } } @@ -4394,7 +4411,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { LOAD_NZCVT; } - cpu->Reg[15] = Memory::Read32(addr); + cpu->Reg[15] = ReadMemory32(cpu, addr); } if (BIT(inst, 15)) { @@ -4428,20 +4445,18 @@ unsigned InterpreterMainLoop(ARMul_State* state) { LDR_INST: { ldst_inst *inst_cream = (ldst_inst *)inst_base->component; - //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { - inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); + inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - unsigned int value = Memory::Read32(addr); - cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + unsigned int value = ReadMemory32(cpu, addr); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; - if (BITS(inst_cream->inst, 12, 15) == 15) { - // For armv5t, should enter thumb when bits[0] is non-zero. - cpu->TFlag = value & 0x1; - cpu->Reg[15] &= 0xFFFFFFFE; - INC_PC(sizeof(ldst_inst)); - goto DISPATCH; - } - //} + if (BITS(inst_cream->inst, 12, 15) == 15) { + // For armv5t, should enter thumb when bits[0] is non-zero. + cpu->TFlag = value & 0x1; + cpu->Reg[15] &= 0xFFFFFFFE; + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(ldst_inst)); @@ -4454,7 +4469,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { ldst_inst *inst_cream = (ldst_inst *)inst_base->component; inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - unsigned int value = Memory::Read32(addr); + unsigned int value = ReadMemory32(cpu, addr); cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { @@ -4537,8 +4552,10 @@ unsigned InterpreterMainLoop(ARMul_State* state) { // Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - cpu->Reg[BITS(inst_cream->inst, 12, 15)] = Memory::Read32(addr); - cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = Memory::Read32(addr + 4); + // The 3DS doesn't have LPAE (Large Physical Access Extension), so it + // wouldn't do this as a single read. + cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = ReadMemory32(cpu, addr); + cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = ReadMemory32(cpu, addr + 4); // No dispatch since this operation should not modify R15 } @@ -4557,7 +4574,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { add_exclusive_addr(cpu, read_addr); cpu->exclusive_state = 1; - RD = Memory::Read32(read_addr); + RD = ReadMemory32(cpu, read_addr); if (inst_cream->Rd == 15) { INC_PC(sizeof(generic_arm_inst)); goto DISPATCH; @@ -4597,7 +4614,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { add_exclusive_addr(cpu, read_addr); cpu->exclusive_state = 1; - RD = Memory::Read16(read_addr); + RD = ReadMemory16(cpu, read_addr); if (inst_cream->Rd == 15) { INC_PC(sizeof(generic_arm_inst)); goto DISPATCH; @@ -4617,8 +4634,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { add_exclusive_addr(cpu, read_addr); cpu->exclusive_state = 1; - RD = Memory::Read32(read_addr); - RD2 = Memory::Read32(read_addr + 4); + RD = ReadMemory32(cpu, read_addr); + RD2 = ReadMemory32(cpu, read_addr + 4); if (inst_cream->Rd == 15) { INC_PC(sizeof(generic_arm_inst)); @@ -4635,7 +4652,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { ldst_inst* inst_cream = (ldst_inst*)inst_base->component; inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - cpu->Reg[BITS(inst_cream->inst, 12, 15)] = Memory::Read16(addr); + + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ReadMemory16(cpu, addr); if (BITS(inst_cream->inst, 12, 15) == 15) { INC_PC(sizeof(ldst_inst)); goto DISPATCH; @@ -4671,7 +4689,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { ldst_inst* inst_cream = (ldst_inst*)inst_base->component; inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - unsigned int value = Memory::Read16(addr); + + unsigned int value = ReadMemory16(cpu, addr); if (BIT(value, 15)) { value |= 0xffff0000; } @@ -4692,7 +4711,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { ldst_inst* inst_cream = (ldst_inst*)inst_base->component; inst_cream->get_addr(cpu, inst_cream->inst, addr, 1); - unsigned int value = Memory::Read32(addr); + unsigned int value = ReadMemory32(cpu, addr); cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; if (BITS(inst_cream->inst, 12, 15) == 15) { @@ -5521,6 +5540,23 @@ unsigned InterpreterMainLoop(ARMul_State* state) { } SETEND_INST: + { + // SETEND is unconditional + setend_inst* const inst_cream = (setend_inst*)inst_base->component; + const bool big_endian = (inst_cream->set_bigend == 1); + + if (big_endian) + cpu->Cpsr |= (1 << 9); + else + cpu->Cpsr &= ~(1 << 9); + + LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE"); + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(setend_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } SHADD8_INST: SHADD16_INST: @@ -5976,36 +6012,36 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (BIT(inst_cream->inst, 22) == 1) { for (int i = 0; i < 13; i++) { if (BIT(inst_cream->inst, i)) { - Memory::Write32(addr, cpu->Reg[i]); + WriteMemory32(cpu, addr, cpu->Reg[i]); addr += 4; } } if (BIT(inst_cream->inst, 13)) { if (cpu->Mode == USER32MODE) - Memory::Write32(addr, cpu->Reg[13]); + WriteMemory32(cpu, addr, cpu->Reg[13]); else - Memory::Write32(addr, cpu->Reg_usr[0]); + WriteMemory32(cpu, addr, cpu->Reg_usr[0]); addr += 4; } if (BIT(inst_cream->inst, 14)) { if (cpu->Mode == USER32MODE) - Memory::Write32(addr, cpu->Reg[14]); + WriteMemory32(cpu, addr, cpu->Reg[14]); else - Memory::Write32(addr, cpu->Reg_usr[1]); + WriteMemory32(cpu, addr, cpu->Reg_usr[1]); addr += 4; } if (BIT(inst_cream->inst, 15)) { - Memory::Write32(addr, cpu->Reg_usr[1] + 8); + WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); } } else { for (int i = 0; i < 15; i++) { if (BIT(inst_cream->inst, i)) { if (i == Rn) - Memory::Write32(addr, old_RN); + WriteMemory32(cpu, addr, old_RN); else - Memory::Write32(addr, cpu->Reg[i]); + WriteMemory32(cpu, addr, cpu->Reg[i]); addr += 4; } @@ -6013,7 +6049,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { // Check PC reg if (BIT(inst_cream->inst, 15)) - Memory::Write32(addr, cpu->Reg_usr[1] + 8); + WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -6046,7 +6082,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { inst_cream->get_addr(cpu, inst_cream->inst, addr, 0); unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; - Memory::Write32(addr, value); + WriteMemory32(cpu, addr, value); } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(ldst_inst)); @@ -6109,10 +6145,10 @@ unsigned InterpreterMainLoop(ARMul_State* state) { ldst_inst* inst_cream = (ldst_inst*)inst_base->component; inst_cream->get_addr(cpu, inst_cream->inst, addr, 0); - unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; - Memory::Write32(addr, value); - value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]; - Memory::Write32(addr + 4, value); + // The 3DS doesn't have the Large Physical Access Extension (LPAE) + // so STRD wouldn't store these as a single write. + WriteMemory32(cpu, addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]); + WriteMemory32(cpu, addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]); } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(ldst_inst)); @@ -6129,7 +6165,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { remove_exclusive(cpu, write_addr); cpu->exclusive_state = 0; - Memory::Write32(write_addr, cpu->Reg[inst_cream->Rm]); + WriteMemory32(cpu, write_addr, RM); RD = 0; } else { // Failed to write due to mutex access @@ -6173,8 +6209,16 @@ unsigned InterpreterMainLoop(ARMul_State* state) { remove_exclusive(cpu, write_addr); cpu->exclusive_state = 0; - Memory::Write32(write_addr, cpu->Reg[inst_cream->Rm]); - Memory::Write32(write_addr + 4, cpu->Reg[inst_cream->Rm + 1]); + const u32 rt = cpu->Reg[inst_cream->Rm + 0]; + const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; + u64 value; + + if (InBigEndianMode(cpu)) + value = (((u64)rt << 32) | rt2); + else + value = (((u64)rt2 << 32) | rt); + + WriteMemory64(cpu, write_addr, value); RD = 0; } else { @@ -6197,7 +6241,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { remove_exclusive(cpu, write_addr); cpu->exclusive_state = 0; - Memory::Write16(write_addr, cpu->Reg[inst_cream->Rm]); + WriteMemory16(cpu, write_addr, RM); RD = 0; } else { // Failed to write due to mutex access @@ -6216,7 +6260,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { inst_cream->get_addr(cpu, inst_cream->inst, addr, 0); unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; - Memory::Write16(addr, value); + WriteMemory16(cpu, addr, value); } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(ldst_inst)); @@ -6230,7 +6274,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { inst_cream->get_addr(cpu, inst_cream->inst, addr, 0); unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; - Memory::Write32(addr, value); + WriteMemory32(cpu, addr, value); } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(ldst_inst)); @@ -6289,8 +6333,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) { swp_inst* inst_cream = (swp_inst*)inst_base->component; addr = RN; - unsigned int value = Memory::Read32(addr); - Memory::Write32(addr, RM); + unsigned int value = ReadMemory32(cpu, addr); + WriteMemory32(cpu, addr, RM); RD = value; } diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index ed4f6c2a2..aca2bfbbd 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -201,3 +201,9 @@ u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) *saturation_occurred = false; return (u32)value; } + +// Whether or not the given CPU is in big endian mode (E bit is set) +bool InBigEndianMode(ARMul_State* cpu) +{ + return (cpu->Cpsr & (1 << 9)) != 0; +} diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 16f3ac86c..c1a19fecc 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -18,7 +18,6 @@ #pragma once #include "common/common_types.h" -#include "core/arm/skyeye_common/armmmu.h" #include "core/arm/skyeye_common/arm_regformat.h" #include "core/arm/skyeye_common/skyeye_defs.h" @@ -356,3 +355,5 @@ extern u16 ARMul_UnsignedSaturatedSub16(u16, u16); extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8); extern u32 ARMul_SignedSatQ(s32, u8, bool*); extern u32 ARMul_UnsignedSatQ(s32, u8, bool*); + +extern bool InBigEndianMode(ARMul_State*); diff --git a/src/core/arm/skyeye_common/armmmu.h b/src/core/arm/skyeye_common/armmmu.h index 6e54142ee..22e564c3d 100644 --- a/src/core/arm/skyeye_common/armmmu.h +++ b/src/core/arm/skyeye_common/armmmu.h @@ -20,37 +20,82 @@ #pragma once +#include "core/mem_map.h" +#include "core/arm/skyeye_common/armdefs.h" + // Register numbers in the MMU enum { - MMU_ID = 0, - MMU_CONTROL = 1, - MMU_TRANSLATION_TABLE_BASE = 2, - MMU_DOMAIN_ACCESS_CONTROL = 3, - MMU_FAULT_STATUS = 5, - MMU_FAULT_ADDRESS = 6, - MMU_CACHE_OPS = 7, - MMU_TLB_OPS = 8, - MMU_CACHE_LOCKDOWN = 9, - MMU_TLB_LOCKDOWN = 10, - MMU_PID = 13, - - // MMU_V4 - MMU_V4_CACHE_OPS = 7, - MMU_V4_TLB_OPS = 8, - - // MMU_V3 - MMU_V3_FLUSH_TLB = 5, - MMU_V3_FLUSH_TLB_ENTRY = 6, - MMU_V3_FLUSH_CACHE = 7, - - // MMU Intel SA-1100 - MMU_SA_RB_OPS = 9, - MMU_SA_DEBUG = 14, - MMU_SA_CP15_R15 = 15, - - // Intel xscale CP15 - XSCALE_CP15_CACHE_TYPE = 0, - XSCALE_CP15_AUX_CONTROL = 1, - XSCALE_CP15_COPRO_ACCESS = 15, + MMU_ID = 0, + MMU_CONTROL = 1, + MMU_TRANSLATION_TABLE_BASE = 2, + MMU_DOMAIN_ACCESS_CONTROL = 3, + MMU_FAULT_STATUS = 5, + MMU_FAULT_ADDRESS = 6, + MMU_CACHE_OPS = 7, + MMU_TLB_OPS = 8, + MMU_CACHE_LOCKDOWN = 9, + MMU_TLB_LOCKDOWN = 10, + MMU_PID = 13, + + // MMU_V4 + MMU_V4_CACHE_OPS = 7, + MMU_V4_TLB_OPS = 8, + + // MMU_V3 + MMU_V3_FLUSH_TLB = 5, + MMU_V3_FLUSH_TLB_ENTRY = 6, + MMU_V3_FLUSH_CACHE = 7, }; + +// Reads data in big/little endian format based on the +// state of the E (endian) bit in the emulated CPU's APSR. +inline u16 ReadMemory16(ARMul_State* cpu, u32 address) { + u16 data = Memory::Read16(address); + + if (InBigEndianMode(cpu)) + data = Common::swap16(data); + + return data; +} + +inline u32 ReadMemory32(ARMul_State* cpu, u32 address) { + u32 data = Memory::Read32(address); + + if (InBigEndianMode(cpu)) + data = Common::swap32(data); + + return data; +} + +inline u64 ReadMemory64(ARMul_State* cpu, u32 address) { + u64 data = Memory::Read64(address); + + if (InBigEndianMode(cpu)) + data = Common::swap64(data); + + return data; +} + +// Writes data in big/little endian format based on the +// state of the E (endian) bit in the emulated CPU's APSR. +inline void WriteMemory16(ARMul_State* cpu, u32 address, u16 data) { + if (InBigEndianMode(cpu)) + data = Common::swap16(data); + + Memory::Write16(address, data); +} + +inline void WriteMemory32(ARMul_State* cpu, u32 address, u32 data) { + if (InBigEndianMode(cpu)) + data = Common::swap32(data); + + Memory::Write32(address, data); +} + +inline void WriteMemory64(ARMul_State* cpu, u32 address, u64 data) { + if (InBigEndianMode(cpu)) + data = Common::swap64(data); + + Memory::Write64(address, data); +} diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index b9b96c388..368b5a25d 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -1388,12 +1388,20 @@ VSTR_INST: if (inst_cream->single) { - Memory::Write32(addr, cpu->ExtReg[inst_cream->d]); + WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]); } else { - Memory::Write32(addr, cpu->ExtReg[inst_cream->d*2]); - Memory::Write32(addr + 4, cpu->ExtReg[inst_cream->d*2+1]); + const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; + const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; + + if (InBigEndianMode(cpu)) { + WriteMemory32(cpu, addr + 0, word2); + WriteMemory32(cpu, addr + 4, word1); + } else { + WriteMemory32(cpu, addr + 0, word1); + WriteMemory32(cpu, addr + 4, word2); + } } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -1447,17 +1455,27 @@ VPUSH_INST: { if (inst_cream->single) { - Memory::Write32(addr, cpu->ExtReg[inst_cream->d+i]); + WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); addr += 4; } else { - Memory::Write32(addr, cpu->ExtReg[(inst_cream->d+i)*2]); - Memory::Write32(addr + 4, cpu->ExtReg[(inst_cream->d+i)*2 + 1]); + const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; + const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; + + if (InBigEndianMode(cpu)) { + WriteMemory32(cpu, addr + 0, word2); + WriteMemory32(cpu, addr + 4, word1); + } else { + WriteMemory32(cpu, addr + 0, word1); + WriteMemory32(cpu, addr + 4, word2); + } + addr += 8; } } - cpu->Reg[R13] = cpu->Reg[R13] - inst_cream->imm32; + + cpu->Reg[R13] -= inst_cream->imm32; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vpush_inst)); @@ -1516,13 +1534,22 @@ VSTM_INST: /* encoding 1 */ { if (inst_cream->single) { - Memory::Write32(addr, cpu->ExtReg[inst_cream->d+i]); + WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); addr += 4; } else { - Memory::Write32(addr, cpu->ExtReg[(inst_cream->d+i)*2]); - Memory::Write32(addr + 4, cpu->ExtReg[(inst_cream->d+i)*2 + 1]); + const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; + const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; + + if (InBigEndianMode(cpu)) { + WriteMemory32(cpu, addr + 0, word2); + WriteMemory32(cpu, addr + 4, word1); + } else { + WriteMemory32(cpu, addr + 0, word1); + WriteMemory32(cpu, addr + 4, word2); + } + addr += 8; } } @@ -1575,8 +1602,6 @@ VPOP_INST: if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { CHECK_VFP_ENABLED; - unsigned int value1, value2; - vpop_inst *inst_cream = (vpop_inst *)inst_base->component; addr = cpu->Reg[R13]; @@ -1585,20 +1610,26 @@ VPOP_INST: { if (inst_cream->single) { - value1 = Memory::Read32(addr); - cpu->ExtReg[inst_cream->d+i] = value1; + cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); addr += 4; } else { - value1 = Memory::Read32(addr); - value2 = Memory::Read32(addr + 4); - cpu->ExtReg[(inst_cream->d+i)*2] = value1; - cpu->ExtReg[(inst_cream->d+i)*2 + 1] = value2; + const u32 word1 = ReadMemory32(cpu, addr + 0); + const u32 word2 = ReadMemory32(cpu, addr + 4); + + if (InBigEndianMode(cpu)) { + cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; + cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; + } else { + cpu->ExtReg[(inst_cream->d+i)*2+0] = word1; + cpu->ExtReg[(inst_cream->d+i)*2+1] = word2; + } + addr += 8; } } - cpu->Reg[R13] = cpu->Reg[R13] + inst_cream->imm32; + cpu->Reg[R13] += inst_cream->imm32; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vpop_inst)); @@ -1653,16 +1684,20 @@ VLDR_INST: if (inst_cream->single) { - cpu->ExtReg[inst_cream->d] = Memory::Read32(addr); + cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr); } else { - unsigned int word1, word2; - word1 = Memory::Read32(addr); - word2 = Memory::Read32(addr + 4); - - cpu->ExtReg[inst_cream->d*2] = word1; - cpu->ExtReg[inst_cream->d*2+1] = word2; + const u32 word1 = ReadMemory32(cpu, addr + 0); + const u32 word2 = ReadMemory32(cpu, addr + 4); + + if (InBigEndianMode(cpu)) { + cpu->ExtReg[inst_cream->d*2+0] = word2; + cpu->ExtReg[inst_cream->d*2+1] = word1; + } else { + cpu->ExtReg[inst_cream->d*2+0] = word1; + cpu->ExtReg[inst_cream->d*2+1] = word2; + } } } cpu->Reg[15] += GET_INST_SIZE(cpu); @@ -1722,13 +1757,22 @@ VLDM_INST: { if (inst_cream->single) { - cpu->ExtReg[inst_cream->d+i] = Memory::Read32(addr); + cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); addr += 4; } else { - cpu->ExtReg[(inst_cream->d+i)*2] = Memory::Read32(addr); - cpu->ExtReg[(inst_cream->d+i)*2 + 1] = Memory::Read32(addr + 4); + const u32 word1 = ReadMemory32(cpu, addr + 0); + const u32 word2 = ReadMemory32(cpu, addr + 4); + + if (InBigEndianMode(cpu)) { + cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; + cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; + } else { + cpu->ExtReg[(inst_cream->d+i)*2+0] = word1; + cpu->ExtReg[(inst_cream->d+i)*2+1] = word2; + } + addr += 8; } } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e7f9bec7e..138603d9b 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -7,7 +7,7 @@ #include "core/hle/service/hid/hid_spvr.h" #include "core/hle/service/hid/hid_user.h" -#include "core/arm/arm_interface.h" +#include "core/core_timing.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/hle.h" @@ -82,7 +82,7 @@ void HIDUpdate() { // If we just updated index 0, provide a new timestamp if (mem->pad.index == 0) { mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks; - mem->pad.index_reset_ticks = (s64)Core::g_app_core->GetTicks(); + mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks(); } mem->touch.index = next_touch_index; @@ -102,7 +102,7 @@ void HIDUpdate() { // If we just updated index 0, provide a new timestamp if (mem->touch.index == 0) { mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; - mem->touch.index_reset_ticks = (s64)Core::g_app_core->GetTicks(); + mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); } // Signal both handles when there's an update to Pad or touch @@ -114,6 +114,7 @@ void GetIPCHandles(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = 0; // No error + cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom(); @@ -123,6 +124,37 @@ void GetIPCHandles(Service::Interface* self) { cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom(); } +void EnableAccelerometer(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + event_accelerometer->Signal(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_HID, "(STUBBED) called"); +} + +void EnableGyroscopeLow(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + event_gyroscope->Signal(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_HID, "(STUBBED) called"); +} + +void GetSoundVolume(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = volume; + + LOG_WARNING(Service_HID, "(STUBBED) called"); +} + void HIDInit() { using namespace Kernel; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 0946cf660..97462c7f8 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -161,7 +161,7 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; * None * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unused + * 2 : IPC Command Structure translate-header * 3 : Handle to HID_User shared memory * 4 : Event signaled by HID_User * 5 : Event signaled by HID_User @@ -171,6 +171,34 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; */ void GetIPCHandles(Interface* self); +/** + * HID::EnableAccelerometer service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void EnableAccelerometer(Interface* self); + +/** + * HID::EnableGyroscopeLow service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void EnableGyroscopeLow(Interface* self); + +/** + * HID::GetSoundVolume service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : u8 output value + */ +void GetSoundVolume(Interface* self); + /// Checks for user input updates void HIDUpdate(); diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 790dcabbf..f296b076f 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -13,13 +13,13 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0000, GetIPCHandles, "GetIPCHandles"}, {0x000B0000, nullptr, "StartAnalogStickCalibration"}, {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, - {0x00110000, nullptr, "EnableAccelerometer"}, + {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, {0x00120000, nullptr, "DisableAccelerometer"}, - {0x00130000, nullptr, "EnableGyroscopeLow"}, + {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, {0x00140000, nullptr, "DisableGyroscopeLow"}, {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, - {0x00170000, nullptr, "GetSoundVolume"}, + {0x00170000, GetSoundVolume, "GetSoundVolume"}, }; HID_SPVR_Interface::HID_SPVR_Interface() { diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index c2d5758fb..3682c9416 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -10,14 +10,14 @@ namespace Service { namespace HID { const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, GetIPCHandles, "GetIPCHandles"}, - {0x00110000, nullptr, "EnableAccelerometer"}, - {0x00120000, nullptr, "DisableAccelerometer"}, - {0x00130000, nullptr, "EnableGyroscopeLow"}, - {0x00140000, nullptr, "DisableGyroscopeLow"}, - {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, - {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, - {0x00170000, nullptr, "GetSoundVolume"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles"}, + {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, + {0x00120000, nullptr, "DisableAccelerometer"}, + {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, + {0x00140000, nullptr, "DisableGyroscopeLow"}, + {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, + {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, + {0x00170000, GetSoundVolume, "GetSoundVolume"}, }; HID_U_Interface::HID_U_Interface() { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 17385f9b2..bbb4eb9cd 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -7,8 +7,9 @@ #include "common/string_util.h" #include "common/symbols.h" -#include "core/arm/arm_interface.h" +#include "core/core_timing.h" #include "core/mem_map.h" +#include "core/arm/arm_interface.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/event.h" @@ -551,7 +552,7 @@ static void SleepThread(s64 nanoseconds) { /// This returns the total CPU ticks elapsed since the CPU was powered-on static s64 GetSystemTick() { - return (s64)Core::g_app_core->GetTicks(); + return (s64)CoreTiming::GetTicks(); } /// Creates a memory block at the specified address with the specified permissions and size diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index f933a5e8d..e6983a225 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -118,8 +118,14 @@ inline void Write(u32 addr, const T data) { u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); - unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; - unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; + if (config.scaling > config.ScaleXY) { + LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value()); + UNIMPLEMENTED(); + break; + } + + unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; + unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; u32 output_width = config.output_width / horizontal_scale; u32 output_height = config.output_height / vertical_scale; @@ -140,14 +146,23 @@ inline void Write(u32 addr, const T data) { break; } - // TODO(Subv): Blend the pixels when horizontal / vertical scaling is enabled, + // TODO(Subv): Implement the box filter when scaling is enabled // right now we're just skipping the extra pixels. for (u32 y = 0; y < output_height; ++y) { for (u32 x = 0; x < output_width; ++x) { Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; - u32 scaled_x = x * horizontal_scale; - u32 scaled_y = y * vertical_scale; + // Calculate the [x,y] position of the input image + // based on the current output position and the scale + u32 input_x = x * horizontal_scale; + u32 input_y = y * vertical_scale; + + if (config.flip_vertically) { + // Flip the y value of the output data, + // we do this after calculating the [x,y] position of the input image + // to account for the scaling options. + y = output_height - y - 1; + } u32 dst_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.output_format); u32 src_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.input_format); @@ -159,14 +174,14 @@ inline void Write(u32 addr, const T data) { u32 coarse_y = y & ~7; u32 stride = output_width * dst_bytes_per_pixel; - src_offset = (scaled_x + scaled_y * config.input_width) * src_bytes_per_pixel; + src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; } else { // Interpret the input as tiled and the output as linear - u32 coarse_y = scaled_y & ~7; + u32 coarse_y = input_y & ~7; u32 stride = config.input_width * src_bytes_per_pixel; - src_offset = VideoCore::GetMortonOffset(scaled_x, scaled_y, src_bytes_per_pixel) + coarse_y * stride; + src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; dst_offset = (x + y * output_width) * dst_bytes_per_pixel; } diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 5b7f0a4e9..c8f884494 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -188,17 +188,22 @@ struct Regs { BitField<16, 16, u32> input_height; }; + enum ScalingMode : u32 { + NoScale = 0, // Doesn't scale the image + ScaleX = 1, // Downscales the image in half in the X axis and applies a box filter + ScaleXY = 2, // Downscales the image in half in both the X and Y axes and applies a box filter + }; + union { u32 flags; - BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true + BitField< 0, 1, u32> flip_vertically; // flips input data vertically BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing BitField< 8, 3, PixelFormat> input_format; BitField<12, 3, PixelFormat> output_format; - BitField<24, 1, u32> scale_horizontally; - BitField<25, 1, u32> scale_vertically; + BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer }; INSERT_PADDING_WORDS(0x1); diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 9ae2de99f..f6f670060 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -20,8 +20,8 @@ struct NCCH_Header { u16 version; u8 reserved_0[4]; u8 program_id[8]; - u8 temp_flag; - u8 reserved_1[0x2f]; + u8 reserved_1[0x10]; + u8 logo_region_hash[0x20]; u8 product_code[0x10]; u8 extended_header_hash[0x20]; u32 extended_header_size; @@ -29,15 +29,16 @@ struct NCCH_Header { u8 flags[8]; u32 plain_region_offset; u32 plain_region_size; - u8 reserved_3[8]; + u32 logo_region_offset; + u32 logo_region_size; u32 exefs_offset; u32 exefs_size; u32 exefs_hash_region_size; - u8 reserved_4[4]; + u8 reserved_3[4]; u32 romfs_offset; u32 romfs_size; u32 romfs_hash_region_size; - u8 reserved_5[4]; + u8 reserved_4[4]; u8 exefs_super_block_hash[0x20]; u8 romfs_super_block_hash[0x20]; }; @@ -88,8 +89,7 @@ struct ExHeader_DependencyList{ }; struct ExHeader_SystemInfo{ - u32 save_data_size; - u8 reserved[4]; + u64 save_data_size; u8 jump_id[8]; u8 reserved_2[0x30]; }; @@ -104,11 +104,14 @@ struct ExHeader_StorageInfo{ struct ExHeader_ARM11_SystemLocalCaps{ u8 program_id[8]; - u8 flags[8]; - u8 resource_limit_descriptor[0x10][2]; + u32 core_version; + u8 flags[3]; + u8 priority; + u8 resource_limit_descriptor[0x16][2]; ExHeader_StorageInfo storage_info; - u8 service_access_control[0x20][8]; - u8 reserved[0x1f]; + u8 service_access_control[0x32][8]; + u8 ex_service_access_control[0x2][8]; + u8 reserved[0xf]; u8 resource_limit_category; }; diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 8f4f21fec..bce99dffa 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -147,6 +147,7 @@ inline void Write(VAddr addr, T data); u8 Read8(VAddr addr); u16 Read16(VAddr addr); u32 Read32(VAddr addr); +u64 Read64(VAddr addr); u32 Read8_ZX(VAddr addr); u32 Read16_ZX(VAddr addr); diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 48f61db4e..a161a8204 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -245,6 +245,12 @@ u32 Read32(const VAddr addr) { return (u32)data; } +u64 Read64(const VAddr addr) { + u64_le data = 0; + Read<u64_le>(data, addr); + return (u64)data; +} + u32 Read8_ZX(const VAddr addr) { return (u32)Read8(addr); } |