/*
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 .
*/
#ifndef ARM_CPU
#define ARM_CPU
#include "types.h"
#include "bits.h"
#include "MMU.h"
#include "common.h"
static inline uint32_t CODE(uint32_t i) { return (i >> 25) & 0x7; }
static const uint32_t EXCEPTION_RESET = 0x00;
static const uint32_t EXCEPTION_UNDEFINED_INSTRUCTION = 0x04;
static const uint32_t EXCEPTION_SWI = 0x08;
static const uint32_t EXCEPTION_PREFETCH_ABORT = 0x0C;
static const uint32_t EXCEPTION_DATA_ABORT = 0x10;
static const uint32_t EXCEPTION_RESERVED_0x14 = 0x14;
static const uint32_t EXCEPTION_IRQ = 0x18;
static const uint32_t EXCEPTION_FAST_IRQ = 0x1C;
static inline uint32_t INSTRUCTION_INDEX(uint32_t i) { return ((i >> 16) & 0xFF0) | ((i >> 4) & 0xF); }
static inline uint32_t ROR(uint32_t i, uint32_t j) { return (i >> j) | (i << (32 - j)); }
template static inline T UNSIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b) | ((a | b) & ~c)); }
template static inline T UNSIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((~a & b) | ((~a | b) & c)); }
template static inline T SIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b & ~c) | (~a & ~b & c)); }
template static inline T SIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((a & ~b & ~c) | (~a & b & c)); }
// ============================= CPRS flags funcs
static inline bool CarryFrom(int32_t left, int32_t right)
{
uint32_t res = 0xFFFFFFFFU - static_cast(left);
return static_cast(right) > res;
}
static inline bool BorrowFrom(int32_t left, int32_t right)
{
return static_cast(right) > static_cast(left);
}
static 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));
}
//zero 15-feb-2009 - these werent getting used and they were getting in my way
//#define EQ 0x0
//#define NE 0x1
//#define CS 0x2
//#define CC 0x3
//#define MI 0x4
//#define PL 0x5
//#define VS 0x6
//#define VC 0x7
//#define HI 0x8
//#define LS 0x9
//#define GE 0xA
//#define LT 0xB
//#define GT 0xC
//#define LE 0xD
//#define AL 0xE
extern const uint8_t arm_cond_table[16 * 16];
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
static 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); }
/**
* The control interface to a CPU
*/
/*struct armcpu_ctrl_iface
{*/
/** stall the processor */
//void (*stall)(void *instance);
/** unstall the processor */
//void (*unstall)(void *instance);
/** read a register value */
//uint32_t (*read_reg)(void *instance, uint32_t reg_num);
/** set a register value */
//void (*set_reg)(void *instance, uint32_t reg_num, uint32_t value);
/** install the post execute function */
//void (*install_post_ex_fn)( void *instance, void (*fn)(void *, uint32_t, int), void *fn_data);
/** remove the post execute function */
//void (*remove_post_ex_fn)(void *instance);
/** the private data passed to all interface functions */
/*void *data;
};*/
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;
armcp_t *coproc[16];
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;
#ifdef GDB_STUB
/** there is a pending irq for the cpu */
int irq_flag;
/** the post executed function (if installed) */
void (*post_ex_fn)(void *, uint32_t adr, int thumb);
/** data for the post executed function */
void *post_ex_fn_data;
/** the memory interface */
armcpu_memory_iface *mem_if;
/** the ctrl interface */
armcpu_ctrl_iface ctrl_iface;
#endif
};
#ifdef GDB_STUB
int armcpu_new(armcpu_t *armcpu, uint32_t id, armcpu_memory_iface *mem_if, armcpu_ctrl_iface **ctrl_iface_ret);
#else
int armcpu_new(armcpu_t *armcpu, uint32_t id);
#endif
void armcpu_init(armcpu_t *armcpu, uint32_t adr);
uint32_t armcpu_switchMode(armcpu_t *armcpu, uint8_t mode);
template uint32_t armcpu_exec();
bool armcpu_irqException(armcpu_t *armcpu);
//bool armcpu_flagIrq( 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;
static 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();
}
static inline void NDS_makeIrq(int PROCNUM, uint32_t num)
{
setIF(PROCNUM, 1<> 6;
strcpy(txt, intToBin(static_cast(tmp)) + 6);
}
else
{
tmp = ((instr >> 16) & 0x0FF0) | ((instr >> 4) & 0x0F);
strcpy(txt, intToBin(tmp) + 20);
}
return _strdup(txt);
}*/
#endif