| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							| 
									
										
										
										
											2014-12-16 21:38:14 -08:00
										 |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-06 04:06:12 -03:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2016-04-05 13:29:55 +01:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2015-04-27 22:44:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 21:10:41 -04:00
										 |  |  | #include "core/arm/skyeye_common/armstate.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-25 20:19:39 -04:00
										 |  |  | #include "core/arm/skyeye_common/armsupp.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | #include "core/arm/skyeye_common/vfp/vfp.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "core/arm/dyncom/arm_dyncom.h"
 | 
					
						
							|  |  |  | #include "core/arm/dyncom/arm_dyncom_interpreter.h"
 | 
					
						
							| 
									
										
										
										
											2015-02-12 15:11:39 -05:00
										 |  |  | #include "core/arm/dyncom/arm_dyncom_run.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 04:30:09 -02:00
										 |  |  | #include "core/core.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-05 20:17:49 -05:00
										 |  |  | #include "core/core_timing.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-12 15:11:39 -05:00
										 |  |  | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | 
					
						
							| 
									
										
										
										
											2016-04-05 13:29:55 +01:00
										 |  |  |     state = std::make_unique<ARMul_State>(initial_mode); | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ARM_DynCom::~ARM_DynCom() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetPC(u32 pc) { | 
					
						
							| 
									
										
										
										
											2015-01-31 21:44:35 -05:00
										 |  |  |     state->Reg[15] = pc; | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 ARM_DynCom::GetPC() const { | 
					
						
							| 
									
										
										
										
											2014-11-09 17:00:59 -05:00
										 |  |  |     return state->Reg[15]; | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 ARM_DynCom::GetReg(int index) const { | 
					
						
							|  |  |  |     return state->Reg[index]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetReg(int index, u32 value) { | 
					
						
							|  |  |  |     state->Reg[index] = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 21:24:25 -04:00
										 |  |  | u32 ARM_DynCom::GetVFPReg(int index) const { | 
					
						
							|  |  |  |     return state->ExtReg[index]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetVFPReg(int index, u32 value) { | 
					
						
							|  |  |  |     state->ExtReg[index] = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 ARM_DynCom::GetVFPSystemReg(VFPSystemRegister reg) const { | 
					
						
							|  |  |  |     return state->VFP[reg]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { | 
					
						
							|  |  |  |     state->VFP[reg] = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | u32 ARM_DynCom::GetCPSR() const { | 
					
						
							|  |  |  |     return state->Cpsr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetCPSR(u32 cpsr) { | 
					
						
							|  |  |  |     state->Cpsr = cpsr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-06 12:57:49 -04:00
										 |  |  | u32 ARM_DynCom::GetCP15Register(CP15Register reg) { | 
					
						
							|  |  |  |     return state->CP15[reg]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) { | 
					
						
							|  |  |  |     state->CP15[reg] = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-23 22:45:52 -05:00
										 |  |  | void ARM_DynCom::AddTicks(u64 ticks) { | 
					
						
							| 
									
										
										
										
											2015-01-05 20:17:49 -05:00
										 |  |  |     down_count -= ticks; | 
					
						
							|  |  |  |     if (down_count < 0) | 
					
						
							|  |  |  |         CoreTiming::Advance(); | 
					
						
							| 
									
										
										
										
											2014-12-23 22:45:52 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | void ARM_DynCom::ExecuteInstructions(int num_instructions) { | 
					
						
							|  |  |  |     state->NumInstrsToExecute = num_instructions; | 
					
						
							| 
									
										
										
										
											2014-11-09 01:26:03 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
 | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  |     // executing one instruction at a time. Otherwise, if a block is being executed, more
 | 
					
						
							| 
									
										
										
										
											2014-11-09 01:26:03 -05:00
										 |  |  |     // instructions may actually be executed than specified.
 | 
					
						
							| 
									
										
										
										
											2015-01-05 20:17:49 -05:00
										 |  |  |     unsigned ticks_executed = InterpreterMainLoop(state.get()); | 
					
						
							|  |  |  |     AddTicks(ticks_executed); | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 22:56:17 -08:00
										 |  |  | void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | 
					
						
							|  |  |  |     memset(&context, 0, sizeof(Core::ThreadContext)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context.cpu_registers[0] = arg; | 
					
						
							|  |  |  |     context.pc = entry_point; | 
					
						
							|  |  |  |     context.sp = stack_top; | 
					
						
							|  |  |  |     context.cpsr = 0x1F; // Usermode
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 04:30:09 -02:00
										 |  |  | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | 
					
						
							| 
									
										
										
										
											2015-07-26 11:39:57 -04:00
										 |  |  |     memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); | 
					
						
							|  |  |  |     memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ctx.sp = state->Reg[13]; | 
					
						
							|  |  |  |     ctx.lr = state->Reg[14]; | 
					
						
							| 
									
										
										
										
											2014-11-09 17:00:59 -05:00
										 |  |  |     ctx.pc = state->Reg[15]; | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  |     ctx.cpsr = state->Cpsr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx.fpscr = state->VFP[1]; | 
					
						
							|  |  |  |     ctx.fpexc = state->VFP[2]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 04:30:09 -02:00
										 |  |  | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | 
					
						
							| 
									
										
										
										
											2015-07-26 11:39:57 -04:00
										 |  |  |     memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); | 
					
						
							|  |  |  |     memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     state->Reg[13] = ctx.sp; | 
					
						
							|  |  |  |     state->Reg[14] = ctx.lr; | 
					
						
							| 
									
										
										
										
											2015-01-31 21:44:35 -05:00
										 |  |  |     state->Reg[15] = ctx.pc; | 
					
						
							| 
									
										
										
										
											2014-09-12 18:34:51 -04:00
										 |  |  |     state->Cpsr = ctx.cpsr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     state->VFP[1] = ctx.fpscr; | 
					
						
							|  |  |  |     state->VFP[2] = ctx.fpexc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM_DynCom::PrepareReschedule() { | 
					
						
							|  |  |  |     state->NumInstrsToExecute = 0; | 
					
						
							|  |  |  | } |