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