/***************************************************************************** * * arm7core.h * Portable ARM7TDMI Core Emulator * * Copyright Steve Ellenoff, all rights reserved. * * - This source code is released as freeware for non-commercial purposes. * - You are free to use and redistribute this code in modified or * unmodified form, provided you list me in the credits. * - If you modify this source code, you must add a notice to each modified * source file that it has been changed. If you're a nice person, you * will clearly mark each change too. :) * - If you wish to use this for commercial purposes, please contact me at * sellenoff@hotmail.com * - The author of this copywritten work reserves the right to change the * terms of its usage and license at any time, including retroactively * - This entire notice must remain in the source code. * * This work is based on: * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) * ***************************************************************************** This file contains everything related to the arm7 core itself, and is presumed to be cpu implementation non-specific, ie, applies to only the core. ******************************************************************************/ #pragma once #ifndef __ARM7CORE_H__ #define __ARM7CORE_H__ #include "cpuintrf.h" /**************************************************************************************************** * INTERRUPT LINES/EXCEPTIONS ***************************************************************************************************/ enum { ARM7_IRQ_LINE=0, ARM7_FIRQ_LINE, ARM7_ABORT_EXCEPTION, ARM7_ABORT_PREFETCH_EXCEPTION, ARM7_UNDEFINE_EXCEPTION, ARM7_NUM_LINES }; // Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify /**************************************************************************************************** * ARM7 CORE REGISTERS ***************************************************************************************************/ enum { ARM7_PC = 0, ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7, ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15, ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14, ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR, ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR }; #define ARM7CORE_REGS \ UINT32 sArmRegister[kNumRegisters]; \ UINT8 pendingIrq; \ UINT8 pendingFiq; \ UINT8 pendingAbtD; \ UINT8 pendingAbtP; \ UINT8 pendingUnd; \ UINT8 pendingSwi; \ cpu_irq_callback irq_callback; \ const device_config *device; /**************************************************************************************************** * VARIOUS INTERNAL STRUCS/DEFINES/ETC.. ***************************************************************************************************/ // Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes enum { eARM7_MODE_USER = 0x0, // Bit: 4-0 = 10000 eARM7_MODE_FIQ = 0x1, // Bit: 4-0 = 10001 eARM7_MODE_IRQ = 0x2, // Bit: 4-0 = 10010 eARM7_MODE_SVC = 0x3, // Bit: 4-0 = 10011 eARM7_MODE_ABT = 0x7, // Bit: 4-0 = 10111 eARM7_MODE_UND = 0xb, // Bit: 4-0 = 11011 eARM7_MODE_SYS = 0xf // Bit: 4-0 = 11111 }; #define ARM7_NUM_MODES 0x10 /* There are 36 Unique - 32 bit processor registers */ /* Each mode has 17 registers (except user & system, which have 16) */ /* This is a list of each *unique* register */ enum { /* All modes have the following */ eR0 = 0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13, /* Stack Pointer */ eR14, /* Link Register (holds return address) */ eR15, /* Program Counter */ eCPSR, /* Current Status Program Register */ /* Fast Interrupt - Bank switched registers */ eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eSPSR_FIQ, /* IRQ - Bank switched registers */ eR13_IRQ, eR14_IRQ, eSPSR_IRQ, /* Supervisor/Service Mode - Bank switched registers */ eR13_SVC, eR14_SVC, eSPSR_SVC, /* Abort Mode - Bank switched registers */ eR13_ABT, eR14_ABT, eSPSR_ABT, /* Undefined Mode - Bank switched registers */ eR13_UND, eR14_UND, eSPSR_UND, kNumRegisters }; static const int thumbCycles[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f }; /* 17 processor registers are visible at any given time, * banked depending on processor mode. */ static const int sRegisterTable[ARM7_NUM_MODES][18] = { { /* USR */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13, eR14, eR15, eCPSR // No SPSR in this mode }, { /* FIQ */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eR15, eCPSR, eSPSR_FIQ }, { /* IRQ */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13_IRQ, eR14_IRQ, eR15, eCPSR, eSPSR_IRQ }, { /* SVC */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13_SVC, eR14_SVC, eR15, eCPSR, eSPSR_SVC }, {0}, {0}, {0}, // values for modes 4,5,6 are not valid { /* ABT */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13_ABT, eR14_ABT, eR15, eCPSR, eSPSR_ABT }, {0}, {0}, {0}, // values for modes 8,9,a are not valid! { /* UND */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13_UND, eR14_UND, eR15, eCPSR, eSPSR_UND }, {0}, {0}, {0}, // values for modes c,d, e are not valid! { /* SYS */ eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, eR8, eR9, eR10, eR11, eR12, eR13, eR14, eR15, eCPSR // No SPSR in this mode } }; #define N_BIT 31 #define Z_BIT 30 #define C_BIT 29 #define V_BIT 28 #define I_BIT 7 #define F_BIT 6 #define T_BIT 5 // Thumb mode #define N_MASK ((UINT32)(1 << N_BIT)) /* Negative flag */ #define Z_MASK ((UINT32)(1 << Z_BIT)) /* Zero flag */ #define C_MASK ((UINT32)(1 << C_BIT)) /* Carry flag */ #define V_MASK ((UINT32)(1 << V_BIT)) /* oVerflow flag */ #define I_MASK ((UINT32)(1 << I_BIT)) /* Interrupt request disable */ #define F_MASK ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */ #define T_MASK ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */ #define N_IS_SET(pc) ((pc) & N_MASK) #define Z_IS_SET(pc) ((pc) & Z_MASK) #define C_IS_SET(pc) ((pc) & C_MASK) #define V_IS_SET(pc) ((pc) & V_MASK) #define I_IS_SET(pc) ((pc) & I_MASK) #define F_IS_SET(pc) ((pc) & F_MASK) #define T_IS_SET(pc) ((pc) & T_MASK) #define N_IS_CLEAR(pc) (!N_IS_SET(pc)) #define Z_IS_CLEAR(pc) (!Z_IS_SET(pc)) #define C_IS_CLEAR(pc) (!C_IS_SET(pc)) #define V_IS_CLEAR(pc) (!V_IS_SET(pc)) #define I_IS_CLEAR(pc) (!I_IS_SET(pc)) #define F_IS_CLEAR(pc) (!F_IS_SET(pc)) #define T_IS_CLEAR(pc) (!T_IS_SET(pc)) /* Deconstructing an instruction */ // todo: use these in all places (including dasm file) #define INSN_COND ((UINT32)0xf0000000u) #define INSN_SDT_L ((UINT32)0x00100000u) #define INSN_SDT_W ((UINT32)0x00200000u) #define INSN_SDT_B ((UINT32)0x00400000u) #define INSN_SDT_U ((UINT32)0x00800000u) #define INSN_SDT_P ((UINT32)0x01000000u) #define INSN_BDT_L ((UINT32)0x00100000u) #define INSN_BDT_W ((UINT32)0x00200000u) #define INSN_BDT_S ((UINT32)0x00400000u) #define INSN_BDT_U ((UINT32)0x00800000u) #define INSN_BDT_P ((UINT32)0x01000000u) #define INSN_BDT_REGS ((UINT32)0x0000ffffu) #define INSN_SDT_IMM ((UINT32)0x00000fffu) #define INSN_MUL_A ((UINT32)0x00200000u) #define INSN_MUL_RM ((UINT32)0x0000000fu) #define INSN_MUL_RS ((UINT32)0x00000f00u) #define INSN_MUL_RN ((UINT32)0x0000f000u) #define INSN_MUL_RD ((UINT32)0x000f0000u) #define INSN_I ((UINT32)0x02000000u) #define INSN_OPCODE ((UINT32)0x01e00000u) #define INSN_S ((UINT32)0x00100000u) #define INSN_BL ((UINT32)0x01000000u) #define INSN_BRANCH ((UINT32)0x00ffffffu) #define INSN_SWI ((UINT32)0x00ffffffu) #define INSN_RN ((UINT32)0x000f0000u) #define INSN_RD ((UINT32)0x0000f000u) #define INSN_OP2 ((UINT32)0x00000fffu) #define INSN_OP2_SHIFT ((UINT32)0x00000f80u) #define INSN_OP2_SHIFT_TYPE ((UINT32)0x00000070u) #define INSN_OP2_RM ((UINT32)0x0000000fu) #define INSN_OP2_ROTATE ((UINT32)0x00000f00u) #define INSN_OP2_IMM ((UINT32)0x000000ffu) #define INSN_OP2_SHIFT_TYPE_SHIFT 4 #define INSN_OP2_SHIFT_SHIFT 7 #define INSN_OP2_ROTATE_SHIFT 8 #define INSN_MUL_RS_SHIFT 8 #define INSN_MUL_RN_SHIFT 12 #define INSN_MUL_RD_SHIFT 16 #define INSN_OPCODE_SHIFT 21 #define INSN_RN_SHIFT 16 #define INSN_RD_SHIFT 12 #define INSN_COND_SHIFT 28 #define THUMB_INSN_TYPE ((UINT16)0xf000) #define THUMB_COND_TYPE ((UINT16)0x0f00) #define THUMB_GROUP4_TYPE ((UINT16)0x0c00) #define THUMB_GROUP5_TYPE ((UINT16)0x0e00) #define THUMB_GROUP5_RM ((UINT16)0x01c0) #define THUMB_GROUP5_RN ((UINT16)0x0038) #define THUMB_GROUP5_RD ((UINT16)0x0007) #define THUMB_ADDSUB_RNIMM ((UINT16)0x01c0) #define THUMB_ADDSUB_RS ((UINT16)0x0038) #define THUMB_ADDSUB_RD ((UINT16)0x0007) #define THUMB_INSN_ADDSUB ((UINT16)0x0800) #define THUMB_INSN_CMP ((UINT16)0x0800) #define THUMB_INSN_SUB ((UINT16)0x0800) #define THUMB_INSN_IMM_RD ((UINT16)0x0700) #define THUMB_INSN_IMM_S ((UINT16)0x0080) #define THUMB_INSN_IMM ((UINT16)0x00ff) #define THUMB_ADDSUB_TYPE ((UINT16)0x0600) #define THUMB_HIREG_OP ((UINT16)0x0300) #define THUMB_HIREG_H ((UINT16)0x00c0) #define THUMB_HIREG_RS ((UINT16)0x0038) #define THUMB_HIREG_RD ((UINT16)0x0007) #define THUMB_STACKOP_TYPE ((UINT16)0x0f00) #define THUMB_STACKOP_L ((UINT16)0x0800) #define THUMB_STACKOP_RD ((UINT16)0x0700) #define THUMB_ALUOP_TYPE ((UINT16)0x03c0) #define THUMB_BLOP_LO ((UINT16)0x0800) #define THUMB_BLOP_OFFS ((UINT16)0x07ff) #define THUMB_SHIFT_R ((UINT16)0x0800) #define THUMB_SHIFT_AMT ((UINT16)0x07c0) #define THUMB_HALFOP_L ((UINT16)0x0800) #define THUMB_HALFOP_OFFS ((UINT16)0x07c0) #define THUMB_BRANCH_OFFS ((UINT16)0x07ff) #define THUMB_LSOP_L ((UINT16)0x0800) #define THUMB_LSOP_OFFS ((UINT16)0x07c0) #define THUMB_MULTLS ((UINT16)0x0800) #define THUMB_MULTLS_BASE ((UINT16)0x0700) #define THUMB_RELADDR_SP ((UINT16)0x0800) #define THUMB_RELADDR_RD ((UINT16)0x0700) #define THUMB_INSN_TYPE_SHIFT 12 #define THUMB_COND_TYPE_SHIFT 8 #define THUMB_GROUP4_TYPE_SHIFT 10 #define THUMB_GROUP5_TYPE_SHIFT 9 #define THUMB_ADDSUB_TYPE_SHIFT 9 #define THUMB_INSN_IMM_RD_SHIFT 8 #define THUMB_STACKOP_TYPE_SHIFT 8 #define THUMB_HIREG_OP_SHIFT 8 #define THUMB_STACKOP_RD_SHIFT 8 #define THUMB_MULTLS_BASE_SHIFT 8 #define THUMB_RELADDR_RD_SHIFT 8 #define THUMB_HIREG_H_SHIFT 6 #define THUMB_HIREG_RS_SHIFT 3 #define THUMB_ALUOP_TYPE_SHIFT 6 #define THUMB_SHIFT_AMT_SHIFT 6 #define THUMB_HALFOP_OFFS_SHIFT 6 #define THUMB_LSOP_OFFS_SHIFT 6 #define THUMB_GROUP5_RM_SHIFT 6 #define THUMB_GROUP5_RN_SHIFT 3 #define THUMB_GROUP5_RD_SHIFT 0 #define THUMB_ADDSUB_RNIMM_SHIFT 6 #define THUMB_ADDSUB_RS_SHIFT 3 #define THUMB_ADDSUB_RD_SHIFT 0 enum { OPCODE_AND, /* 0000 */ OPCODE_EOR, /* 0001 */ OPCODE_SUB, /* 0010 */ OPCODE_RSB, /* 0011 */ OPCODE_ADD, /* 0100 */ OPCODE_ADC, /* 0101 */ OPCODE_SBC, /* 0110 */ OPCODE_RSC, /* 0111 */ OPCODE_TST, /* 1000 */ OPCODE_TEQ, /* 1001 */ OPCODE_CMP, /* 1010 */ OPCODE_CMN, /* 1011 */ OPCODE_ORR, /* 1100 */ OPCODE_MOV, /* 1101 */ OPCODE_BIC, /* 1110 */ OPCODE_MVN /* 1111 */ }; enum { COND_EQ = 0, /* Z equal */ COND_NE, /* ~Z not equal */ COND_CS, COND_HS = 2, /* C unsigned higher or same */ COND_CC, COND_LO = 3, /* ~C unsigned lower */ COND_MI, /* N negative */ COND_PL, /* ~N positive or zero */ COND_VS, /* V overflow */ COND_VC, /* ~V no overflow */ COND_HI, /* C && ~Z unsigned higher */ COND_LS, /* ~C || Z unsigned lower or same */ COND_GE, /* N == V greater or equal */ COND_LT, /* N != V less than */ COND_GT, /* ~Z && N == V greater than */ COND_LE, /* Z || N != V less than or equal */ COND_AL, /* 1 always */ COND_NV /* 0 never */ }; #define LSL(v, s) ((v) << (s)) #define LSR(v, s) ((v) >> (s)) #define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s)))) #define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s)))) /* Convenience Macros */ #define R15 ARM7REG(eR15) #define SPSR 17 // SPSR is always the 18th register in our 0 based array sRegisterTable[][18] #define GET_CPSR ARM7REG(eCPSR) #define SET_CPSR(v) (GET_CPSR = (v)) #define MODE_FLAG 0xF // Mode bits are 4:0 of CPSR, but we ignore bit 4. #define GET_MODE (GET_CPSR & MODE_FLAG) #define SIGN_BIT ((UINT32)(1 << 31)) #define SIGN_BITS_DIFFER(a, b) (((a) ^ (b)) >> 31) /* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */ #define THUMB_SIGN_BIT ((UINT32)(1 << 31)) #define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31) /* At one point I thought these needed to be cpu implementation specific, but they don't.. */ #define GET_REGISTER(reg) GetRegister(reg) #define SET_REGISTER(reg, val) SetRegister(reg, val) #define ARM7_CHECKIRQ arm7_check_irq_state() extern WRITE32_HANDLER((*arm7_coproc_do_callback)); extern READ32_HANDLER((*arm7_coproc_rt_r_callback)); extern WRITE32_HANDLER((*arm7_coproc_rt_w_callback)); extern void (*arm7_coproc_dt_r_callback)(UINT32 insn, UINT32* prn, UINT32 (*read32)(UINT32 addr)); extern void (*arm7_coproc_dt_w_callback)(UINT32 insn, UINT32* prn, void (*write32)(UINT32 addr, UINT32 data)); extern UINT32 arm7_disasm(char *pBuf, UINT32 pc, UINT32 opcode); extern UINT32 thumb_disasm(char *pBuf, UINT32 pc, UINT16 opcode); #ifdef UNUSED_DEFINITION extern char *(*arm7_dasm_cop_dt_callback)(char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); extern char *(*arm7_dasm_cop_rt_callback)(char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); extern char *(*arm7_dasm_cop_do_callback)(char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); #endif #endif /* __ARM7CORE_H__ */