summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2014-12-23 22:45:52 -0500
committerGravatar bunnei2014-12-25 22:46:44 -0500
commit4783133bbd651590b5116be95a5deda31fe9f4dc (patch)
treedaf8cd9fd9be955d30ba217087003ed653342cb3 /src
parentUpdate README.md (fix typo) (diff)
downloadyuzu-4783133bbd651590b5116be95a5deda31fe9f4dc.tar.gz
yuzu-4783133bbd651590b5116be95a5deda31fe9f4dc.tar.xz
yuzu-4783133bbd651590b5116be95a5deda31fe9f4dc.zip
ARM: Add a mechanism for faking CPU time elapsed during HLE.
- Also a few cleanups.
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/arm_interface.h6
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp49
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h14
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp51
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h6
-rw-r--r--src/core/hle/hle.cpp8
6 files changed, 39 insertions, 95 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index c59355339..3b7209418 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -78,6 +78,12 @@ public:
78 virtual u64 GetTicks() const = 0; 78 virtual u64 GetTicks() const = 0;
79 79
80 /** 80 /**
81 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
82 * @param ticks Number of ticks to advance the CPU core
83 */
84 virtual void AddTicks(u64 ticks) = 0;
85
86 /**
81 * Saves the current CPU context 87 * Saves the current CPU context
82 * @param ctx Thread context to save 88 * @param ctx Thread context to save
83 */ 89 */
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 6d4fb1b48..a838fd25a 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -47,68 +47,38 @@ ARM_DynCom::ARM_DynCom() : ticks(0) {
47ARM_DynCom::~ARM_DynCom() { 47ARM_DynCom::~ARM_DynCom() {
48} 48}
49 49
50/**
51 * Set the Program Counter to an address
52 * @param addr Address to set PC to
53 */
54void ARM_DynCom::SetPC(u32 pc) { 50void ARM_DynCom::SetPC(u32 pc) {
55 state->pc = state->Reg[15] = pc; 51 state->pc = state->Reg[15] = pc;
56} 52}
57 53
58/*
59 * Get the current Program Counter
60 * @return Returns current PC
61 */
62u32 ARM_DynCom::GetPC() const { 54u32 ARM_DynCom::GetPC() const {
63 return state->Reg[15]; 55 return state->Reg[15];
64} 56}
65 57
66/**
67 * Get an ARM register
68 * @param index Register index (0-15)
69 * @return Returns the value in the register
70 */
71u32 ARM_DynCom::GetReg(int index) const { 58u32 ARM_DynCom::GetReg(int index) const {
72 return state->Reg[index]; 59 return state->Reg[index];
73} 60}
74 61
75/**
76 * Set an ARM register
77 * @param index Register index (0-15)
78 * @param value Value to set register to
79 */
80void ARM_DynCom::SetReg(int index, u32 value) { 62void ARM_DynCom::SetReg(int index, u32 value) {
81 state->Reg[index] = value; 63 state->Reg[index] = value;
82} 64}
83 65
84/**
85 * Get the current CPSR register
86 * @return Returns the value of the CPSR register
87 */
88u32 ARM_DynCom::GetCPSR() const { 66u32 ARM_DynCom::GetCPSR() const {
89 return state->Cpsr; 67 return state->Cpsr;
90} 68}
91 69
92/**
93 * Set the current CPSR register
94 * @param cpsr Value to set CPSR to
95 */
96void ARM_DynCom::SetCPSR(u32 cpsr) { 70void ARM_DynCom::SetCPSR(u32 cpsr) {
97 state->Cpsr = cpsr; 71 state->Cpsr = cpsr;
98} 72}
99 73
100/**
101 * Returns the number of clock ticks since the last reset
102 * @return Returns number of clock ticks
103 */
104u64 ARM_DynCom::GetTicks() const { 74u64 ARM_DynCom::GetTicks() const {
105 return ticks; 75 return ticks;
106} 76}
107 77
108/** 78void ARM_DynCom::AddTicks(u64 ticks) {
109 * Executes the given number of instructions 79 this->ticks += ticks;
110 * @param num_instructions Number of instructions to executes 80}
111 */ 81
112void ARM_DynCom::ExecuteInstructions(int num_instructions) { 82void ARM_DynCom::ExecuteInstructions(int num_instructions) {
113 state->NumInstrsToExecute = num_instructions; 83 state->NumInstrsToExecute = num_instructions;
114 84
@@ -118,11 +88,6 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
118 ticks += InterpreterMainLoop(state.get()); 88 ticks += InterpreterMainLoop(state.get());
119} 89}
120 90
121/**
122 * Saves the current CPU context
123 * @param ctx Thread context to save
124 * @todo Do we need to save Reg[15] and NextInstr?
125 */
126void ARM_DynCom::SaveContext(ThreadContext& ctx) { 91void ARM_DynCom::SaveContext(ThreadContext& ctx) {
127 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); 92 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
128 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); 93 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
@@ -139,11 +104,6 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) {
139 ctx.mode = state->NextInstr; 104 ctx.mode = state->NextInstr;
140} 105}
141 106
142/**
143 * Loads a CPU context
144 * @param ctx Thread context to load
145 * @param Do we need to load Reg[15] and NextInstr?
146 */
147void ARM_DynCom::LoadContext(const ThreadContext& ctx) { 107void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
148 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); 108 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
149 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); 109 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
@@ -160,7 +120,6 @@ void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
160 state->NextInstr = ctx.mode; 120 state->NextInstr = ctx.mode;
161} 121}
162 122
163/// Prepare core for thread reschedule (if needed to correctly handle state)
164void ARM_DynCom::PrepareReschedule() { 123void ARM_DynCom::PrepareReschedule() {
165 state->NumInstrsToExecute = 0; 124 state->NumInstrsToExecute = 0;
166} 125}
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 6fa2a0ba7..7284dcd07 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -27,14 +27,14 @@ public:
27 * Get the current Program Counter 27 * Get the current Program Counter
28 * @return Returns current PC 28 * @return Returns current PC
29 */ 29 */
30 u32 GetPC() const; 30 u32 GetPC() const override;
31 31
32 /** 32 /**
33 * Get an ARM register 33 * Get an ARM register
34 * @param index Register index (0-15) 34 * @param index Register index (0-15)
35 * @return Returns the value in the register 35 * @return Returns the value in the register
36 */ 36 */
37 u32 GetReg(int index) const; 37 u32 GetReg(int index) const override;
38 38
39 /** 39 /**
40 * Set an ARM register 40 * Set an ARM register
@@ -47,7 +47,7 @@ public:
47 * Get the current CPSR register 47 * Get the current CPSR register
48 * @return Returns the value of the CPSR register 48 * @return Returns the value of the CPSR register
49 */ 49 */
50 u32 GetCPSR() const; 50 u32 GetCPSR() const override;
51 51
52 /** 52 /**
53 * Set the current CPSR register 53 * Set the current CPSR register
@@ -59,7 +59,13 @@ public:
59 * Returns the number of clock ticks since the last reset 59 * Returns the number of clock ticks since the last reset
60 * @return Returns number of clock ticks 60 * @return Returns number of clock ticks
61 */ 61 */
62 u64 GetTicks() const; 62 u64 GetTicks() const override;
63
64 /**
65 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
66 * @param ticks Number of ticks to advance the CPU core
67 */
68 void AddTicks(u64 ticks) override;
63 69
64 /** 70 /**
65 * Saves the current CPU context 71 * Saves the current CPU context
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index be04fc1a1..80ebc359e 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -38,78 +38,43 @@ ARM_Interpreter::~ARM_Interpreter() {
38 delete state; 38 delete state;
39} 39}
40 40
41/**
42 * Set the Program Counter to an address
43 * @param addr Address to set PC to
44 */
45void ARM_Interpreter::SetPC(u32 pc) { 41void ARM_Interpreter::SetPC(u32 pc) {
46 state->pc = state->Reg[15] = pc; 42 state->pc = state->Reg[15] = pc;
47} 43}
48 44
49/*
50 * Get the current Program Counter
51 * @return Returns current PC
52 */
53u32 ARM_Interpreter::GetPC() const { 45u32 ARM_Interpreter::GetPC() const {
54 return state->pc; 46 return state->pc;
55} 47}
56 48
57/**
58 * Get an ARM register
59 * @param index Register index (0-15)
60 * @return Returns the value in the register
61 */
62u32 ARM_Interpreter::GetReg(int index) const { 49u32 ARM_Interpreter::GetReg(int index) const {
63 return state->Reg[index]; 50 return state->Reg[index];
64} 51}
65 52
66/**
67 * Set an ARM register
68 * @param index Register index (0-15)
69 * @param value Value to set register to
70 */
71void ARM_Interpreter::SetReg(int index, u32 value) { 53void ARM_Interpreter::SetReg(int index, u32 value) {
72 state->Reg[index] = value; 54 state->Reg[index] = value;
73} 55}
74 56
75/**
76 * Get the current CPSR register
77 * @return Returns the value of the CPSR register
78 */
79u32 ARM_Interpreter::GetCPSR() const { 57u32 ARM_Interpreter::GetCPSR() const {
80 return state->Cpsr; 58 return state->Cpsr;
81} 59}
82 60
83/**
84 * Set the current CPSR register
85 * @param cpsr Value to set CPSR to
86 */
87void ARM_Interpreter::SetCPSR(u32 cpsr) { 61void ARM_Interpreter::SetCPSR(u32 cpsr) {
88 state->Cpsr = cpsr; 62 state->Cpsr = cpsr;
89} 63}
90 64
91/**
92 * Returns the number of clock ticks since the last reset
93 * @return Returns number of clock ticks
94 */
95u64 ARM_Interpreter::GetTicks() const { 65u64 ARM_Interpreter::GetTicks() const {
96 return ARMul_Time(state); 66 return state->NumInstrs;
67}
68
69void ARM_Interpreter::AddTicks(u64 ticks) {
70 state->NumInstrs += ticks;
97} 71}
98 72
99/**
100 * Executes the given number of instructions
101 * @param num_instructions Number of instructions to executes
102 */
103void ARM_Interpreter::ExecuteInstructions(int num_instructions) { 73void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
104 state->NumInstrsToExecute = num_instructions - 1; 74 state->NumInstrsToExecute = num_instructions - 1;
105 ARMul_Emulate32(state); 75 ARMul_Emulate32(state);
106} 76}
107 77
108/**
109 * Saves the current CPU context
110 * @param ctx Thread context to save
111 * @todo Do we need to save Reg[15] and NextInstr?
112 */
113void ARM_Interpreter::SaveContext(ThreadContext& ctx) { 78void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
114 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); 79 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
115 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); 80 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
@@ -126,11 +91,6 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
126 ctx.mode = state->NextInstr; 91 ctx.mode = state->NextInstr;
127} 92}
128 93
129/**
130 * Loads a CPU context
131 * @param ctx Thread context to load
132 * @param Do we need to load Reg[15] and NextInstr?
133 */
134void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { 94void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
135 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); 95 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
136 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); 96 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
@@ -147,7 +107,6 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
147 state->NextInstr = ctx.mode; 107 state->NextInstr = ctx.mode;
148} 108}
149 109
150/// Prepare core for thread reschedule (if needed to correctly handle state)
151void ARM_Interpreter::PrepareReschedule() { 110void ARM_Interpreter::PrepareReschedule() {
152 state->NumInstrsToExecute = 0; 111 state->NumInstrsToExecute = 0;
153} 112}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index b685215a0..019dad5df 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -61,6 +61,12 @@ public:
61 u64 GetTicks() const override; 61 u64 GetTicks() const override;
62 62
63 /** 63 /**
64 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
65 * @param ticks Number of ticks to advance the CPU core
66 */
67 void AddTicks(u64 ticks) override;
68
69 /**
64 * Saves the current CPU context 70 * Saves the current CPU context
65 * @param ctx Thread context to save 71 * @param ctx Thread context to save
66 */ 72 */
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 2d314a4cf..33ac12507 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -43,7 +43,15 @@ void CallSVC(u32 opcode) {
43 43
44void Reschedule(const char *reason) { 44void Reschedule(const char *reason) {
45 _dbg_assert_msg_(Kernel, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason."); 45 _dbg_assert_msg_(Kernel, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
46
47 // TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
48 // routines. This simulates that time by artificially advancing the number of CPU "ticks".
49 // The value was chosen empirically, it seems to work well enough for everything tested, but
50 // is likely not ideal. We should find a more accurate way to simulate timing with HLE.
51 Core::g_app_core->AddTicks(4000);
52
46 Core::g_app_core->PrepareReschedule(); 53 Core::g_app_core->PrepareReschedule();
54
47 g_reschedule = true; 55 g_reschedule = true;
48} 56}
49 57