/*
Copyright (C) 2006 yopyop
Copyright (C) 2006-2012 DeSmuME team
This file 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 file 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 the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
#include "bits.h"
#include "MMU.h"
#include "instructions.h"
inline uint32_t CODE(uint32_t i) { return (i >> 25) & 0x7; }
const uint32_t EXCEPTION_RESET = 0x00;
const uint32_t EXCEPTION_UNDEFINED_INSTRUCTION = 0x04;
const uint32_t EXCEPTION_SWI = 0x08;
const uint32_t EXCEPTION_PREFETCH_ABORT = 0x0C;
const uint32_t EXCEPTION_DATA_ABORT = 0x10;
const uint32_t EXCEPTION_RESERVED_0x14 = 0x14;
const uint32_t EXCEPTION_IRQ = 0x18;
const uint32_t EXCEPTION_FAST_IRQ = 0x1C;
inline uint32_t INSTRUCTION_INDEX(uint32_t i) { return ((i >> 16) & 0xFF0) | ((i >> 4) & 0xF); }
inline uint32_t ROR(uint32_t i, uint32_t j) { return (i >> j) | (i << (32 - j)); }
template<typename T> inline T UNSIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b) | ((a | b) & ~c)); }
template<typename T> inline T UNSIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((~a & b) | ((~a | b) & c)); }
template<typename T> inline T SIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b & ~c) | (~a & ~b & c)); }
template<typename T> inline T SIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((a & ~b & ~c) | (~a & b & c)); }
// ============================= CPRS flags funcs
inline bool CarryFrom(int32_t left, int32_t right)
{
uint32_t res = 0xFFFFFFFFU - static_cast<uint32_t>(left);
return static_cast<uint32_t>(right) > res;
}
inline bool BorrowFrom(int32_t left, int32_t right)
{
return static_cast<uint32_t>(right) > static_cast<uint32_t>(left);
}
inline bool OverflowFromADD(int32_t alu_out, int32_t left, int32_t right)
{
return ((left >= 0 && right >= 0) || (left < 0 && right < 0)) && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
}
inline bool OverflowFromSUB(int32_t alu_out, int32_t left, int32_t right)
{
return ((left < 0 && right >= 0) || (left >= 0 && right < 0)) && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
}
const uint8_t arm_cond_table[] =
{
// N=0, Z=0, C=0, V=0
0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF, // 0x00
0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x20, // 0x00
// N=0, Z=0, C=0, V=1
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x00, // 0x10
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=0, Z=0, C=1, V=0
0x00,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF, // 0x20
0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x20,
// N=0, Z=0, C=1, V=1
0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00, // 0x30
0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=0, Z=1, C=0, V=0
0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF, // 0x40
0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
// N=0, Z=1, C=0, V=1
0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x00, // 0x50
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=0, Z=1, C=1, V=0
0xFF,0x00,0xFF,0x00,0x00,0xFF,0x00,0xFF, // 0x60
0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
// N=0, Z=1, C=1, V=1
0xFF,0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, // 0x70
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=1, Z=0, C=0, V=0
0x00,0xFF,0x00,0xFF,0xFF,0x00,0x00,0xFF, // 0x80
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=1, Z=0, C=0, V=1
0x00,0xFF,0x00,0xFF,0xFF,0x00,0xFF,0x00, // 0x90
0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x20,
// N=1, Z=0, C=1, V=0
0x00,0xFF,0xFF,0x00,0xFF,0x00,0x00,0xFF, // 0xA0
0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=1, Z=0, C=1, V=1
0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x00, // 0xB0
0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x20,
// N=1, Z=1, C=0, V=0
0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF, // 0xC0
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=1, Z=1, C=0, V=1
0xFF,0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00, // 0xD0
0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
// N=1, Z=1, C=1, V=0
0xFF,0x00,0xFF,0x00,0xFF,0x00,0x00,0xFF, // 0xE0
0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
// N=1, Z=1, C=1, V=1
0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, // 0xF0
0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20
};
enum Mode
{
USR = 0x10,
FIQ = 0x11,
IRQ = 0x12,
SVC = 0x13,
ABT = 0x17,
UND = 0x1B,
SYS = 0x1F
};
#ifdef WORDS_BIGENDIAN
typedef union
{
struct
{
uint32_t N : 1,
Z : 1,
C : 1,
V : 1,
Q : 1,
RAZ : 19,
I : 1,
F : 1,
T : 1,
mode : 5;
} bits;
uint32_t val;
} Status_Reg;
#else
typedef union
{
struct
{
uint32_t mode : 5,
T : 1,
F : 1,
I : 1,
RAZ : 19,
Q : 1,
V : 1,
C : 1,
Z : 1,
N : 1;
} bits;
uint32_t val;
} Status_Reg;
#endif
inline uint8_t TEST_COND(uint32_t cond, uint32_t inst, Status_Reg CPSR) { return arm_cond_table[((CPSR.val >> 24) & 0xf0) | cond] & (1 << inst); }
typedef void *armcp_t;
struct armcpu_t
{
uint32_t proc_ID;
uint32_t instruction; //4
uint32_t instruct_adr; //8
uint32_t next_instruction; //12
uint32_t R[16]; //16
Status_Reg CPSR; //80
Status_Reg SPSR;
void changeCPSR();
uint32_t R13_usr, R14_usr;
uint32_t R13_svc, R14_svc;
uint32_t R13_abt, R14_abt;
uint32_t R13_und, R14_und;
uint32_t R13_irq, R14_irq;
uint32_t R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq;
Status_Reg SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq;
uint32_t intVector;
uint8_t LDTBit; // 1 : ARMv5 style 0 : non ARMv5
bool waitIRQ;
bool halt_IE_and_IF; //the cpu is halted, waiting for IE&IF to signal something
uint8_t intrWaitARM_state;
bool BIOS_loaded;
uint32_t (**swi_tab)();
// flag indicating if the processor is stalled (for debugging)
int stalled;
#if defined(_M_X64) || defined(__x86_64__)
u8 cond_table[16 * 16];
#endif
};
int armcpu_new(armcpu_t *armcpu, uint32_t id);
void armcpu_init(armcpu_t *armcpu, uint32_t adr);
uint32_t armcpu_switchMode(armcpu_t *armcpu, uint8_t mode);
bool armcpu_irqException(armcpu_t *armcpu);
void armcpu_exception(armcpu_t *cpu, uint32_t number);
uint32_t TRAPUNDEF(armcpu_t* cpu);
uint32_t armcpu_Wait4IRQ(armcpu_t *cpu);
extern armcpu_t NDS_ARM7, NDS_ARM9;
template<int PROCNUM> uint32_t armcpu_exec();
#ifdef HAVE_JIT
template<int PROCNUM, bool jit> uint32_t armcpu_exec();
#endif
inline void setIF(int PROCNUM, uint32_t flag)
{
// don't set generated bits!!!
assert(!(flag&0x00200000));
MMU.reg_IF_bits[PROCNUM] |= flag;
extern void NDS_Reschedule();
NDS_Reschedule();
}
inline void NDS_makeIrq(int PROCNUM, uint32_t num)
{
setIF(PROCNUM, 1 << num);
}