mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #1001 from lioncash/arm
dyncom: Centralize state-related functions.
This commit is contained in:
		
						commit
						62caa89f48
					
				
					 12 changed files with 1028 additions and 1109 deletions
				
			
		|  | @ -4,9 +4,8 @@ set(SRCS | ||||||
|             arm/dyncom/arm_dyncom.cpp |             arm/dyncom/arm_dyncom.cpp | ||||||
|             arm/dyncom/arm_dyncom_dec.cpp |             arm/dyncom/arm_dyncom_dec.cpp | ||||||
|             arm/dyncom/arm_dyncom_interpreter.cpp |             arm/dyncom/arm_dyncom_interpreter.cpp | ||||||
|             arm/dyncom/arm_dyncom_run.cpp |  | ||||||
|             arm/dyncom/arm_dyncom_thumb.cpp |             arm/dyncom/arm_dyncom_thumb.cpp | ||||||
|             arm/skyeye_common/arminit.cpp |             arm/skyeye_common/armstate.cpp | ||||||
|             arm/skyeye_common/armsupp.cpp |             arm/skyeye_common/armsupp.cpp | ||||||
|             arm/skyeye_common/vfp/vfp.cpp |             arm/skyeye_common/vfp/vfp.cpp | ||||||
|             arm/skyeye_common/vfp/vfpdouble.cpp |             arm/skyeye_common/vfp/vfpdouble.cpp | ||||||
|  | @ -133,7 +132,6 @@ set(HEADERS | ||||||
|             arm/dyncom/arm_dyncom_thumb.h |             arm/dyncom/arm_dyncom_thumb.h | ||||||
|             arm/skyeye_common/arm_regformat.h |             arm/skyeye_common/arm_regformat.h | ||||||
|             arm/skyeye_common/armstate.h |             arm/skyeye_common/armstate.h | ||||||
|             arm/skyeye_common/armmmu.h |  | ||||||
|             arm/skyeye_common/armsupp.h |             arm/skyeye_common/armsupp.h | ||||||
|             arm/skyeye_common/vfp/asm_vfp.h |             arm/skyeye_common/vfp/asm_vfp.h | ||||||
|             arm/skyeye_common/vfp/vfp.h |             arm/skyeye_common/vfp/vfp.h | ||||||
|  |  | ||||||
|  | @ -18,16 +18,7 @@ | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| 
 | 
 | ||||||
| ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | ||||||
|     state = Common::make_unique<ARMul_State>(); |     state = Common::make_unique<ARMul_State>(initial_mode); | ||||||
| 
 |  | ||||||
|     // Reset the core to initial state
 |  | ||||||
|     ARMul_Reset(state.get()); |  | ||||||
| 
 |  | ||||||
|     // Switch to the desired privilege mode.
 |  | ||||||
|     switch_mode(state.get(), initial_mode); |  | ||||||
| 
 |  | ||||||
|     state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
 |  | ||||||
|     state->Reg[15] = 0x00000000; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ARM_DynCom::~ARM_DynCom() { | ARM_DynCom::~ARM_DynCom() { | ||||||
|  | @ -91,8 +82,8 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | ||||||
|     memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); |     memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); | ||||||
|     memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); |     memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); | ||||||
| 
 | 
 | ||||||
|     ctx.sp = state->Reg[13]; |     ctx.sp = state->Reg[13]; | ||||||
|     ctx.lr = state->Reg[14]; |     ctx.lr = state->Reg[14]; | ||||||
|  | @ -104,8 +95,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | ||||||
|     memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); |     memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); | ||||||
|     memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); |     memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); | ||||||
| 
 | 
 | ||||||
|     state->Reg[13] = ctx.sp; |     state->Reg[13] = ctx.sp; | ||||||
|     state->Reg[14] = ctx.lr; |     state->Reg[14] = ctx.lr; | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,93 +0,0 @@ | ||||||
| // Copyright 2012 Michael Kang, 2014 Citra Emulator Project
 |  | ||||||
| // Licensed under GPLv2 or any later version
 |  | ||||||
| // Refer to the license.txt file included.
 |  | ||||||
| 
 |  | ||||||
| #include "core/arm/dyncom/arm_dyncom_run.h" |  | ||||||
| #include "core/arm/skyeye_common/armstate.h" |  | ||||||
| 
 |  | ||||||
| void switch_mode(ARMul_State* core, uint32_t mode) { |  | ||||||
|     if (core->Mode == mode) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     if (mode != USERBANK) { |  | ||||||
|         switch (core->Mode) { |  | ||||||
|         case SYSTEM32MODE: // Shares registers with user mode
 |  | ||||||
|         case USER32MODE: |  | ||||||
|             core->Reg_usr[0] = core->Reg[13]; |  | ||||||
|             core->Reg_usr[1] = core->Reg[14]; |  | ||||||
|             break; |  | ||||||
|         case IRQ32MODE: |  | ||||||
|             core->Reg_irq[0] = core->Reg[13]; |  | ||||||
|             core->Reg_irq[1] = core->Reg[14]; |  | ||||||
|             core->Spsr[IRQBANK] = core->Spsr_copy; |  | ||||||
|             break; |  | ||||||
|         case SVC32MODE: |  | ||||||
|             core->Reg_svc[0] = core->Reg[13]; |  | ||||||
|             core->Reg_svc[1] = core->Reg[14]; |  | ||||||
|             core->Spsr[SVCBANK] = core->Spsr_copy; |  | ||||||
|             break; |  | ||||||
|         case ABORT32MODE: |  | ||||||
|             core->Reg_abort[0] = core->Reg[13]; |  | ||||||
|             core->Reg_abort[1] = core->Reg[14]; |  | ||||||
|             core->Spsr[ABORTBANK] = core->Spsr_copy; |  | ||||||
|             break; |  | ||||||
|         case UNDEF32MODE: |  | ||||||
|             core->Reg_undef[0] = core->Reg[13]; |  | ||||||
|             core->Reg_undef[1] = core->Reg[14]; |  | ||||||
|             core->Spsr[UNDEFBANK] = core->Spsr_copy; |  | ||||||
|             break; |  | ||||||
|         case FIQ32MODE: |  | ||||||
|             core->Reg_firq[0] = core->Reg[13]; |  | ||||||
|             core->Reg_firq[1] = core->Reg[14]; |  | ||||||
|             core->Spsr[FIQBANK] = core->Spsr_copy; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         switch (mode) { |  | ||||||
|         case USER32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_usr[0]; |  | ||||||
|             core->Reg[14] = core->Reg_usr[1]; |  | ||||||
|             core->Bank = USERBANK; |  | ||||||
|             break; |  | ||||||
|         case IRQ32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_irq[0]; |  | ||||||
|             core->Reg[14] = core->Reg_irq[1]; |  | ||||||
|             core->Spsr_copy = core->Spsr[IRQBANK]; |  | ||||||
|             core->Bank = IRQBANK; |  | ||||||
|             break; |  | ||||||
|         case SVC32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_svc[0]; |  | ||||||
|             core->Reg[14] = core->Reg_svc[1]; |  | ||||||
|             core->Spsr_copy = core->Spsr[SVCBANK]; |  | ||||||
|             core->Bank = SVCBANK; |  | ||||||
|             break; |  | ||||||
|         case ABORT32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_abort[0]; |  | ||||||
|             core->Reg[14] = core->Reg_abort[1]; |  | ||||||
|             core->Spsr_copy = core->Spsr[ABORTBANK]; |  | ||||||
|             core->Bank = ABORTBANK; |  | ||||||
|             break; |  | ||||||
|         case UNDEF32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_undef[0]; |  | ||||||
|             core->Reg[14] = core->Reg_undef[1]; |  | ||||||
|             core->Spsr_copy = core->Spsr[UNDEFBANK]; |  | ||||||
|             core->Bank = UNDEFBANK; |  | ||||||
|             break; |  | ||||||
|         case FIQ32MODE: |  | ||||||
|             core->Reg[13] = core->Reg_firq[0]; |  | ||||||
|             core->Reg[14] = core->Reg_firq[1]; |  | ||||||
|             core->Spsr_copy = core->Spsr[FIQBANK]; |  | ||||||
|             core->Bank = FIQBANK; |  | ||||||
|             break; |  | ||||||
|         case SYSTEM32MODE: // Shares registers with user mode.
 |  | ||||||
|             core->Reg[13] = core->Reg_usr[0]; |  | ||||||
|             core->Reg[14] = core->Reg_usr[1]; |  | ||||||
|             core->Bank = SYSTEMBANK; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Set the mode bits in the APSR
 |  | ||||||
|         core->Cpsr = (core->Cpsr & ~core->Mode) | mode; |  | ||||||
|         core->Mode = mode; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -20,38 +20,29 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/arm/skyeye_common/armstate.h" | #include "core/arm/skyeye_common/armstate.h" | ||||||
| 
 | 
 | ||||||
| void switch_mode(ARMul_State* core, uint32_t mode); |  | ||||||
| 
 |  | ||||||
| // Note that for the 3DS, a Thumb instruction will only ever be
 |  | ||||||
| // two bytes in size. Thus we don't need to worry about ThumbEE
 |  | ||||||
| // or Thumb-2 where instructions can be 4 bytes in length.
 |  | ||||||
| static inline u32 GET_INST_SIZE(ARMul_State* core) { |  | ||||||
|     return core->TFlag? 2 : 4; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Checks if the PC is being read, and if so, word-aligns it. |  * Checks if the PC is being read, and if so, word-aligns it. | ||||||
|  * Used with address calculations. |  * Used with address calculations. | ||||||
|  * |  * | ||||||
|  * @param core The ARM CPU state instance. |  * @param cpu The ARM CPU state instance. | ||||||
|  * @param Rn   The register being read. |  * @param Rn   The register being read. | ||||||
|  * |  * | ||||||
|  * @return If the PC is being read, then the word-aligned PC value is returned. |  * @return If the PC is being read, then the word-aligned PC value is returned. | ||||||
|  *         If the PC is not being read, then the value stored in the register is returned. |  *         If the PC is not being read, then the value stored in the register is returned. | ||||||
|  */ |  */ | ||||||
| static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) { | static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) { | ||||||
|     return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; |     return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Reads the PC. Used for data processing operations that use the PC. |  * Reads the PC. Used for data processing operations that use the PC. | ||||||
|  * |  * | ||||||
|  * @param core The ARM CPU state instance. |  * @param cpu The ARM CPU state instance. | ||||||
|  * @param Rn   The register being read. |  * @param Rn   The register being read. | ||||||
|  * |  * | ||||||
|  * @return If the PC is being read, then the incremented PC value is returned. |  * @return If the PC is being read, then the incremented PC value is returned. | ||||||
|  *         If the PC is not being read, then the values stored in the register is returned. |  *         If the PC is not being read, then the values stored in the register is returned. | ||||||
|  */ |  */ | ||||||
| static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) { | static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) { | ||||||
|     return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; |     return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,100 +0,0 @@ | ||||||
| /*  arminit.c -- ARMulator initialization:  ARM6 Instruction Emulator.
 |  | ||||||
|     Copyright (C) 1994 Advanced RISC Machines Ltd. |  | ||||||
| 
 |  | ||||||
|     This program is free software; you can redistribute it and/or modify |  | ||||||
|     it under the terms of the GNU General Public License as published by |  | ||||||
|     the Free Software Foundation; either version 2 of the License, or |  | ||||||
|     (at your option) any later version. |  | ||||||
| 
 |  | ||||||
|     This program is distributed in the hope that it will be useful, |  | ||||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|     GNU General Public License for more details. |  | ||||||
| 
 |  | ||||||
|     You should have received a copy of the GNU General Public License |  | ||||||
|     along with this program; if not, write to the Free Software |  | ||||||
|     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |  | ||||||
| 
 |  | ||||||
| #include <cstring> |  | ||||||
| #include "core/arm/skyeye_common/armstate.h" |  | ||||||
| #include "core/arm/skyeye_common/vfp/vfp.h" |  | ||||||
| 
 |  | ||||||
| // Resets certain MPCore CP15 values to their ARM-defined reset values.
 |  | ||||||
| static void ResetMPCoreCP15Registers(ARMul_State* cpu) |  | ||||||
| { |  | ||||||
|     // c0
 |  | ||||||
|     cpu->CP15[CP15_MAIN_ID]  = 0x410FB024; |  | ||||||
|     cpu->CP15[CP15_TLB_TYPE] = 0x00000800; |  | ||||||
|     cpu->CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; |  | ||||||
|     cpu->CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; |  | ||||||
|     cpu->CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; |  | ||||||
|     cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; |  | ||||||
|     cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; |  | ||||||
|     cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; |  | ||||||
|     cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_ISA_FEATURE_0] = 0x00100011; |  | ||||||
|     cpu->CP15[CP15_ISA_FEATURE_1] = 0x12002111; |  | ||||||
|     cpu->CP15[CP15_ISA_FEATURE_2] = 0x11221011; |  | ||||||
|     cpu->CP15[CP15_ISA_FEATURE_3] = 0x01102131; |  | ||||||
|     cpu->CP15[CP15_ISA_FEATURE_4] = 0x00000141; |  | ||||||
| 
 |  | ||||||
|     // c1
 |  | ||||||
|     cpu->CP15[CP15_CONTROL] = 0x00054078; |  | ||||||
|     cpu->CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; |  | ||||||
|     cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     // c2
 |  | ||||||
|     cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     // c3
 |  | ||||||
|     cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     // c7
 |  | ||||||
|     cpu->CP15[CP15_PHYS_ADDRESS] = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     // c9
 |  | ||||||
|     cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; |  | ||||||
| 
 |  | ||||||
|     // c10
 |  | ||||||
|     cpu->CP15[CP15_TLB_LOCKDOWN] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; |  | ||||||
|     cpu->CP15[CP15_NORMAL_REGION_REMAP]  = 0x44E048E0; |  | ||||||
| 
 |  | ||||||
|     // c13
 |  | ||||||
|     cpu->CP15[CP15_PID] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_CONTEXT_ID]  = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_THREAD_UPRW] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_THREAD_URO]  = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_THREAD_PRW]  = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     // c15
 |  | ||||||
|     cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL]    = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]    = 0x00000000; |  | ||||||
|     cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Performs a reset
 |  | ||||||
| void ARMul_Reset(ARMul_State* state) |  | ||||||
| { |  | ||||||
|     VFPInit(state); |  | ||||||
| 
 |  | ||||||
|     state->Reg[15] = 0; |  | ||||||
|     state->Cpsr = INTBITS | SVC32MODE; |  | ||||||
|     state->Mode = SVC32MODE; |  | ||||||
|     state->Bank = SVCBANK; |  | ||||||
| 
 |  | ||||||
|     ResetMPCoreCP15Registers(state); |  | ||||||
| 
 |  | ||||||
|     state->NresetSig = HIGH; |  | ||||||
|     state->NfiqSig = HIGH; |  | ||||||
|     state->NirqSig = HIGH; |  | ||||||
|     state->NtransSig = (state->Mode & 3) ? HIGH : LOW; |  | ||||||
|     state->abortSig = LOW; |  | ||||||
| 
 |  | ||||||
|     state->NumInstrs = 0; |  | ||||||
|     state->Emulate = RUN; |  | ||||||
| } |  | ||||||
|  | @ -1,104 +0,0 @@ | ||||||
| /*
 |  | ||||||
|     armmmu.c - Memory Management Unit emulation. |  | ||||||
|     ARMulator extensions for the ARM7100 family. |  | ||||||
|     Copyright (C) 1999  Ben Williamson |  | ||||||
| 
 |  | ||||||
|     This program is free software; you can redistribute it and/or modify |  | ||||||
|     it under the terms of the GNU General Public License as published by |  | ||||||
|     the Free Software Foundation; either version 2 of the License, or |  | ||||||
|     (at your option) any later version. |  | ||||||
| 
 |  | ||||||
|     This program is distributed in the hope that it will be useful, |  | ||||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|     GNU General Public License for more details. |  | ||||||
| 
 |  | ||||||
|     You should have received a copy of the GNU General Public License |  | ||||||
|     along with this program; if not, write to the Free Software |  | ||||||
|     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "common/swap.h" |  | ||||||
| 
 |  | ||||||
| #include "core/memory.h" |  | ||||||
| #include "core/arm/skyeye_common/armstate.h" |  | ||||||
| #include "core/arm/skyeye_common/armsupp.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, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // 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); |  | ||||||
| } |  | ||||||
							
								
								
									
										657
									
								
								src/core/arm/skyeye_common/armstate.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										657
									
								
								src/core/arm/skyeye_common/armstate.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,657 @@ | ||||||
|  | // Copyright 2015 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/swap.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "core/mem_map.h" | ||||||
|  | #include "core/memory.h" | ||||||
|  | #include "core/arm/skyeye_common/armstate.h" | ||||||
|  | #include "core/arm/skyeye_common/vfp/vfp.h" | ||||||
|  | 
 | ||||||
|  | ARMul_State::ARMul_State(PrivilegeMode initial_mode) | ||||||
|  | { | ||||||
|  |     Reset(); | ||||||
|  |     ChangePrivilegeMode(initial_mode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ARMul_State::ChangePrivilegeMode(u32 new_mode) | ||||||
|  | { | ||||||
|  |     if (Mode == new_mode) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     if (new_mode != USERBANK) { | ||||||
|  |         switch (Mode) { | ||||||
|  |         case SYSTEM32MODE: // Shares registers with user mode
 | ||||||
|  |         case USER32MODE: | ||||||
|  |             Reg_usr[0] = Reg[13]; | ||||||
|  |             Reg_usr[1] = Reg[14]; | ||||||
|  |             break; | ||||||
|  |         case IRQ32MODE: | ||||||
|  |             Reg_irq[0] = Reg[13]; | ||||||
|  |             Reg_irq[1] = Reg[14]; | ||||||
|  |             Spsr[IRQBANK] = Spsr_copy; | ||||||
|  |             break; | ||||||
|  |         case SVC32MODE: | ||||||
|  |             Reg_svc[0] = Reg[13]; | ||||||
|  |             Reg_svc[1] = Reg[14]; | ||||||
|  |             Spsr[SVCBANK] = Spsr_copy; | ||||||
|  |             break; | ||||||
|  |         case ABORT32MODE: | ||||||
|  |             Reg_abort[0] = Reg[13]; | ||||||
|  |             Reg_abort[1] = Reg[14]; | ||||||
|  |             Spsr[ABORTBANK] = Spsr_copy; | ||||||
|  |             break; | ||||||
|  |         case UNDEF32MODE: | ||||||
|  |             Reg_undef[0] = Reg[13]; | ||||||
|  |             Reg_undef[1] = Reg[14]; | ||||||
|  |             Spsr[UNDEFBANK] = Spsr_copy; | ||||||
|  |             break; | ||||||
|  |         case FIQ32MODE: | ||||||
|  |             Reg_firq[0] = Reg[13]; | ||||||
|  |             Reg_firq[1] = Reg[14]; | ||||||
|  |             Spsr[FIQBANK] = Spsr_copy; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         switch (new_mode) { | ||||||
|  |         case USER32MODE: | ||||||
|  |             Reg[13] = Reg_usr[0]; | ||||||
|  |             Reg[14] = Reg_usr[1]; | ||||||
|  |             Bank = USERBANK; | ||||||
|  |             break; | ||||||
|  |         case IRQ32MODE: | ||||||
|  |             Reg[13] = Reg_irq[0]; | ||||||
|  |             Reg[14] = Reg_irq[1]; | ||||||
|  |             Spsr_copy = Spsr[IRQBANK]; | ||||||
|  |             Bank = IRQBANK; | ||||||
|  |             break; | ||||||
|  |         case SVC32MODE: | ||||||
|  |             Reg[13] = Reg_svc[0]; | ||||||
|  |             Reg[14] = Reg_svc[1]; | ||||||
|  |             Spsr_copy = Spsr[SVCBANK]; | ||||||
|  |             Bank = SVCBANK; | ||||||
|  |             break; | ||||||
|  |         case ABORT32MODE: | ||||||
|  |             Reg[13] = Reg_abort[0]; | ||||||
|  |             Reg[14] = Reg_abort[1]; | ||||||
|  |             Spsr_copy = Spsr[ABORTBANK]; | ||||||
|  |             Bank = ABORTBANK; | ||||||
|  |             break; | ||||||
|  |         case UNDEF32MODE: | ||||||
|  |             Reg[13] = Reg_undef[0]; | ||||||
|  |             Reg[14] = Reg_undef[1]; | ||||||
|  |             Spsr_copy = Spsr[UNDEFBANK]; | ||||||
|  |             Bank = UNDEFBANK; | ||||||
|  |             break; | ||||||
|  |         case FIQ32MODE: | ||||||
|  |             Reg[13] = Reg_firq[0]; | ||||||
|  |             Reg[14] = Reg_firq[1]; | ||||||
|  |             Spsr_copy = Spsr[FIQBANK]; | ||||||
|  |             Bank = FIQBANK; | ||||||
|  |             break; | ||||||
|  |         case SYSTEM32MODE: // Shares registers with user mode.
 | ||||||
|  |             Reg[13] = Reg_usr[0]; | ||||||
|  |             Reg[14] = Reg_usr[1]; | ||||||
|  |             Bank = SYSTEMBANK; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Set the mode bits in the APSR
 | ||||||
|  |         Cpsr = (Cpsr & ~Mode) | new_mode; | ||||||
|  |         Mode = new_mode; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Performs a reset
 | ||||||
|  | void ARMul_State::Reset() | ||||||
|  | { | ||||||
|  |     VFPInit(this); | ||||||
|  | 
 | ||||||
|  |     // Set stack pointer to the top of the stack
 | ||||||
|  |     Reg[13] = 0x10000000; | ||||||
|  |     Reg[15] = 0; | ||||||
|  | 
 | ||||||
|  |     Cpsr = INTBITS | SVC32MODE; | ||||||
|  |     Mode = SVC32MODE; | ||||||
|  |     Bank = SVCBANK; | ||||||
|  | 
 | ||||||
|  |     ResetMPCoreCP15Registers(); | ||||||
|  | 
 | ||||||
|  |     NresetSig = HIGH; | ||||||
|  |     NfiqSig = HIGH; | ||||||
|  |     NirqSig = HIGH; | ||||||
|  |     NtransSig = (Mode & 3) ? HIGH : LOW; | ||||||
|  |     abortSig = LOW; | ||||||
|  | 
 | ||||||
|  |     NumInstrs = 0; | ||||||
|  |     Emulate = RUN; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Resets certain MPCore CP15 values to their ARM-defined reset values.
 | ||||||
|  | void ARMul_State::ResetMPCoreCP15Registers() | ||||||
|  | { | ||||||
|  |     // c0
 | ||||||
|  |     CP15[CP15_MAIN_ID] = 0x410FB024; | ||||||
|  |     CP15[CP15_TLB_TYPE] = 0x00000800; | ||||||
|  |     CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; | ||||||
|  |     CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; | ||||||
|  |     CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; | ||||||
|  |     CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; | ||||||
|  |     CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; | ||||||
|  |     CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; | ||||||
|  |     CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; | ||||||
|  |     CP15[CP15_ISA_FEATURE_0] = 0x00100011; | ||||||
|  |     CP15[CP15_ISA_FEATURE_1] = 0x12002111; | ||||||
|  |     CP15[CP15_ISA_FEATURE_2] = 0x11221011; | ||||||
|  |     CP15[CP15_ISA_FEATURE_3] = 0x01102131; | ||||||
|  |     CP15[CP15_ISA_FEATURE_4] = 0x00000141; | ||||||
|  | 
 | ||||||
|  |     // c1
 | ||||||
|  |     CP15[CP15_CONTROL] = 0x00054078; | ||||||
|  |     CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; | ||||||
|  |     CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; | ||||||
|  | 
 | ||||||
|  |     // c2
 | ||||||
|  |     CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; | ||||||
|  |     CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; | ||||||
|  |     CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; | ||||||
|  | 
 | ||||||
|  |     // c3
 | ||||||
|  |     CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; | ||||||
|  | 
 | ||||||
|  |     // c7
 | ||||||
|  |     CP15[CP15_PHYS_ADDRESS] = 0x00000000; | ||||||
|  | 
 | ||||||
|  |     // c9
 | ||||||
|  |     CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; | ||||||
|  | 
 | ||||||
|  |     // c10
 | ||||||
|  |     CP15[CP15_TLB_LOCKDOWN] = 0x00000000; | ||||||
|  |     CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; | ||||||
|  |     CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; | ||||||
|  | 
 | ||||||
|  |     // c13
 | ||||||
|  |     CP15[CP15_PID] = 0x00000000; | ||||||
|  |     CP15[CP15_CONTEXT_ID] = 0x00000000; | ||||||
|  |     CP15[CP15_THREAD_UPRW] = 0x00000000; | ||||||
|  |     CP15[CP15_THREAD_URO] = 0x00000000; | ||||||
|  |     CP15[CP15_THREAD_PRW] = 0x00000000; | ||||||
|  | 
 | ||||||
|  |     // c15
 | ||||||
|  |     CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; | ||||||
|  |     CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; | ||||||
|  |     CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; | ||||||
|  |     CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; | ||||||
|  |     CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u16 ARMul_State::ReadMemory16(u32 address) const | ||||||
|  | { | ||||||
|  |     u16 data = Memory::Read16(address); | ||||||
|  | 
 | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap16(data); | ||||||
|  | 
 | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u32 ARMul_State::ReadMemory32(u32 address) const | ||||||
|  | { | ||||||
|  |     u32 data = Memory::Read32(address); | ||||||
|  | 
 | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap32(data); | ||||||
|  | 
 | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u64 ARMul_State::ReadMemory64(u32 address) const | ||||||
|  | { | ||||||
|  |     u64 data = Memory::Read64(address); | ||||||
|  | 
 | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap64(data); | ||||||
|  | 
 | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ARMul_State::WriteMemory16(u32 address, u16 data) | ||||||
|  | { | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap16(data); | ||||||
|  | 
 | ||||||
|  |     Memory::Write16(address, data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ARMul_State::WriteMemory32(u32 address, u32 data) | ||||||
|  | { | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap32(data); | ||||||
|  | 
 | ||||||
|  |     Memory::Write32(address, data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ARMul_State::WriteMemory64(u32 address, u64 data) | ||||||
|  | { | ||||||
|  |     if (InBigEndianMode()) | ||||||
|  |         data = Common::swap64(data); | ||||||
|  | 
 | ||||||
|  |     Memory::Write64(address, data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Reads from the CP15 registers. Used with implementation of the MRC instruction.
 | ||||||
|  | // Note that since the 3DS does not have the hypervisor extensions, these registers
 | ||||||
|  | // are not implemented.
 | ||||||
|  | u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const | ||||||
|  | { | ||||||
|  |     // Unprivileged registers
 | ||||||
|  |     if (crn == 13 && opcode_1 == 0 && crm == 0) | ||||||
|  |     { | ||||||
|  |         if (opcode_2 == 2) | ||||||
|  |             return CP15[CP15_THREAD_UPRW]; | ||||||
|  | 
 | ||||||
|  |         if (opcode_2 == 3) | ||||||
|  |             return CP15[CP15_THREAD_URO]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (InAPrivilegedMode()) | ||||||
|  |     { | ||||||
|  |         if (crn == 0 && opcode_1 == 0) | ||||||
|  |         { | ||||||
|  |             if (crm == 0) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     return CP15[CP15_MAIN_ID]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 1) | ||||||
|  |                     return CP15[CP15_CACHE_TYPE]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 3) | ||||||
|  |                     return CP15[CP15_TLB_TYPE]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 5) | ||||||
|  |                     return CP15[CP15_CPU_ID]; | ||||||
|  |             } | ||||||
|  |             else if (crm == 1) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     return CP15[CP15_PROCESSOR_FEATURE_0]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 1) | ||||||
|  |                     return CP15[CP15_PROCESSOR_FEATURE_1]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 2) | ||||||
|  |                     return CP15[CP15_DEBUG_FEATURE_0]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 4) | ||||||
|  |                     return CP15[CP15_MEMORY_MODEL_FEATURE_0]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 5) | ||||||
|  |                     return CP15[CP15_MEMORY_MODEL_FEATURE_1]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 6) | ||||||
|  |                     return CP15[CP15_MEMORY_MODEL_FEATURE_2]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 7) | ||||||
|  |                     return CP15[CP15_MEMORY_MODEL_FEATURE_3]; | ||||||
|  |             } | ||||||
|  |             else if (crm == 2) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     return CP15[CP15_ISA_FEATURE_0]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 1) | ||||||
|  |                     return CP15[CP15_ISA_FEATURE_1]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 2) | ||||||
|  |                     return CP15[CP15_ISA_FEATURE_2]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 3) | ||||||
|  |                     return CP15[CP15_ISA_FEATURE_3]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 4) | ||||||
|  |                     return CP15[CP15_ISA_FEATURE_4]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 1 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_CONTROL]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 1) | ||||||
|  |                 return CP15[CP15_AUXILIARY_CONTROL]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 2) | ||||||
|  |                 return CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 2 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_TRANSLATION_BASE_TABLE_0]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 1) | ||||||
|  |                 return CP15[CP15_TRANSLATION_BASE_TABLE_1]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 2) | ||||||
|  |                 return CP15[CP15_TRANSLATION_BASE_CONTROL]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||||||
|  |             return CP15[CP15_DOMAIN_ACCESS_CONTROL]; | ||||||
|  | 
 | ||||||
|  |         if (crn == 5 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_FAULT_STATUS]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 1) | ||||||
|  |                 return CP15[CP15_INSTR_FAULT_STATUS]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 6 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_FAULT_ADDRESS]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 1) | ||||||
|  |                 return CP15[CP15_WFAR]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) | ||||||
|  |             return CP15[CP15_PHYS_ADDRESS]; | ||||||
|  | 
 | ||||||
|  |         if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||||||
|  |             return CP15[CP15_DATA_CACHE_LOCKDOWN]; | ||||||
|  | 
 | ||||||
|  |         if (crn == 10 && opcode_1 == 0) | ||||||
|  |         { | ||||||
|  |             if (crm == 0 && opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_TLB_LOCKDOWN]; | ||||||
|  | 
 | ||||||
|  |             if (crm == 2) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     return CP15[CP15_PRIMARY_REGION_REMAP]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 1) | ||||||
|  |                     return CP15[CP15_NORMAL_REGION_REMAP]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 13 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_PID]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 1) | ||||||
|  |                 return CP15[CP15_CONTEXT_ID]; | ||||||
|  | 
 | ||||||
|  |             if (opcode_2 == 4) | ||||||
|  |                 return CP15[CP15_THREAD_PRW]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (crn == 15) | ||||||
|  |         { | ||||||
|  |             if (opcode_1 == 0 && crm == 12) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     return CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 1) | ||||||
|  |                     return CP15[CP15_CYCLE_COUNTER]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 2) | ||||||
|  |                     return CP15[CP15_COUNT_0]; | ||||||
|  | 
 | ||||||
|  |                 if (opcode_2 == 3) | ||||||
|  |                     return CP15[CP15_COUNT_1]; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (opcode_1 == 5 && opcode_2 == 2) | ||||||
|  |             { | ||||||
|  |                 if (crm == 5) | ||||||
|  |                     return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; | ||||||
|  | 
 | ||||||
|  |                 if (crm == 6) | ||||||
|  |                     return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; | ||||||
|  | 
 | ||||||
|  |                 if (crm == 7) | ||||||
|  |                     return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||||||
|  |                 return CP15[CP15_TLB_DEBUG_CONTROL]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Write to the CP15 registers. Used with implementation of the MCR instruction.
 | ||||||
|  | // Note that since the 3DS does not have the hypervisor extensions, these registers
 | ||||||
|  | // are not implemented.
 | ||||||
|  | void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) | ||||||
|  | { | ||||||
|  |     if (InAPrivilegedMode()) | ||||||
|  |     { | ||||||
|  |         if (crn == 1 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 CP15[CP15_CONTROL] = value; | ||||||
|  |             else if (opcode_2 == 1) | ||||||
|  |                 CP15[CP15_AUXILIARY_CONTROL] = value; | ||||||
|  |             else if (opcode_2 == 2) | ||||||
|  |                 CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 2 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; | ||||||
|  |             else if (opcode_2 == 1) | ||||||
|  |                 CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; | ||||||
|  |             else if (opcode_2 == 2) | ||||||
|  |                 CP15[CP15_TRANSLATION_BASE_CONTROL] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||||||
|  |         { | ||||||
|  |             CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 5 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 CP15[CP15_FAULT_STATUS] = value; | ||||||
|  |             else if (opcode_2 == 1) | ||||||
|  |                 CP15[CP15_INSTR_FAULT_STATUS] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 6 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 CP15[CP15_FAULT_ADDRESS] = value; | ||||||
|  |             else if (opcode_2 == 1) | ||||||
|  |                 CP15[CP15_WFAR] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 7 && opcode_1 == 0) | ||||||
|  |         { | ||||||
|  |             if (crm == 0 && opcode_2 == 4) | ||||||
|  |             { | ||||||
|  |                 CP15[CP15_WAIT_FOR_INTERRUPT] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 4 && opcode_2 == 0) | ||||||
|  |             { | ||||||
|  |                 // NOTE: Not entirely accurate. This should do permission checks.
 | ||||||
|  |                 CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); | ||||||
|  |             } | ||||||
|  |             else if (crm == 5) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_INVALIDATE_INSTR_CACHE] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; | ||||||
|  |                 else if (opcode_2 == 6) | ||||||
|  |                     CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; | ||||||
|  |                 else if (opcode_2 == 7) | ||||||
|  |                     CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 6) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_INVALIDATE_DATA_CACHE] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 7 && opcode_2 == 0) | ||||||
|  |             { | ||||||
|  |                 CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 10) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_CLEAN_DATA_CACHE] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 14) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else if (crn == 8 && opcode_1 == 0) | ||||||
|  |         { | ||||||
|  |             if (crm == 5) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_INVALIDATE_ITLB] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; | ||||||
|  |                 else if (opcode_2 == 3) | ||||||
|  |                     CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 6) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_INVALIDATE_DTLB] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; | ||||||
|  |                 else if (opcode_2 == 3) | ||||||
|  |                     CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 7) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_INVALIDATE_UTLB] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; | ||||||
|  |                 else if (opcode_2 == 3) | ||||||
|  |                     CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||||||
|  |         { | ||||||
|  |             CP15[CP15_DATA_CACHE_LOCKDOWN] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 10 && opcode_1 == 0) | ||||||
|  |         { | ||||||
|  |             if (crm == 0 && opcode_2 == 0) | ||||||
|  |             { | ||||||
|  |                 CP15[CP15_TLB_LOCKDOWN] = value; | ||||||
|  |             } | ||||||
|  |             else if (crm == 2) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_PRIMARY_REGION_REMAP] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_NORMAL_REGION_REMAP] = value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else if (crn == 13 && opcode_1 == 0 && crm == 0) | ||||||
|  |         { | ||||||
|  |             if (opcode_2 == 0) | ||||||
|  |                 CP15[CP15_PID] = value; | ||||||
|  |             else if (opcode_2 == 1) | ||||||
|  |                 CP15[CP15_CONTEXT_ID] = value; | ||||||
|  |             else if (opcode_2 == 3) | ||||||
|  |                 CP15[CP15_THREAD_URO] = value; | ||||||
|  |             else if (opcode_2 == 4) | ||||||
|  |                 CP15[CP15_THREAD_PRW] = value; | ||||||
|  |         } | ||||||
|  |         else if (crn == 15) | ||||||
|  |         { | ||||||
|  |             if (opcode_1 == 0 && crm == 12) | ||||||
|  |             { | ||||||
|  |                 if (opcode_2 == 0) | ||||||
|  |                     CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; | ||||||
|  |                 else if (opcode_2 == 1) | ||||||
|  |                     CP15[CP15_CYCLE_COUNTER] = value; | ||||||
|  |                 else if (opcode_2 == 2) | ||||||
|  |                     CP15[CP15_COUNT_0] = value; | ||||||
|  |                 else if (opcode_2 == 3) | ||||||
|  |                     CP15[CP15_COUNT_1] = value; | ||||||
|  |             } | ||||||
|  |             else if (opcode_1 == 5) | ||||||
|  |             { | ||||||
|  |                 if (crm == 4) | ||||||
|  |                 { | ||||||
|  |                     if (opcode_2 == 2) | ||||||
|  |                         CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||||||
|  |                     else if (opcode_2 == 4) | ||||||
|  |                         CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||||||
|  |                 } | ||||||
|  |                 else if (crm == 5 && opcode_2 == 2) | ||||||
|  |                 { | ||||||
|  |                     CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; | ||||||
|  |                 } | ||||||
|  |                 else if (crm == 6 && opcode_2 == 2) | ||||||
|  |                 { | ||||||
|  |                     CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; | ||||||
|  |                 } | ||||||
|  |                 else if (crm == 7 && opcode_2 == 2) | ||||||
|  |                 { | ||||||
|  |                     CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||||||
|  |             { | ||||||
|  |                 CP15[CP15_TLB_DEBUG_CONTROL] = value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Unprivileged registers
 | ||||||
|  |     if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) | ||||||
|  |     { | ||||||
|  |         CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; | ||||||
|  |     } | ||||||
|  |     else if (crn == 7 && opcode_1 == 0 && crm == 10) | ||||||
|  |     { | ||||||
|  |         if (opcode_2 == 4) | ||||||
|  |             CP15[CP15_DATA_SYNC_BARRIER] = value; | ||||||
|  |         else if (opcode_2 == 5) | ||||||
|  |             CP15[CP15_DATA_MEMORY_BARRIER] = value; | ||||||
|  |     } | ||||||
|  |     else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) | ||||||
|  |     { | ||||||
|  |         CP15[CP15_THREAD_UPRW] = value; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <array> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| 
 | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | @ -37,67 +38,30 @@ enum { | ||||||
|     INSTCACHE = 2, |     INSTCACHE = 2, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define VFP_REG_NUM 64 | // ARM privilege modes
 | ||||||
| struct ARMul_State | enum PrivilegeMode { | ||||||
| { |     USER32MODE   = 16, | ||||||
|     u32 Emulate;       // To start and stop emulation
 |     FIQ32MODE    = 17, | ||||||
| 
 |     IRQ32MODE    = 18, | ||||||
|     // Order of the following register should not be modified
 |     SVC32MODE    = 19, | ||||||
|     u32 Reg[16];            // The current register file
 |     ABORT32MODE  = 23, | ||||||
|     u32 Cpsr;               // The current PSR
 |     UNDEF32MODE  = 27, | ||||||
|     u32 Spsr_copy; |     SYSTEM32MODE = 31 | ||||||
|     u32 phys_pc; |  | ||||||
|     u32 Reg_usr[2]; |  | ||||||
|     u32 Reg_svc[2];         // R13_SVC R14_SVC
 |  | ||||||
|     u32 Reg_abort[2];       // R13_ABORT R14_ABORT
 |  | ||||||
|     u32 Reg_undef[2];       // R13 UNDEF R14 UNDEF
 |  | ||||||
|     u32 Reg_irq[2];         // R13_IRQ R14_IRQ
 |  | ||||||
|     u32 Reg_firq[7];        // R8---R14 FIRQ
 |  | ||||||
|     u32 Spsr[7];            // The exception psr's
 |  | ||||||
|     u32 Mode;               // The current mode
 |  | ||||||
|     u32 Bank;               // The current register bank
 |  | ||||||
|     u32 exclusive_tag;      // The address for which the local monitor is in exclusive access mode
 |  | ||||||
|     u32 exclusive_state; |  | ||||||
|     u32 exclusive_result; |  | ||||||
|     u32 CP15[CP15_REGISTER_COUNT]; |  | ||||||
| 
 |  | ||||||
|     // FPSID, FPSCR, and FPEXC
 |  | ||||||
|     u32 VFP[VFP_SYSTEM_REGISTER_COUNT]; |  | ||||||
|     // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
 |  | ||||||
|     // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
 |  | ||||||
|     // and only 32 singleword registers are accessible (S0-S31).
 |  | ||||||
|     u32 ExtReg[VFP_REG_NUM]; |  | ||||||
|     /* ---- End of the ordered registers ---- */ |  | ||||||
| 
 |  | ||||||
|     u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
 |  | ||||||
|     unsigned int shifter_carry_out; |  | ||||||
| 
 |  | ||||||
|     // Add armv6 flags dyf:2010-08-09
 |  | ||||||
|     u32 GEFlag, EFlag, AFlag, QFlag; |  | ||||||
| 
 |  | ||||||
|     u32 TFlag; // Thumb state
 |  | ||||||
| 
 |  | ||||||
|     unsigned long long NumInstrs; // The number of instructions executed
 |  | ||||||
|     unsigned NumInstrsToExecute; |  | ||||||
| 
 |  | ||||||
|     unsigned NresetSig; // Reset the processor
 |  | ||||||
|     unsigned NfiqSig; |  | ||||||
|     unsigned NirqSig; |  | ||||||
| 
 |  | ||||||
|     unsigned abortSig; |  | ||||||
|     unsigned NtransSig; |  | ||||||
|     unsigned bigendSig; |  | ||||||
|     unsigned syscallSig; |  | ||||||
| 
 |  | ||||||
|     // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
 |  | ||||||
|     // process for our purposes), not per ARMul_State (which tracks CPU core state).
 |  | ||||||
|     std::unordered_map<u32, int> instruction_cache; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /***************************************************************************\
 | // ARM privilege mode register banks
 | ||||||
| *                      The hardware vector addresses                        * | enum { | ||||||
| \***************************************************************************/ |     USERBANK   = 0, | ||||||
|  |     FIQBANK    = 1, | ||||||
|  |     IRQBANK    = 2, | ||||||
|  |     SVCBANK    = 3, | ||||||
|  |     ABORTBANK  = 4, | ||||||
|  |     UNDEFBANK  = 5, | ||||||
|  |     DUMMYBANK  = 6, | ||||||
|  |     SYSTEMBANK = 7 | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
|  | // Hardware vector addresses
 | ||||||
| enum { | enum { | ||||||
|     ARMResetV          = 0, |     ARMResetV          = 0, | ||||||
|     ARMUndefinedInstrV = 4, |     ARMUndefinedInstrV = 4, | ||||||
|  | @ -119,40 +83,7 @@ enum { | ||||||
|     ARMul_FIQV            = ARMFIQV |     ARMul_FIQV            = ARMFIQV | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /***************************************************************************\
 | // Coprocessor status values
 | ||||||
| *                          Mode and Bank Constants                          * |  | ||||||
| \***************************************************************************/ |  | ||||||
| 
 |  | ||||||
| enum PrivilegeMode { |  | ||||||
|     USER32MODE   = 16, |  | ||||||
|     FIQ32MODE    = 17, |  | ||||||
|     IRQ32MODE    = 18, |  | ||||||
|     SVC32MODE    = 19, |  | ||||||
|     ABORT32MODE  = 23, |  | ||||||
|     UNDEF32MODE  = 27, |  | ||||||
|     SYSTEM32MODE = 31 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     USERBANK   = 0, |  | ||||||
|     FIQBANK    = 1, |  | ||||||
|     IRQBANK    = 2, |  | ||||||
|     SVCBANK    = 3, |  | ||||||
|     ABORTBANK  = 4, |  | ||||||
|     UNDEFBANK  = 5, |  | ||||||
|     DUMMYBANK  = 6, |  | ||||||
|     SYSTEMBANK = 7 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /***************************************************************************\
 |  | ||||||
| *                  Definitions of things in the emulator                     * |  | ||||||
| \***************************************************************************/ |  | ||||||
| void ARMul_Reset(ARMul_State* state); |  | ||||||
| 
 |  | ||||||
| /***************************************************************************\
 |  | ||||||
| *            Definitions of things in the co-processor interface             * |  | ||||||
| \***************************************************************************/ |  | ||||||
| 
 |  | ||||||
| enum { | enum { | ||||||
|     ARMul_FIRST     = 0, |     ARMul_FIRST     = 0, | ||||||
|     ARMul_TRANSFER  = 1, |     ARMul_TRANSFER  = 1, | ||||||
|  | @ -164,10 +95,7 @@ enum { | ||||||
|     ARMul_INC       = 3 |     ARMul_INC       = 3 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /***************************************************************************\
 | // Instruction condition codes
 | ||||||
| *               Definitions of things in the host environment                * |  | ||||||
| \***************************************************************************/ |  | ||||||
| 
 |  | ||||||
| enum ConditionCode { | enum ConditionCode { | ||||||
|     EQ = 0, |     EQ = 0, | ||||||
|     NE = 1, |     NE = 1, | ||||||
|  | @ -213,3 +141,93 @@ enum { | ||||||
|     ONCE       = 2, // Execute just one iteration
 |     ONCE       = 2, // Execute just one iteration
 | ||||||
|     RUN        = 3  // Continuous execution
 |     RUN        = 3  // Continuous execution
 | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | struct ARMul_State final | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     explicit ARMul_State(PrivilegeMode initial_mode); | ||||||
|  | 
 | ||||||
|  |     void ChangePrivilegeMode(u32 new_mode); | ||||||
|  |     void Reset(); | ||||||
|  | 
 | ||||||
|  |     // Reads/writes data in big/little endian format based on the
 | ||||||
|  |     // state of the E (endian) bit in the APSR.
 | ||||||
|  |     u16 ReadMemory16(u32 address) const; | ||||||
|  |     u32 ReadMemory32(u32 address) const; | ||||||
|  |     u64 ReadMemory64(u32 address) const; | ||||||
|  |     void WriteMemory16(u32 address, u16 data); | ||||||
|  |     void WriteMemory32(u32 address, u32 data); | ||||||
|  |     void WriteMemory64(u32 address, u64 data); | ||||||
|  | 
 | ||||||
|  |     u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; | ||||||
|  |     void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | ||||||
|  | 
 | ||||||
|  |     // Whether or not the given CPU is in big endian mode (E bit is set)
 | ||||||
|  |     bool InBigEndianMode() const { | ||||||
|  |         return (Cpsr & (1 << 9)) != 0; | ||||||
|  |     } | ||||||
|  |     // Whether or not the given CPU is in a mode other than user mode.
 | ||||||
|  |     bool InAPrivilegedMode() const { | ||||||
|  |         return (Mode != USER32MODE); | ||||||
|  |     } | ||||||
|  |     // Note that for the 3DS, a Thumb instruction will only ever be
 | ||||||
|  |     // two bytes in size. Thus we don't need to worry about ThumbEE
 | ||||||
|  |     // or Thumb-2 where instructions can be 4 bytes in length.
 | ||||||
|  |     u32 GetInstructionSize() const { | ||||||
|  |         return TFlag ? 2 : 4; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::array<u32, 16> Reg;      // The current register file
 | ||||||
|  |     std::array<u32, 2> Reg_usr; | ||||||
|  |     std::array<u32, 2> Reg_svc;   // R13_SVC R14_SVC
 | ||||||
|  |     std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT
 | ||||||
|  |     std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF
 | ||||||
|  |     std::array<u32, 2> Reg_irq;   // R13_IRQ R14_IRQ
 | ||||||
|  |     std::array<u32, 7> Reg_firq;  // R8---R14 FIRQ
 | ||||||
|  |     std::array<u32, 7> Spsr;      // The exception psr's
 | ||||||
|  |     std::array<u32, CP15_REGISTER_COUNT> CP15; | ||||||
|  | 
 | ||||||
|  |     // FPSID, FPSCR, and FPEXC
 | ||||||
|  |     std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP; | ||||||
|  | 
 | ||||||
|  |     // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
 | ||||||
|  |     // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
 | ||||||
|  |     // and only 32 singleword registers are accessible (S0-S31).
 | ||||||
|  |     std::array<u32, 64> ExtReg; | ||||||
|  | 
 | ||||||
|  |     u32 Emulate; // To start and stop emulation
 | ||||||
|  |     u32 Cpsr;    // The current PSR
 | ||||||
|  |     u32 Spsr_copy; | ||||||
|  |     u32 phys_pc; | ||||||
|  | 
 | ||||||
|  |     u32 Mode;          // The current mode
 | ||||||
|  |     u32 Bank;          // The current register bank
 | ||||||
|  |     u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
 | ||||||
|  |     u32 exclusive_state; | ||||||
|  |     u32 exclusive_result; | ||||||
|  | 
 | ||||||
|  |     u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
 | ||||||
|  |     unsigned int shifter_carry_out; | ||||||
|  | 
 | ||||||
|  |     u32 TFlag; // Thumb state
 | ||||||
|  | 
 | ||||||
|  |     unsigned long long NumInstrs; // The number of instructions executed
 | ||||||
|  |     unsigned NumInstrsToExecute; | ||||||
|  | 
 | ||||||
|  |     unsigned NresetSig; // Reset the processor
 | ||||||
|  |     unsigned NfiqSig; | ||||||
|  |     unsigned NirqSig; | ||||||
|  | 
 | ||||||
|  |     unsigned abortSig; | ||||||
|  |     unsigned NtransSig; | ||||||
|  |     unsigned bigendSig; | ||||||
|  |     unsigned syscallSig; | ||||||
|  | 
 | ||||||
|  |     // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
 | ||||||
|  |     // process for our purposes), not per ARMul_State (which tracks CPU core state).
 | ||||||
|  |     std::unordered_map<u32, int> instruction_cache; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void ResetMPCoreCP15Registers(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @ -206,433 +206,3 @@ u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||||||
|     *saturation_occurred = false; |     *saturation_occurred = false; | ||||||
|     return (u32)value; |     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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Whether or not the given CPU is in a mode other than user mode.
 |  | ||||||
| bool InAPrivilegedMode(ARMul_State* cpu) |  | ||||||
| { |  | ||||||
|     return (cpu->Mode != USER32MODE); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Reads from the CP15 registers. Used with implementation of the MRC instruction.
 |  | ||||||
| // Note that since the 3DS does not have the hypervisor extensions, these registers
 |  | ||||||
| // are not implemented.
 |  | ||||||
| u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) |  | ||||||
| { |  | ||||||
|     // Unprivileged registers
 |  | ||||||
|     if (crn == 13 && opcode_1 == 0 && crm == 0) |  | ||||||
|     { |  | ||||||
|         if (opcode_2 == 2) |  | ||||||
|             return cpu->CP15[CP15_THREAD_UPRW]; |  | ||||||
| 
 |  | ||||||
|         if (opcode_2 == 3) |  | ||||||
|             return cpu->CP15[CP15_THREAD_URO]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (InAPrivilegedMode(cpu)) |  | ||||||
|     { |  | ||||||
|         if (crn == 0 && opcode_1 == 0) |  | ||||||
|         { |  | ||||||
|             if (crm == 0) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     return cpu->CP15[CP15_MAIN_ID]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 1) |  | ||||||
|                     return cpu->CP15[CP15_CACHE_TYPE]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 3) |  | ||||||
|                     return cpu->CP15[CP15_TLB_TYPE]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 5) |  | ||||||
|                     return cpu->CP15[CP15_CPU_ID]; |  | ||||||
|             } |  | ||||||
|             else if (crm == 1) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     return cpu->CP15[CP15_PROCESSOR_FEATURE_0]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 1) |  | ||||||
|                     return cpu->CP15[CP15_PROCESSOR_FEATURE_1]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 2) |  | ||||||
|                     return cpu->CP15[CP15_DEBUG_FEATURE_0]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 4) |  | ||||||
|                     return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 5) |  | ||||||
|                     return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 6) |  | ||||||
|                     return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 7) |  | ||||||
|                     return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3]; |  | ||||||
|             } |  | ||||||
|             else if (crm == 2) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     return cpu->CP15[CP15_ISA_FEATURE_0]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 1) |  | ||||||
|                     return cpu->CP15[CP15_ISA_FEATURE_1]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 2) |  | ||||||
|                     return cpu->CP15[CP15_ISA_FEATURE_2]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 3) |  | ||||||
|                     return cpu->CP15[CP15_ISA_FEATURE_3]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 4) |  | ||||||
|                     return cpu->CP15[CP15_ISA_FEATURE_4]; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 1 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_CONTROL]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 1) |  | ||||||
|                 return cpu->CP15[CP15_AUXILIARY_CONTROL]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 2) |  | ||||||
|                 return cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 2 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 1) |  | ||||||
|                 return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 2) |  | ||||||
|                 return cpu->CP15[CP15_TRANSLATION_BASE_CONTROL]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |  | ||||||
|             return cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL]; |  | ||||||
| 
 |  | ||||||
|         if (crn == 5 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_FAULT_STATUS]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 1) |  | ||||||
|                 return cpu->CP15[CP15_INSTR_FAULT_STATUS]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 6 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_FAULT_ADDRESS]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 1) |  | ||||||
|                 return cpu->CP15[CP15_WFAR]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) |  | ||||||
|             return cpu->CP15[CP15_PHYS_ADDRESS]; |  | ||||||
| 
 |  | ||||||
|         if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |  | ||||||
|             return cpu->CP15[CP15_DATA_CACHE_LOCKDOWN]; |  | ||||||
| 
 |  | ||||||
|         if (crn == 10 && opcode_1 == 0) |  | ||||||
|         { |  | ||||||
|             if (crm == 0 && opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_TLB_LOCKDOWN]; |  | ||||||
| 
 |  | ||||||
|             if (crm == 2) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     return cpu->CP15[CP15_PRIMARY_REGION_REMAP]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 1) |  | ||||||
|                     return cpu->CP15[CP15_NORMAL_REGION_REMAP]; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 13 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_PID]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 1) |  | ||||||
|                 return cpu->CP15[CP15_CONTEXT_ID]; |  | ||||||
| 
 |  | ||||||
|             if (opcode_2 == 4) |  | ||||||
|                 return cpu->CP15[CP15_THREAD_PRW]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (crn == 15) |  | ||||||
|         { |  | ||||||
|             if (opcode_1 == 0 && crm == 12) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     return cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 1) |  | ||||||
|                     return cpu->CP15[CP15_CYCLE_COUNTER]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 2) |  | ||||||
|                     return cpu->CP15[CP15_COUNT_0]; |  | ||||||
| 
 |  | ||||||
|                 if (opcode_2 == 3) |  | ||||||
|                     return cpu->CP15[CP15_COUNT_1]; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (opcode_1 == 5 && opcode_2 == 2) |  | ||||||
|             { |  | ||||||
|                 if (crm == 5) |  | ||||||
|                     return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; |  | ||||||
| 
 |  | ||||||
|                 if (crm == 6) |  | ||||||
|                     return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; |  | ||||||
| 
 |  | ||||||
|                 if (crm == 7) |  | ||||||
|                     return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) |  | ||||||
|                 return cpu->CP15[CP15_TLB_DEBUG_CONTROL]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Write to the CP15 registers. Used with implementation of the MCR instruction.
 |  | ||||||
| // Note that since the 3DS does not have the hypervisor extensions, these registers
 |  | ||||||
| // are not implemented.
 |  | ||||||
| void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) |  | ||||||
| { |  | ||||||
|     if (InAPrivilegedMode(cpu)) |  | ||||||
|     { |  | ||||||
|         if (crn == 1 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 cpu->CP15[CP15_CONTROL] = value; |  | ||||||
|             else if (opcode_2 == 1) |  | ||||||
|                 cpu->CP15[CP15_AUXILIARY_CONTROL] = value; |  | ||||||
|             else if (opcode_2 == 2) |  | ||||||
|                 cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 2 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; |  | ||||||
|             else if (opcode_2 == 1) |  | ||||||
|                 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; |  | ||||||
|             else if (opcode_2 == 2) |  | ||||||
|                 cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |  | ||||||
|         { |  | ||||||
|             cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 5 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 cpu->CP15[CP15_FAULT_STATUS] = value; |  | ||||||
|             else if (opcode_2 == 1) |  | ||||||
|                 cpu->CP15[CP15_INSTR_FAULT_STATUS] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 6 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 cpu->CP15[CP15_FAULT_ADDRESS] = value; |  | ||||||
|             else if (opcode_2 == 1) |  | ||||||
|                 cpu->CP15[CP15_WFAR] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 7 && opcode_1 == 0) |  | ||||||
|         { |  | ||||||
|             if (crm == 0 && opcode_2 == 4) |  | ||||||
|             { |  | ||||||
|                 cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 4 && opcode_2 == 0) |  | ||||||
|             { |  | ||||||
|                 // NOTE: Not entirely accurate. This should do permission checks.
 |  | ||||||
|                 cpu->CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); |  | ||||||
|             } |  | ||||||
|             else if (crm == 5) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_INSTR_CACHE] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; |  | ||||||
|                 else if (opcode_2 == 6) |  | ||||||
|                     cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; |  | ||||||
|                 else if (opcode_2 == 7) |  | ||||||
|                     cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 6) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DATA_CACHE] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 7 && opcode_2 == 0) |  | ||||||
|             { |  | ||||||
|                 cpu->CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 10) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_DATA_CACHE] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 14) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (crn == 8 && opcode_1 == 0) |  | ||||||
|         { |  | ||||||
|             LOG_WARNING(Core_ARM11, "TLB operations not fully implemented."); |  | ||||||
| 
 |  | ||||||
|             if (crm == 5) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_ITLB] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; |  | ||||||
|                 else if (opcode_2 == 3) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 6) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DTLB] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; |  | ||||||
|                 else if (opcode_2 == 3) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 7) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_UTLB] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; |  | ||||||
|                 else if (opcode_2 == 3) |  | ||||||
|                     cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) |  | ||||||
|         { |  | ||||||
|             cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 10 && opcode_1 == 0) |  | ||||||
|         { |  | ||||||
|             if (crm == 0 && opcode_2 == 0) |  | ||||||
|             { |  | ||||||
|                 cpu->CP15[CP15_TLB_LOCKDOWN] = value; |  | ||||||
|             } |  | ||||||
|             else if (crm == 2) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_PRIMARY_REGION_REMAP] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_NORMAL_REGION_REMAP] = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (crn == 13 && opcode_1 == 0 && crm == 0) |  | ||||||
|         { |  | ||||||
|             if (opcode_2 == 0) |  | ||||||
|                 cpu->CP15[CP15_PID] = value; |  | ||||||
|             else if (opcode_2 == 1) |  | ||||||
|                 cpu->CP15[CP15_CONTEXT_ID] = value; |  | ||||||
|             else if (opcode_2 == 3) |  | ||||||
|                 cpu->CP15[CP15_THREAD_URO] = value; |  | ||||||
|             else if (opcode_2 == 4) |  | ||||||
|                 cpu->CP15[CP15_THREAD_PRW] = value; |  | ||||||
|         } |  | ||||||
|         else if (crn == 15) |  | ||||||
|         { |  | ||||||
|             if (opcode_1 == 0 && crm == 12) |  | ||||||
|             { |  | ||||||
|                 if (opcode_2 == 0) |  | ||||||
|                     cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; |  | ||||||
|                 else if (opcode_2 == 1) |  | ||||||
|                     cpu->CP15[CP15_CYCLE_COUNTER] = value; |  | ||||||
|                 else if (opcode_2 == 2) |  | ||||||
|                     cpu->CP15[CP15_COUNT_0] = value; |  | ||||||
|                 else if (opcode_2 == 3) |  | ||||||
|                     cpu->CP15[CP15_COUNT_1] = value; |  | ||||||
|             } |  | ||||||
|             else if (opcode_1 == 5) |  | ||||||
|             { |  | ||||||
|                 if (crm == 4) |  | ||||||
|                 { |  | ||||||
|                     if (opcode_2 == 2) |  | ||||||
|                         cpu->CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; |  | ||||||
|                     else if (opcode_2 == 4) |  | ||||||
|                         cpu->CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; |  | ||||||
|                 } |  | ||||||
|                 else if (crm == 5 && opcode_2 == 2) |  | ||||||
|                 { |  | ||||||
|                     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; |  | ||||||
|                 } |  | ||||||
|                 else if (crm == 6 && opcode_2 == 2) |  | ||||||
|                 { |  | ||||||
|                     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; |  | ||||||
|                 } |  | ||||||
|                 else if (crm == 7 && opcode_2 == 2) |  | ||||||
|                 { |  | ||||||
|                     cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) |  | ||||||
|             { |  | ||||||
|                 cpu->CP15[CP15_TLB_DEBUG_CONTROL] = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Unprivileged registers
 |  | ||||||
|     if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) |  | ||||||
|     { |  | ||||||
|         cpu->CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; |  | ||||||
|     } |  | ||||||
|     else if (crn == 7 && opcode_1 == 0 && crm == 10) |  | ||||||
|     { |  | ||||||
|        if (opcode_2 == 4) |  | ||||||
|            cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; |  | ||||||
|        else if (opcode_2 == 5) |  | ||||||
|            cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
|     else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) |  | ||||||
|     { |  | ||||||
|         cpu->CP15[CP15_THREAD_UPRW] = value; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -6,8 +6,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| struct ARMul_State; |  | ||||||
| 
 |  | ||||||
| #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | ||||||
| #define BIT(s, n) ((s >> (n)) & 1) | #define BIT(s, n) ((s >> (n)) & 1) | ||||||
| 
 | 
 | ||||||
|  | @ -32,9 +30,3 @@ u16 ARMul_UnsignedSaturatedSub16(u16, u16); | ||||||
| u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | ||||||
| u32 ARMul_SignedSatQ(s32, u8, bool*); | u32 ARMul_SignedSatQ(s32, u8, bool*); | ||||||
| u32 ARMul_UnsignedSatQ(s32, u8, bool*); | u32 ARMul_UnsignedSatQ(s32, u8, bool*); | ||||||
| 
 |  | ||||||
| bool InBigEndianMode(ARMul_State*); |  | ||||||
| bool InAPrivilegedMode(ARMul_State*); |  | ||||||
| 
 |  | ||||||
| u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); |  | ||||||
| void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); |  | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ VMLA_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmla_inst)); |     INC_PC(sizeof(vmla_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -100,7 +100,7 @@ VMLS_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmls_inst)); |     INC_PC(sizeof(vmls_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -149,7 +149,7 @@ VNMLA_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vnmla_inst)); |     INC_PC(sizeof(vnmla_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -199,7 +199,7 @@ VNMLS_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vnmls_inst)); |     INC_PC(sizeof(vnmls_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -248,7 +248,7 @@ VNMUL_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vnmul_inst)); |     INC_PC(sizeof(vnmul_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -297,7 +297,7 @@ VMUL_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmul_inst)); |     INC_PC(sizeof(vmul_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -346,7 +346,7 @@ VADD_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vadd_inst)); |     INC_PC(sizeof(vadd_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -395,7 +395,7 @@ VSUB_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vsub_inst)); |     INC_PC(sizeof(vsub_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -444,7 +444,7 @@ VDIV_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vdiv_inst)); |     INC_PC(sizeof(vdiv_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -492,7 +492,7 @@ VMOVI_INST: | ||||||
| 
 | 
 | ||||||
|         VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); |         VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovi_inst)); |     INC_PC(sizeof(vmovi_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -536,7 +536,7 @@ VMOVR_INST: | ||||||
| 
 | 
 | ||||||
|         VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); |         VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovr_inst)); |     INC_PC(sizeof(vmovr_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -585,7 +585,7 @@ VABS_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vabs_inst)); |     INC_PC(sizeof(vabs_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -635,7 +635,7 @@ VNEG_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vneg_inst)); |     INC_PC(sizeof(vneg_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -684,7 +684,7 @@ VSQRT_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vsqrt_inst)); |     INC_PC(sizeof(vsqrt_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -733,7 +733,7 @@ VCMP_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vcmp_inst)); |     INC_PC(sizeof(vcmp_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -782,7 +782,7 @@ VCMP2_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vcmp2_inst)); |     INC_PC(sizeof(vcmp2_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -831,7 +831,7 @@ VCVTBDS_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vcvtbds_inst)); |     INC_PC(sizeof(vcvtbds_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -882,7 +882,7 @@ VCVTBFF_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vcvtbff_inst)); |     INC_PC(sizeof(vcvtbff_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -931,7 +931,7 @@ VCVTBFI_INST: | ||||||
| 
 | 
 | ||||||
|         CHECK_VFP_CDP_RET; |         CHECK_VFP_CDP_RET; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vcvtbfi_inst)); |     INC_PC(sizeof(vcvtbfi_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -981,7 +981,7 @@ VMOVBRS_INST: | ||||||
| 
 | 
 | ||||||
|         VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); |         VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovbrs_inst)); |     INC_PC(sizeof(vmovbrs_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1032,7 +1032,7 @@ VMSR_INST: | ||||||
|         { |         { | ||||||
|             cpu->VFP[VFP_FPSCR] = cpu->Reg[rt]; |             cpu->VFP[VFP_FPSCR] = cpu->Reg[rt]; | ||||||
|         } |         } | ||||||
|         else if (InAPrivilegedMode(cpu)) |         else if (cpu->InAPrivilegedMode()) | ||||||
|         { |         { | ||||||
|             if (reg == 8) |             if (reg == 8) | ||||||
|                 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt]; |                 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt]; | ||||||
|  | @ -1042,7 +1042,7 @@ VMSR_INST: | ||||||
|                 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt]; |                 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt]; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmsr_inst)); |     INC_PC(sizeof(vmsr_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1090,7 +1090,7 @@ VMOVBRC_INST: | ||||||
| 
 | 
 | ||||||
|         cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; |         cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovbrc_inst)); |     INC_PC(sizeof(vmovbrc_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1163,7 +1163,7 @@ VMRS_INST: | ||||||
|         { |         { | ||||||
|             cpu->Reg[rt] = cpu->VFP[VFP_MVFR0]; |             cpu->Reg[rt] = cpu->VFP[VFP_MVFR0]; | ||||||
|         } |         } | ||||||
|         else if (InAPrivilegedMode(cpu)) |         else if (cpu->InAPrivilegedMode()) | ||||||
|         { |         { | ||||||
|             if (reg == 8) |             if (reg == 8) | ||||||
|                 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC]; |                 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC]; | ||||||
|  | @ -1173,7 +1173,7 @@ VMRS_INST: | ||||||
|                 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2]; |                 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2]; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmrs_inst)); |     INC_PC(sizeof(vmrs_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1221,7 +1221,7 @@ VMOVBCR_INST: | ||||||
| 
 | 
 | ||||||
|         cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; |         cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovbcr_inst)); |     INC_PC(sizeof(vmovbcr_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1274,7 +1274,7 @@ VMOVBRRSS_INST: | ||||||
|         VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, |         VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | ||||||
|             &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); |             &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovbrrss_inst)); |     INC_PC(sizeof(vmovbrrss_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1322,7 +1322,7 @@ VMOVBRRD_INST: | ||||||
|         VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, |         VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | ||||||
|             &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); |             &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vmovbrrd_inst)); |     INC_PC(sizeof(vmovbrrd_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1378,23 +1378,23 @@ VSTR_INST: | ||||||
| 
 | 
 | ||||||
|         if (inst_cream->single) |         if (inst_cream->single) | ||||||
|         { |         { | ||||||
|             WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]); |             cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; |             const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; | ||||||
|             const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; |             const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; | ||||||
| 
 | 
 | ||||||
|             if (InBigEndianMode(cpu)) { |             if (cpu->InBigEndianMode()) { | ||||||
|                 WriteMemory32(cpu, addr + 0, word2); |                 cpu->WriteMemory32(addr + 0, word2); | ||||||
|                 WriteMemory32(cpu, addr + 4, word1); |                 cpu->WriteMemory32(addr + 4, word1); | ||||||
|             } else { |             } else { | ||||||
|                 WriteMemory32(cpu, addr + 0, word1); |                 cpu->WriteMemory32(addr + 0, word1); | ||||||
|                 WriteMemory32(cpu, addr + 4, word2); |                 cpu->WriteMemory32(addr + 4, word2); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vstr_inst)); |     INC_PC(sizeof(vstr_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1444,7 +1444,7 @@ VPUSH_INST: | ||||||
|         { |         { | ||||||
|             if (inst_cream->single) |             if (inst_cream->single) | ||||||
|             { |             { | ||||||
|                 WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); |                 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); | ||||||
|                 addr += 4; |                 addr += 4; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|  | @ -1452,12 +1452,12 @@ VPUSH_INST: | ||||||
|                 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; |                 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; | ||||||
|                 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; |                 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; | ||||||
| 
 | 
 | ||||||
|                 if (InBigEndianMode(cpu)) { |                 if (cpu->InBigEndianMode()) { | ||||||
|                     WriteMemory32(cpu, addr + 0, word2); |                     cpu->WriteMemory32(addr + 0, word2); | ||||||
|                     WriteMemory32(cpu, addr + 4, word1); |                     cpu->WriteMemory32(addr + 4, word1); | ||||||
|                 } else { |                 } else { | ||||||
|                     WriteMemory32(cpu, addr + 0, word1); |                     cpu->WriteMemory32(addr + 0, word1); | ||||||
|                     WriteMemory32(cpu, addr + 4, word2); |                     cpu->WriteMemory32(addr + 4, word2); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 addr += 8; |                 addr += 8; | ||||||
|  | @ -1466,7 +1466,7 @@ VPUSH_INST: | ||||||
| 
 | 
 | ||||||
|         cpu->Reg[R13] -= inst_cream->imm32; |         cpu->Reg[R13] -= inst_cream->imm32; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vpush_inst)); |     INC_PC(sizeof(vpush_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1522,7 +1522,7 @@ VSTM_INST: /* encoding 1 */ | ||||||
|         { |         { | ||||||
|             if (inst_cream->single) |             if (inst_cream->single) | ||||||
|             { |             { | ||||||
|                 WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); |                 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); | ||||||
|                 addr += 4; |                 addr += 4; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|  | @ -1530,12 +1530,12 @@ VSTM_INST: /* encoding 1 */ | ||||||
|                 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; |                 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; | ||||||
|                 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; |                 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; | ||||||
| 
 | 
 | ||||||
|                 if (InBigEndianMode(cpu)) { |                 if (cpu->InBigEndianMode()) { | ||||||
|                     WriteMemory32(cpu, addr + 0, word2); |                     cpu->WriteMemory32(addr + 0, word2); | ||||||
|                     WriteMemory32(cpu, addr + 4, word1); |                     cpu->WriteMemory32(addr + 4, word1); | ||||||
|                 } else { |                 } else { | ||||||
|                     WriteMemory32(cpu, addr + 0, word1); |                     cpu->WriteMemory32(addr + 0, word1); | ||||||
|                     WriteMemory32(cpu, addr + 4, word2); |                     cpu->WriteMemory32(addr + 4, word2); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 addr += 8; |                 addr += 8; | ||||||
|  | @ -1597,15 +1597,15 @@ VPOP_INST: | ||||||
|         { |         { | ||||||
|             if (inst_cream->single) |             if (inst_cream->single) | ||||||
|             { |             { | ||||||
|                 cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); |                 cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); | ||||||
|                 addr += 4; |                 addr += 4; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 const u32 word1 = ReadMemory32(cpu, addr + 0); |                 const u32 word1 = cpu->ReadMemory32(addr + 0); | ||||||
|                 const u32 word2 = ReadMemory32(cpu, addr + 4); |                 const u32 word2 = cpu->ReadMemory32(addr + 4); | ||||||
| 
 | 
 | ||||||
|                 if (InBigEndianMode(cpu)) { |                 if (cpu->InBigEndianMode()) { | ||||||
|                     cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; |                     cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; | ||||||
|                     cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; |                     cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; | ||||||
|                 } else { |                 } else { | ||||||
|  | @ -1618,7 +1618,7 @@ VPOP_INST: | ||||||
|         } |         } | ||||||
|         cpu->Reg[R13] += inst_cream->imm32; |         cpu->Reg[R13] += inst_cream->imm32; | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vpop_inst)); |     INC_PC(sizeof(vpop_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1670,14 +1670,14 @@ VLDR_INST: | ||||||
| 
 | 
 | ||||||
|         if (inst_cream->single) |         if (inst_cream->single) | ||||||
|         { |         { | ||||||
|             cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr); |             cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             const u32 word1 = ReadMemory32(cpu, addr + 0); |             const u32 word1 = cpu->ReadMemory32(addr + 0); | ||||||
|             const u32 word2 = ReadMemory32(cpu, addr + 4); |             const u32 word2 = cpu->ReadMemory32(addr + 4); | ||||||
| 
 | 
 | ||||||
|             if (InBigEndianMode(cpu)) { |             if (cpu->InBigEndianMode()) { | ||||||
|                 cpu->ExtReg[inst_cream->d*2+0] = word2; |                 cpu->ExtReg[inst_cream->d*2+0] = word2; | ||||||
|                 cpu->ExtReg[inst_cream->d*2+1] = word1; |                 cpu->ExtReg[inst_cream->d*2+1] = word1; | ||||||
|             } else { |             } else { | ||||||
|  | @ -1686,7 +1686,7 @@ VLDR_INST: | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vldr_inst)); |     INC_PC(sizeof(vldr_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  | @ -1742,15 +1742,15 @@ VLDM_INST: | ||||||
|         { |         { | ||||||
|             if (inst_cream->single) |             if (inst_cream->single) | ||||||
|             { |             { | ||||||
|                 cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); |                 cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); | ||||||
|                 addr += 4; |                 addr += 4; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 const u32 word1 = ReadMemory32(cpu, addr + 0); |                 const u32 word1 = cpu->ReadMemory32(addr + 0); | ||||||
|                 const u32 word2 = ReadMemory32(cpu, addr + 4); |                 const u32 word2 = cpu->ReadMemory32(addr + 4); | ||||||
| 
 | 
 | ||||||
|                 if (InBigEndianMode(cpu)) { |                 if (cpu->InBigEndianMode()) { | ||||||
|                     cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; |                     cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; | ||||||
|                     cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; |                     cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; | ||||||
|                 } else { |                 } else { | ||||||
|  | @ -1766,7 +1766,7 @@ VLDM_INST: | ||||||
|                 cpu->Reg[inst_cream->n] - inst_cream->imm32); |                 cpu->Reg[inst_cream->n] - inst_cream->imm32); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     cpu->Reg[15] += GET_INST_SIZE(cpu); |     cpu->Reg[15] += cpu->GetInstructionSize(); | ||||||
|     INC_PC(sizeof(vldm_inst)); |     INC_PC(sizeof(vldm_inst)); | ||||||
|     FETCH_INST; |     FETCH_INST; | ||||||
|     GOTO_NEXT_INST; |     GOTO_NEXT_INST; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue