Merge pull request #1001 from lioncash/arm
dyncom: Centralize state-related functions.
This commit is contained in:
commit
62caa89f48
|
@ -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);
|
|
||||||
}
|
|
|
@ -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…
Reference in New Issue