summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/arm_interface.h6
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp5
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h1
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp150
-rw-r--r--src/core/arm/interpreter/armsupp.cpp6
-rw-r--r--src/core/arm/skyeye_common/armdefs.h3
-rw-r--r--src/core/arm/skyeye_common/armmmu.h105
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp102
-rw-r--r--src/core/hle/service/hid/hid.cpp38
-rw-r--r--src/core/hle/service/hid/hid.h30
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp6
-rw-r--r--src/core/hle/service/hid/hid_user.cpp16
-rw-r--r--src/core/hle/svc.cpp5
-rw-r--r--src/core/hw/gpu.cpp31
-rw-r--r--src/core/hw/gpu.h11
-rw-r--r--src/core/loader/ncch.h25
-rw-r--r--src/core/mem_map.h1
-rw-r--r--src/core/mem_map_funcs.cpp6
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);
}