citra-emu
/
citra
Archived
1
0
Fork 0

Merge pull request #990 from lioncash/arm

dyncom: General cleanup
This commit is contained in:
bunnei 2015-07-25 23:12:34 -04:00
commit 392c7feba0
23 changed files with 320 additions and 415 deletions

View File

@ -15,7 +15,6 @@
#include "common/break_points.h"
#include "common/symbols.h"
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/disassembler/arm_disasm.h"
@ -219,7 +218,7 @@ void DisassemblerWidget::OnToggleStartStop() {
}
void DisassemblerWidget::OnDebugModeEntered() {
ARMword next_instr = Core::g_app_core->GetPC();
u32 next_instr = Core::g_app_core->GetPC();
if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
emu_thread->SetRunning(false);

View File

@ -6,8 +6,8 @@ set(SRCS
arm/dyncom/arm_dyncom_interpreter.cpp
arm/dyncom/arm_dyncom_run.cpp
arm/dyncom/arm_dyncom_thumb.cpp
arm/interpreter/arminit.cpp
arm/interpreter/armsupp.cpp
arm/skyeye_common/arminit.cpp
arm/skyeye_common/armsupp.cpp
arm/skyeye_common/vfp/vfp.cpp
arm/skyeye_common/vfp/vfpdouble.cpp
arm/skyeye_common/vfp/vfpinstr.cpp
@ -132,8 +132,9 @@ set(HEADERS
arm/dyncom/arm_dyncom_run.h
arm/dyncom/arm_dyncom_thumb.h
arm/skyeye_common/arm_regformat.h
arm/skyeye_common/armdefs.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
arm/skyeye_common/vfp/vfp_helper.h

View File

@ -6,7 +6,8 @@
#include "common/make_unique.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
#include "core/arm/dyncom/arm_dyncom.h"
@ -19,18 +20,8 @@
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
state = Common::make_unique<ARMul_State>();
ARMul_NewState(state.get());
ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
state->abort_model = ABORT_BASE_RESTORED;
state->bigendSig = LOW;
state->lateabtSig = LOW;
state->NirqSig = HIGH;
// Reset the core to initial state
ARMul_Reset(state.get());
state->Emulate = RUN;
// Switch to the desired privilege mode.
switch_mode(state.get(), initial_mode);

View File

@ -9,8 +9,8 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/armstate.h"
namespace Core {
struct ThreadContext;

View File

@ -2,8 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/dyncom/arm_dyncom_dec.h"
#include "core/arm/skyeye_common/armsupp.h"
const ISEITEM arm_instruction[] = {
{ "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }},
@ -414,7 +414,7 @@ const ISEITEM arm_exclusion_code[] = {
{ "invalid", 0, INVALID, { 0 }}
};
int decode_arm_instr(uint32_t instr, int32_t *idx) {
int decode_arm_instr(u32 instr, s32* idx) {
int n = 0;
int base = 0;
int ret = DECODE_FAILURE;

View File

@ -4,7 +4,9 @@
#pragma once
int decode_arm_instr(uint32_t instr, int32_t *idx);
#include "common/common_types.h"
int decode_arm_instr(u32 instr, s32* idx);
enum DECODE_STATUS {
DECODE_SUCCESS,

View File

@ -17,8 +17,9 @@
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
#include "core/arm/dyncom/arm_dyncom_run.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armmmu.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
Common::Profiling::TimingCategory profile_execute("DynCom::Execute");
@ -50,22 +51,21 @@ typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
// support LDR/STREXD.
static const ARMword RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
// Exclusive memory access
static int exclusive_detect(ARMul_State* state, ARMword addr) {
static int exclusive_detect(ARMul_State* state, u32 addr) {
if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
return 0;
else
return -1;
}
static void add_exclusive_addr(ARMul_State* state, ARMword addr){
static void add_exclusive_addr(ARMul_State* state, u32 addr){
state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
return;
}
static void remove_exclusive(ARMul_State* state, ARMword addr){
static void remove_exclusive(ARMul_State* state, u32 addr){
state->exclusive_tag = 0xFFFFFFFF;
}

View File

@ -4,6 +4,6 @@
#pragma once
#include "core/arm/skyeye_common/armdefs.h"
struct ARMul_State;
unsigned InterpreterMainLoop(ARMul_State* state);

View File

@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include "core/arm/dyncom/arm_dyncom_run.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
void switch_mode(ARMul_State* core, uint32_t mode) {
if (core->Mode == mode)

View File

@ -18,7 +18,7 @@
#pragma once
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
void switch_mode(ARMul_State* core, uint32_t mode);

View File

@ -6,6 +6,7 @@
// ARM instruction, and using the existing ARM simulator.
#include "core/arm/dyncom/arm_dyncom_thumb.h"
#include "core/arm/skyeye_common/armsupp.h"
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
@ -13,7 +14,7 @@
tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
tdstate valid = t_uninitialized;
ARMword tinstr = instr;
u32 tinstr = instr;
// The endian should be judge here
if((addr & 0x3) != 0)
@ -36,7 +37,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 3: // ADD/SUB
{
static const ARMword subset[4] = {
static const u32 subset[4] = {
0xE0900000, // ADDS Rd,Rs,Rn
0xE0500000, // SUBS Rd,Rs,Rn
0xE2900000, // ADDS Rd,Rs,#imm3
@ -55,7 +56,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 6: // ADD
case 7: // SUB
{
static const ARMword subset[4] = {
static const u32 subset[4] = {
0xE3B00000, // MOVS Rd,#imm8
0xE3500000, // CMP Rd,#imm8
0xE2900000, // ADDS Rd,Rd,#imm8
@ -84,7 +85,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
};
static const struct {
ARMword opcode;
u32 opcode;
otype type;
} subset[16] = {
{ 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
@ -129,8 +130,8 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
break;
}
} else {
ARMword Rd = ((tinstr & 0x0007) >> 0);
ARMword Rs = ((tinstr & 0x0078) >> 3);
u32 Rd = ((tinstr & 0x0007) >> 0);
u32 Rs = ((tinstr & 0x0078) >> 3);
if (tinstr & (1 << 7))
Rd += 8;
@ -184,7 +185,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 10:
case 11:
{
static const ARMword subset[8] = {
static const u32 subset[8] = {
0xE7800000, // STR Rd,[Rb,Ro]
0xE18000B0, // STRH Rd,[Rb,Ro]
0xE7C00000, // STRB Rd,[Rb,Ro]
@ -207,7 +208,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 14: // STRB Rd,[Rb,#imm5]
case 15: // LDRB Rd,[Rb,#imm5]
{
static const ARMword subset[4] = {
static const u32 subset[4] = {
0xE5800000, // STR Rd,[Rb,#imm5]
0xE5900000, // LDR Rd,[Rb,#imm5]
0xE5C00000, // STRB Rd,[Rb,#imm5]
@ -274,7 +275,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| BITS(tinstr, 0, 3) // imm4 field;
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
} else if ((tinstr & 0x0F00) == 0x0200) {
static const ARMword subset[4] = {
static const u32 subset[4] = {
0xE6BF0070, // SXTH
0xE6AF0070, // SXTB
0xE6FF0070, // UXTH
@ -298,7 +299,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| (BIT(tinstr, 4) << 18); // enable bit
}
} else if ((tinstr & 0x0F00) == 0x0a00) {
static const ARMword subset[3] = {
static const u32 subset[3] = {
0xE6BF0F30, // REV
0xE6BF0FB0, // REV16
0xE6FF0FB0, // REVSH
@ -308,7 +309,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| (BITS(tinstr, 0, 2) << 12) // Rd
| BITS(tinstr, 3, 5); // Rm
} else {
static const ARMword subset[4] = {
static const u32 subset[4] = {
0xE92D0000, // STMDB sp!,{rlist}
0xE92D4000, // STMDB sp!,{rlist,lr}
0xE8BD0000, // LDMIA sp!,{rlist}

View File

@ -26,7 +26,7 @@
#pragma once
#include "core/arm/skyeye_common/armdefs.h"
#include "common/common_types.h"
enum tdstate {
t_undefined, // Undefined Thumb instruction

View File

@ -1,318 +0,0 @@
/* armdefs.h -- ARMulator common definitions: 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. */
#pragma once
#include <unordered_map>
#include "common/common_types.h"
#include "core/arm/skyeye_common/arm_regformat.h"
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
#define BIT(s, n) ((s >> (n)) & 1)
// Signal levels
enum {
LOW = 0,
HIGH = 1,
LOWHIGH = 1,
HIGHLOW = 2
};
// Cache types
enum {
NONCACHE = 0,
DATACACHE = 1,
INSTCACHE = 2,
};
// Abort models
enum {
ABORT_BASE_RESTORED = 0,
ABORT_EARLY = 1,
ABORT_BASE_UPDATED = 2
};
#define POS(i) ( (~(i)) >> 31 )
#define NEG(i) ( (i) >> 31 )
typedef u64 ARMdword; // must be 64 bits wide
typedef u32 ARMword; // must be 32 bits wide
typedef u16 ARMhword; // must be 16 bits wide
typedef u8 ARMbyte; // must be 8 bits wide
#define VFP_REG_NUM 64
struct ARMul_State
{
ARMword Emulate; // To start and stop emulation
// Order of the following register should not be modified
ARMword Reg[16]; // The current register file
ARMword Cpsr; // The current PSR
ARMword Spsr_copy;
ARMword phys_pc;
ARMword Reg_usr[2];
ARMword Reg_svc[2]; // R13_SVC R14_SVC
ARMword Reg_abort[2]; // R13_ABORT R14_ABORT
ARMword Reg_undef[2]; // R13 UNDEF R14 UNDEF
ARMword Reg_irq[2]; // R13_IRQ R14_IRQ
ARMword Reg_firq[7]; // R8---R14 FIRQ
ARMword Spsr[7]; // The exception psr's
ARMword Mode; // The current mode
ARMword Bank; // The current register bank
ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode
ARMword exclusive_state;
ARMword exclusive_result;
ARMword CP15[CP15_REGISTER_COUNT];
// FPSID, FPSCR, and FPEXC
ARMword 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).
ARMword ExtReg[VFP_REG_NUM];
/* ---- End of the ordered registers ---- */
ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
unsigned int shifter_carry_out;
// Add armv6 flags dyf:2010-08-09
ARMword GEFlag, EFlag, AFlag, QFlag;
ARMword 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;
/* 2004-05-09 chy
----------------------------------------------------------
read ARM Architecture Reference Manual
2.6.5 Data Abort
There are three Abort Model in ARM arch.
Early Abort Model: used in some ARMv3 and earlier implementations. In this
model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
the base register was unchanged for all other instructions. (oldest)
Base Restored Abort Model: If a Data Abort occurs in an instruction which
specifies base register writeback, the value in the base register is
unchanged. (strongarm, xscale)
Base Updated Abort Model: If a Data Abort occurs in an instruction which
specifies base register writeback, the base register writeback still occurs.
(arm720T)
read PART B
chap2 The System Control Coprocessor CP15
2.4 Register1:control register
L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
processor could be configured:
0=early Abort Model Selected(now obsolete)
1=Late Abort Model selceted(same as Base Updated Abort Model)
on later processors, this bit reads as 1 and ignores writes.
-------------------------------------------------------------
So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
if lateabtSig=0, then it means Base Restored Abort Model
*/
unsigned lateabtSig;
// For differentiating ARM core emulaiton.
bool is_v4; // Are we emulating a v4 architecture (or higher)?
bool is_v5; // Are we emulating a v5 architecture?
bool is_v5e; // Are we emulating a v5e architecture?
bool is_v6; // Are we emulating a v6 architecture?
bool is_v7; // Are we emulating a v7 architecture?
// ARM_ARM A2-18
// 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model
int abort_model;
// 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;
};
/***************************************************************************\
* Types of ARM we know about *
\***************************************************************************/
enum {
ARM_v4_Prop = 0x01,
ARM_v5_Prop = 0x02,
ARM_v5e_Prop = 0x04,
ARM_v6_Prop = 0x08,
ARM_v7_Prop = 0x10,
};
/***************************************************************************\
* The hardware vector addresses *
\***************************************************************************/
enum {
ARMResetV = 0,
ARMUndefinedInstrV = 4,
ARMSWIV = 8,
ARMPrefetchAbortV = 12,
ARMDataAbortV = 16,
ARMAddrExceptnV = 20,
ARMIRQV = 24,
ARMFIQV = 28,
ARMErrorV = 32, // This is an offset, not an address!
ARMul_ResetV = ARMResetV,
ARMul_UndefinedInstrV = ARMUndefinedInstrV,
ARMul_SWIV = ARMSWIV,
ARMul_PrefetchAbortV = ARMPrefetchAbortV,
ARMul_DataAbortV = ARMDataAbortV,
ARMul_AddrExceptnV = ARMAddrExceptnV,
ARMul_IRQV = ARMIRQV,
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);
ARMul_State* ARMul_NewState(ARMul_State* state);
/***************************************************************************\
* Definitions of things in the co-processor interface *
\***************************************************************************/
enum {
ARMul_FIRST = 0,
ARMul_TRANSFER = 1,
ARMul_BUSY = 2,
ARMul_DATA = 3,
ARMul_INTERRUPT = 4,
ARMul_DONE = 0,
ARMul_CANT = 1,
ARMul_INC = 3
};
/***************************************************************************\
* Definitions of things in the host environment *
\***************************************************************************/
enum ConditionCode {
EQ = 0,
NE = 1,
CS = 2,
CC = 3,
MI = 4,
PL = 5,
VS = 6,
VC = 7,
HI = 8,
LS = 9,
GE = 10,
LT = 11,
GT = 12,
LE = 13,
AL = 14,
NV = 15,
};
// Flags for use with the APSR.
enum : u32 {
NBIT = (1U << 31U),
ZBIT = (1 << 30),
CBIT = (1 << 29),
VBIT = (1 << 28),
QBIT = (1 << 27),
JBIT = (1 << 24),
EBIT = (1 << 9),
ABIT = (1 << 8),
IBIT = (1 << 7),
FBIT = (1 << 6),
TBIT = (1 << 5),
// Masks for groups of bits in the APSR.
MODEBITS = 0x1F,
INTBITS = 0x1C0,
};
// Values for Emulate.
enum {
STOP = 0, // Stop
CHANGEMODE = 1, // Change mode
ONCE = 2, // Execute just one iteration
RUN = 3 // Continuous execution
};
bool AddOverflow(ARMword, ARMword, ARMword);
bool SubOverflow(ARMword, ARMword, ARMword);
void ARMul_SelectProcessor(ARMul_State*, unsigned);
u32 AddWithCarry(u32, u32, u32, bool*, bool*);
bool ARMul_AddOverflowQ(ARMword, ARMword);
u8 ARMul_SignedSaturatedAdd8(u8, u8);
u8 ARMul_SignedSaturatedSub8(u8, u8);
u16 ARMul_SignedSaturatedAdd16(u16, u16);
u16 ARMul_SignedSaturatedSub16(u16, u16);
u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
u8 ARMul_UnsignedSaturatedSub8(u8, u8);
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);

View File

@ -16,36 +16,9 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <cstring>
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
/***************************************************************************\
* Returns a new instantiation of the ARMulator's state *
\***************************************************************************/
ARMul_State* ARMul_NewState(ARMul_State* state)
{
state->Emulate = RUN;
state->Mode = USER32MODE;
state->lateabtSig = HIGH;
state->bigendSig = LOW;
return state;
}
/***************************************************************************\
* Call this routine to set ARMulator to model a certain processor *
\***************************************************************************/
void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
{
state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
state->is_v5 = (properties & ARM_v5_Prop) != 0;
state->is_v5e = (properties & ARM_v5e_Prop) != 0;
state->is_v6 = (properties & ARM_v6_Prop) != 0;
state->is_v7 = (properties & ARM_v7_Prop) != 0;
}
// Resets certain MPCore CP15 values to their ARM-defined reset values.
static void ResetMPCoreCP15Registers(ARMul_State* cpu)
{
@ -104,9 +77,7 @@ static void ResetMPCoreCP15Registers(ARMul_State* cpu)
cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
}
/***************************************************************************\
* Call this routine to set up the initial machine state (or perform a RESET *
\***************************************************************************/
// Performs a reset
void ARMul_Reset(ARMul_State* state)
{
VFPInit(state);
@ -125,4 +96,5 @@ void ARMul_Reset(ARMul_State* state)
state->abortSig = LOW;
state->NumInstrs = 0;
state->Emulate = RUN;
}

View File

@ -23,7 +23,8 @@
#include "common/swap.h"
#include "core/memory.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
// Register numbers in the MMU
enum

View File

@ -0,0 +1,215 @@
/* armdefs.h -- ARMulator common definitions: 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. */
#pragma once
#include <unordered_map>
#include "common/common_types.h"
#include "core/arm/skyeye_common/arm_regformat.h"
// Signal levels
enum {
LOW = 0,
HIGH = 1,
LOWHIGH = 1,
HIGHLOW = 2
};
// Cache types
enum {
NONCACHE = 0,
DATACACHE = 1,
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;
};
/***************************************************************************\
* The hardware vector addresses *
\***************************************************************************/
enum {
ARMResetV = 0,
ARMUndefinedInstrV = 4,
ARMSWIV = 8,
ARMPrefetchAbortV = 12,
ARMDataAbortV = 16,
ARMAddrExceptnV = 20,
ARMIRQV = 24,
ARMFIQV = 28,
ARMErrorV = 32, // This is an offset, not an address!
ARMul_ResetV = ARMResetV,
ARMul_UndefinedInstrV = ARMUndefinedInstrV,
ARMul_SWIV = ARMSWIV,
ARMul_PrefetchAbortV = ARMPrefetchAbortV,
ARMul_DataAbortV = ARMDataAbortV,
ARMul_AddrExceptnV = ARMAddrExceptnV,
ARMul_IRQV = ARMIRQV,
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 *
\***************************************************************************/
enum {
ARMul_FIRST = 0,
ARMul_TRANSFER = 1,
ARMul_BUSY = 2,
ARMul_DATA = 3,
ARMul_INTERRUPT = 4,
ARMul_DONE = 0,
ARMul_CANT = 1,
ARMul_INC = 3
};
/***************************************************************************\
* Definitions of things in the host environment *
\***************************************************************************/
enum ConditionCode {
EQ = 0,
NE = 1,
CS = 2,
CC = 3,
MI = 4,
PL = 5,
VS = 6,
VC = 7,
HI = 8,
LS = 9,
GE = 10,
LT = 11,
GT = 12,
LE = 13,
AL = 14,
NV = 15,
};
// Flags for use with the APSR.
enum : u32 {
NBIT = (1U << 31U),
ZBIT = (1 << 30),
CBIT = (1 << 29),
VBIT = (1 << 28),
QBIT = (1 << 27),
JBIT = (1 << 24),
EBIT = (1 << 9),
ABIT = (1 << 8),
IBIT = (1 << 7),
FBIT = (1 << 6),
TBIT = (1 << 5),
// Masks for groups of bits in the APSR.
MODEBITS = 0x1F,
INTBITS = 0x1C0,
};
// Values for Emulate.
enum {
STOP = 0, // Stop
CHANGEMODE = 1, // Change mode
ONCE = 2, // Execute just one iteration
RUN = 3 // Continuous execution
};

View File

@ -18,8 +18,9 @@
#include "common/logging/log.h"
#include "core/mem_map.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
// Unsigned sum of absolute difference
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
@ -47,21 +48,21 @@ u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bo
}
// Compute whether an addition of A and B, giving RESULT, overflowed.
bool AddOverflow(ARMword a, ARMword b, ARMword result)
bool AddOverflow(u32 a, u32 b, u32 result)
{
return ((NEG(a) && NEG(b) && POS(result)) ||
(POS(a) && POS(b) && NEG(result)));
}
// Compute whether a subtraction of A and B, giving RESULT, overflowed.
bool SubOverflow(ARMword a, ARMword b, ARMword result)
bool SubOverflow(u32 a, u32 b, u32 result)
{
return ((NEG(a) && POS(b) && POS(result)) ||
(POS(a) && NEG(b) && NEG(result)));
}
// Returns true if the Q flag should be set as a result of overflow.
bool ARMul_AddOverflowQ(ARMword a, ARMword b)
bool ARMul_AddOverflowQ(u32 a, u32 b)
{
u32 result = a + b;
if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)

View File

@ -0,0 +1,40 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#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)
#define POS(i) ( (~(i)) >> 31 )
#define NEG(i) ( (i) >> 31 )
bool AddOverflow(u32, u32, u32);
bool SubOverflow(u32, u32, u32);
u32 AddWithCarry(u32, u32, u32, bool*, bool*);
bool ARMul_AddOverflowQ(u32, u32);
u8 ARMul_SignedSaturatedAdd8(u8, u8);
u8 ARMul_SignedSaturatedSub8(u8, u8);
u16 ARMul_SignedSaturatedAdd16(u16, u16);
u16 ARMul_SignedSaturatedSub16(u16, u16);
u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
u8 ARMul_UnsignedSaturatedSub8(u8, u8);
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);

View File

@ -23,7 +23,7 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
@ -43,7 +43,7 @@ void VFPInit(ARMul_State* state)
state->VFP[VFP_MVFR1] = 0;
}
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value)
{
if (to_arm)
{
@ -55,7 +55,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
}
}
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
{
if (to_arm)
{
@ -68,7 +68,7 @@ void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword
state->ExtReg[n*2] = *value1;
}
}
void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
{
if (to_arm)
{
@ -82,7 +82,7 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
}
}
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm)
{
if (single)
{
@ -95,7 +95,7 @@ void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
state->ExtReg[d*2] = 0;
}
}
void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword m)
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m)
{
if (single)
{

View File

@ -36,8 +36,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value);
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm);
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm);

View File

@ -34,7 +34,7 @@
#include <cstdio>
#include "common/common_types.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#define do_div(n, base) {n/=base;}
@ -415,7 +415,7 @@ struct op {
u32 flags;
};
static inline u32 fls(ARMword x)
static inline u32 fls(u32 x)
{
int r = 32;

View File

@ -70,9 +70,9 @@ static void vfp_double_dump(const char *str, struct vfp_double *d)
static void vfp_double_normalise_denormal(struct vfp_double *vd)
{
int bits = 31 - fls((ARMword)(vd->significand >> 32));
int bits = 31 - fls((u32)(vd->significand >> 32));
if (bits == 31)
bits = 63 - fls((ARMword)vd->significand);
bits = 63 - fls((u32)vd->significand);
vfp_double_dump("normalise_denormal: in", vd);
@ -109,9 +109,9 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
exponent = vd->exponent;
significand = vd->significand;
shift = 32 - fls((ARMword)(significand >> 32));
shift = 32 - fls((u32)(significand >> 32));
if (shift == 32)
shift = 64 - fls((ARMword)significand);
shift = 64 - fls((u32)significand);
if (shift) {
exponent -= shift;
significand <<= shift;
@ -566,7 +566,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
/*
* 2^0 <= m < 2^32-2^8
*/
d = (ARMword)((vdm.significand << 1) >> shift);
d = (u32)((vdm.significand << 1) >> shift);
rem = vdm.significand << (65 - shift);
if (rmode == FPSCR_ROUND_NEAREST) {
@ -647,7 +647,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
int shift = 1023 + 63 - vdm.exponent; /* 58 */
u64 rem, incr = 0;
d = (ARMword)((vdm.significand << 1) >> shift);
d = (u32)((vdm.significand << 1) >> shift);
rem = vdm.significand << (65 - shift);
if (rmode == FPSCR_ROUND_NEAREST) {

View File

@ -13,7 +13,7 @@
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/hle.h"