Merge pull request #1001 from lioncash/arm

dyncom: Centralize state-related functions.
master
bunnei 2015-07-27 01:09:46 +07:00
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_dec.cpp
arm/dyncom/arm_dyncom_interpreter.cpp
arm/dyncom/arm_dyncom_run.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/vfp/vfp.cpp
arm/skyeye_common/vfp/vfpdouble.cpp
@ -133,7 +132,6 @@ set(HEADERS
arm/dyncom/arm_dyncom_thumb.h
arm/skyeye_common/arm_regformat.h
arm/skyeye_common/armstate.h
arm/skyeye_common/armmmu.h
arm/skyeye_common/armsupp.h
arm/skyeye_common/vfp/asm_vfp.h
arm/skyeye_common/vfp/vfp.h

@ -18,16 +18,7 @@
#include "core/core_timing.h"
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
state = Common::make_unique<ARMul_State>();
// 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;
state = Common::make_unique<ARMul_State>(initial_mode);
}
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) {
memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
ctx.sp = state->Reg[13];
ctx.lr = state->Reg[14];
@ -104,8 +95,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
}
void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
state->Reg[13] = ctx.sp;
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"
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.
* Used with address calculations.
*
* @param core The ARM CPU state instance.
* @param cpu The ARM CPU state instance.
* @param Rn The register being read.
*
* @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.
*/
static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) {
return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int 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.
*
* @param core The ARM CPU state instance.
* @param cpu The ARM CPU state instance.
* @param Rn The register being read.
*
* @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.
*/
static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) {
return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int 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);
}

@ -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
#include <array>
#include <unordered_map>
#include "common/common_types.h"
@ -37,67 +38,30 @@ enum {
INSTCACHE = 2,
};
#define VFP_REG_NUM 64
struct ARMul_State
{
u32 Emulate; // To start and stop emulation
// Order of the following register should not be modified
u32 Reg[16]; // The current register file
u32 Cpsr; // The current PSR
u32 Spsr_copy;
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 modes
enum PrivilegeMode {
USER32MODE = 16,
FIQ32MODE = 17,
IRQ32MODE = 18,
SVC32MODE = 19,
ABORT32MODE = 23,
UNDEF32MODE = 27,
SYSTEM32MODE = 31
};
/***************************************************************************\
* The hardware vector addresses *
\***************************************************************************/
// ARM privilege mode register banks
enum {
USERBANK = 0,
FIQBANK = 1,
IRQBANK = 2,
SVCBANK = 3,
ABORTBANK = 4,
UNDEFBANK = 5,
DUMMYBANK = 6,
SYSTEMBANK = 7
};
// Hardware vector addresses
enum {
ARMResetV = 0,
ARMUndefinedInstrV = 4,
@ -119,40 +83,7 @@ enum {
ARMul_FIQV = ARMFIQV
};
/***************************************************************************\
* 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 *
\***************************************************************************/
// Coprocessor status values
enum {
ARMul_FIRST = 0,
ARMul_TRANSFER = 1,
@ -164,10 +95,7 @@ enum {
ARMul_INC = 3
};
/***************************************************************************\
* Definitions of things in the host environment *
\***************************************************************************/
// Instruction condition codes
enum ConditionCode {
EQ = 0,
NE = 1,
@ -213,3 +141,93 @@ enum {
ONCE = 2, // Execute just one iteration
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;
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"
struct ARMul_State;
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
#define BIT(s, n) ((s >> (n)) & 1)
@ -32,9 +30,3 @@ u16 ARMul_UnsignedSaturatedSub16(u16, u16);
u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
u32 ARMul_SignedSatQ(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;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -100,7 +100,7 @@ VMLS_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmls_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -149,7 +149,7 @@ VNMLA_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -199,7 +199,7 @@ VNMLS_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmls_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -248,7 +248,7 @@ VNMUL_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -297,7 +297,7 @@ VMUL_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -346,7 +346,7 @@ VADD_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vadd_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -395,7 +395,7 @@ VSUB_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vsub_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -444,7 +444,7 @@ VDIV_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vdiv_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -492,7 +492,7 @@ VMOVI_INST:
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));
FETCH_INST;
GOTO_NEXT_INST;
@ -536,7 +536,7 @@ VMOVR_INST:
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));
FETCH_INST;
GOTO_NEXT_INST;
@ -585,7 +585,7 @@ VABS_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vabs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -635,7 +635,7 @@ VNEG_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vneg_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -684,7 +684,7 @@ VSQRT_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vsqrt_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -733,7 +733,7 @@ VCMP_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcmp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -782,7 +782,7 @@ VCMP2_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcmp2_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -831,7 +831,7 @@ VCVTBDS_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbds_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -882,7 +882,7 @@ VCVTBFF_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbff_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -931,7 +931,7 @@ VCVTBFI_INST:
CHECK_VFP_CDP_RET;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbfi_inst));
FETCH_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]));
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1032,7 +1032,7 @@ VMSR_INST:
{
cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
}
else if (InAPrivilegedMode(cpu))
else if (cpu->InAPrivilegedMode())
{
if (reg == 8)
cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
@ -1042,7 +1042,7 @@ VMSR_INST:
cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmsr_inst));
FETCH_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->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1163,7 +1163,7 @@ VMRS_INST:
{
cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
}
else if (InAPrivilegedMode(cpu))
else if (cpu->InAPrivilegedMode())
{
if (reg == 8)
cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
@ -1173,7 +1173,7 @@ VMRS_INST:
cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmrs_inst));
FETCH_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[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbcr_inst));
FETCH_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,
&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));
FETCH_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,
&(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));
FETCH_INST;
GOTO_NEXT_INST;
@ -1378,23 +1378,23 @@ VSTR_INST:
if (inst_cream->single)
{
WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]);
cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]);
}
else
{
const u32 word1 = cpu->ExtReg[inst_cream->d*2+0];
const u32 word2 = cpu->ExtReg[inst_cream->d*2+1];
if (InBigEndianMode(cpu)) {
WriteMemory32(cpu, addr + 0, word2);
WriteMemory32(cpu, addr + 4, word1);
if (cpu->InBigEndianMode()) {
cpu->WriteMemory32(addr + 0, word2);
cpu->WriteMemory32(addr + 4, word1);
} else {
WriteMemory32(cpu, addr + 0, word1);
WriteMemory32(cpu, addr + 4, word2);
cpu->WriteMemory32(addr + 0, word1);
cpu->WriteMemory32(addr + 4, word2);
}
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vstr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1444,7 +1444,7 @@ VPUSH_INST:
{
if (inst_cream->single)
{
WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]);
cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
}
else
@ -1452,12 +1452,12 @@ VPUSH_INST:
const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
if (InBigEndianMode(cpu)) {
WriteMemory32(cpu, addr + 0, word2);
WriteMemory32(cpu, addr + 4, word1);
if (cpu->InBigEndianMode()) {
cpu->WriteMemory32(addr + 0, word2);
cpu->WriteMemory32(addr + 4, word1);
} else {
WriteMemory32(cpu, addr + 0, word1);
WriteMemory32(cpu, addr + 4, word2);
cpu->WriteMemory32(addr + 0, word1);
cpu->WriteMemory32(addr + 4, word2);
}
addr += 8;
@ -1466,7 +1466,7 @@ VPUSH_INST:
cpu->Reg[R13] -= inst_cream->imm32;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vpush_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1522,7 +1522,7 @@ VSTM_INST: /* encoding 1 */
{
if (inst_cream->single)
{
WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]);
cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
}
else
@ -1530,12 +1530,12 @@ VSTM_INST: /* encoding 1 */
const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
if (InBigEndianMode(cpu)) {
WriteMemory32(cpu, addr + 0, word2);
WriteMemory32(cpu, addr + 4, word1);
if (cpu->InBigEndianMode()) {
cpu->WriteMemory32(addr + 0, word2);
cpu->WriteMemory32(addr + 4, word1);
} else {
WriteMemory32(cpu, addr + 0, word1);
WriteMemory32(cpu, addr + 4, word2);
cpu->WriteMemory32(addr + 0, word1);
cpu->WriteMemory32(addr + 4, word2);
}
addr += 8;
@ -1597,15 +1597,15 @@ VPOP_INST:
{
if (inst_cream->single)
{
cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr);
cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
addr += 4;
}
else
{
const u32 word1 = ReadMemory32(cpu, addr + 0);
const u32 word2 = ReadMemory32(cpu, addr + 4);
const u32 word1 = cpu->ReadMemory32(addr + 0);
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+1] = word1;
} else {
@ -1618,7 +1618,7 @@ VPOP_INST:
}
cpu->Reg[R13] += inst_cream->imm32;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vpop_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1670,14 +1670,14 @@ VLDR_INST:
if (inst_cream->single)
{
cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr);
cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr);
}
else
{
const u32 word1 = ReadMemory32(cpu, addr + 0);
const u32 word2 = ReadMemory32(cpu, addr + 4);
const u32 word1 = cpu->ReadMemory32(addr + 0);
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+1] = word1;
} else {
@ -1686,7 +1686,7 @@ VLDR_INST:
}
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vldr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@ -1742,15 +1742,15 @@ VLDM_INST:
{
if (inst_cream->single)
{
cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr);
cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
addr += 4;
}
else
{
const u32 word1 = ReadMemory32(cpu, addr + 0);
const u32 word2 = ReadMemory32(cpu, addr + 4);
const u32 word1 = cpu->ReadMemory32(addr + 0);
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+1] = word1;
} else {
@ -1766,7 +1766,7 @@ VLDM_INST:
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));
FETCH_INST;
GOTO_NEXT_INST;