1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <algorithm>
6 #include <cstring>
7 #include <memory>
8 #include "core/arm/dyncom/arm_dyncom.h"
9 #include "core/arm/dyncom/arm_dyncom_interpreter.h"
10 #include "core/arm/dyncom/arm_dyncom_trans.h"
11 #include "core/arm/skyeye_common/armstate.h"
12 #include "core/core.h"
13 #include "core/core_timing.h"
14
15 class DynComThreadContext final : public ARM_Interface::ThreadContext {
16 public:
DynComThreadContext()17 DynComThreadContext() {
18 Reset();
19 }
20 ~DynComThreadContext() override = default;
21
Reset()22 void Reset() override {
23 cpu_registers = {};
24 cpsr = 0;
25 fpu_registers = {};
26 fpscr = 0;
27 fpexc = 0;
28 }
29
GetCpuRegister(std::size_t index) const30 u32 GetCpuRegister(std::size_t index) const override {
31 return cpu_registers[index];
32 }
SetCpuRegister(std::size_t index,u32 value)33 void SetCpuRegister(std::size_t index, u32 value) override {
34 cpu_registers[index] = value;
35 }
GetCpsr() const36 u32 GetCpsr() const override {
37 return cpsr;
38 }
SetCpsr(u32 value)39 void SetCpsr(u32 value) override {
40 cpsr = value;
41 }
GetFpuRegister(std::size_t index) const42 u32 GetFpuRegister(std::size_t index) const override {
43 return fpu_registers[index];
44 }
SetFpuRegister(std::size_t index,u32 value)45 void SetFpuRegister(std::size_t index, u32 value) override {
46 fpu_registers[index] = value;
47 }
GetFpscr() const48 u32 GetFpscr() const override {
49 return fpscr;
50 }
SetFpscr(u32 value)51 void SetFpscr(u32 value) override {
52 fpscr = value;
53 }
GetFpexc() const54 u32 GetFpexc() const override {
55 return fpexc;
56 }
SetFpexc(u32 value)57 void SetFpexc(u32 value) override {
58 fpexc = value;
59 }
60
61 private:
62 friend class ARM_DynCom;
63
64 std::array<u32, 16> cpu_registers;
65 u32 cpsr;
66 std::array<u32, 64> fpu_registers;
67 u32 fpscr;
68 u32 fpexc;
69 };
70
ARM_DynCom(Core::System * system,Memory::MemorySystem & memory,PrivilegeMode initial_mode,u32 id,std::shared_ptr<Core::Timing::Timer> timer)71 ARM_DynCom::ARM_DynCom(Core::System* system, Memory::MemorySystem& memory,
72 PrivilegeMode initial_mode, u32 id,
73 std::shared_ptr<Core::Timing::Timer> timer)
74 : ARM_Interface(id, timer), system(system) {
75 state = std::make_unique<ARMul_State>(system, memory, initial_mode);
76 }
77
~ARM_DynCom()78 ARM_DynCom::~ARM_DynCom() {}
79
Run()80 void ARM_DynCom::Run() {
81 DEBUG_ASSERT(system != nullptr);
82 ExecuteInstructions(std::max<s64>(timer->GetDowncount(), 0));
83 }
84
Step()85 void ARM_DynCom::Step() {
86 ExecuteInstructions(1);
87 }
88
ClearInstructionCache()89 void ARM_DynCom::ClearInstructionCache() {
90 state->instruction_cache.clear();
91 trans_cache_buf_top = 0;
92 }
93
InvalidateCacheRange(u32,std::size_t)94 void ARM_DynCom::InvalidateCacheRange(u32, std::size_t) {
95 ClearInstructionCache();
96 }
97
SetPageTable(const std::shared_ptr<Memory::PageTable> & page_table)98 void ARM_DynCom::SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) {
99 ClearInstructionCache();
100 }
101
GetPageTable() const102 std::shared_ptr<Memory::PageTable> ARM_DynCom::GetPageTable() const {
103 return nullptr;
104 }
105
PurgeState()106 void ARM_DynCom::PurgeState() {}
107
SetPC(u32 pc)108 void ARM_DynCom::SetPC(u32 pc) {
109 state->Reg[15] = pc;
110 }
111
GetPC() const112 u32 ARM_DynCom::GetPC() const {
113 return state->Reg[15];
114 }
115
GetReg(int index) const116 u32 ARM_DynCom::GetReg(int index) const {
117 return state->Reg[index];
118 }
119
SetReg(int index,u32 value)120 void ARM_DynCom::SetReg(int index, u32 value) {
121 state->Reg[index] = value;
122 }
123
GetVFPReg(int index) const124 u32 ARM_DynCom::GetVFPReg(int index) const {
125 return state->ExtReg[index];
126 }
127
SetVFPReg(int index,u32 value)128 void ARM_DynCom::SetVFPReg(int index, u32 value) {
129 state->ExtReg[index] = value;
130 }
131
GetVFPSystemReg(VFPSystemRegister reg) const132 u32 ARM_DynCom::GetVFPSystemReg(VFPSystemRegister reg) const {
133 return state->VFP[reg];
134 }
135
SetVFPSystemReg(VFPSystemRegister reg,u32 value)136 void ARM_DynCom::SetVFPSystemReg(VFPSystemRegister reg, u32 value) {
137 state->VFP[reg] = value;
138 }
139
GetCPSR() const140 u32 ARM_DynCom::GetCPSR() const {
141 return state->Cpsr;
142 }
143
SetCPSR(u32 cpsr)144 void ARM_DynCom::SetCPSR(u32 cpsr) {
145 state->Cpsr = cpsr;
146 }
147
GetCP15Register(CP15Register reg) const148 u32 ARM_DynCom::GetCP15Register(CP15Register reg) const {
149 return state->CP15[reg];
150 }
151
SetCP15Register(CP15Register reg,u32 value)152 void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) {
153 state->CP15[reg] = value;
154 }
155
ExecuteInstructions(u64 num_instructions)156 void ARM_DynCom::ExecuteInstructions(u64 num_instructions) {
157 state->NumInstrsToExecute = num_instructions;
158 unsigned ticks_executed = InterpreterMainLoop(state.get());
159 if (system != nullptr) {
160 timer->AddTicks(ticks_executed);
161 }
162 state->ServeBreak();
163 }
164
NewContext() const165 std::unique_ptr<ARM_Interface::ThreadContext> ARM_DynCom::NewContext() const {
166 return std::make_unique<DynComThreadContext>();
167 }
168
SaveContext(const std::unique_ptr<ThreadContext> & arg)169 void ARM_DynCom::SaveContext(const std::unique_ptr<ThreadContext>& arg) {
170 DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(arg.get());
171 ASSERT(ctx);
172
173 ctx->cpu_registers = state->Reg;
174 ctx->cpsr = state->Cpsr;
175 ctx->fpu_registers = state->ExtReg;
176 ctx->fpscr = state->VFP[VFP_FPSCR];
177 ctx->fpexc = state->VFP[VFP_FPEXC];
178 }
179
LoadContext(const std::unique_ptr<ThreadContext> & arg)180 void ARM_DynCom::LoadContext(const std::unique_ptr<ThreadContext>& arg) {
181 DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(arg.get());
182 ASSERT(ctx);
183
184 state->Reg = ctx->cpu_registers;
185 state->Cpsr = ctx->cpsr;
186 state->ExtReg = ctx->fpu_registers;
187 state->VFP[VFP_FPSCR] = ctx->fpscr;
188 state->VFP[VFP_FPEXC] = ctx->fpexc;
189 }
190
PrepareReschedule()191 void ARM_DynCom::PrepareReschedule() {
192 state->NumInstrsToExecute = 0;
193 }
194