ARM7 updates [R. Belmont, Ryan Holtz]

- Prepped to support multiple architecture versions
- Added ARM9 CPU type (ARMv5TE)
- Added mostly-stubbed system coprocessor/MMU support
This commit is contained in:
R. Belmont 2009-07-16 05:09:35 +00:00
parent 00cdb38daf
commit 2ce6e69018
5 changed files with 304 additions and 47 deletions

View File

@ -1,9 +1,10 @@
/*****************************************************************************
*
* arm7.c
* Portable ARM7TDMI CPU Emulator
* Portable CPU Emulator for 32-bit ARM v3/4/5/6
*
* Copyright Steve Ellenoff, all rights reserved.
* Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
@ -20,7 +21,6 @@
* 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)
* #3) Thumb support by Ryan Holtz
*
*****************************************************************************/
@ -41,14 +41,12 @@
/* Example for showing how Co-Proc functions work */
#define TEST_COPROC_FUNCS 1
/* prototypes */
#if TEST_COPROC_FUNCS
static WRITE32_HANDLER(test_do_callback);
static READ32_HANDLER(test_rt_r_callback);
static WRITE32_HANDLER(test_rt_w_callback);
static void test_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
static void test_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));
#endif
/* prototypes of coprocessor functions */
static WRITE32_DEVICE_HANDLER(arm7_do_callback);
static READ32_DEVICE_HANDLER(arm7_rt_r_callback);
static WRITE32_DEVICE_HANDLER(arm7_rt_w_callback);
void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));
/* Macros that can be re-defined for custom cpu implementations - The core expects these to be defined */
/* In this case, we are using the default arm7 handlers (supplied by the core)
@ -92,20 +90,34 @@ static CPU_INIT( arm7 )
cpustate->device = device;
cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
#if TEST_COPROC_FUNCS
// setup co-proc callbacks example
arm7_coproc_do_callback = test_do_callback;
arm7_coproc_rt_r_callback = test_rt_r_callback;
arm7_coproc_rt_w_callback = test_rt_w_callback;
arm7_coproc_dt_r_callback = test_dt_r_callback;
arm7_coproc_dt_w_callback = test_dt_w_callback;
#endif
// setup co-proc callbacks
arm7_coproc_do_callback = arm7_do_callback;
arm7_coproc_rt_r_callback = arm7_rt_r_callback;
arm7_coproc_rt_w_callback = arm7_rt_w_callback;
arm7_coproc_dt_r_callback = arm7_dt_r_callback;
arm7_coproc_dt_w_callback = arm7_dt_w_callback;
}
static CPU_RESET( arm7 )
{
arm_state *cpustate = device->token;
// must call core reset
arm7_core_reset(device);
cpustate->archRev = 4; // ARMv4
cpustate->archFlags = eARM_ARCHFLAGS_T; // has Thumb
}
static CPU_RESET( arm9 )
{
arm_state *cpustate = device->token;
// must call core reset
cpustate->archRev = 5; // ARMv5
cpustate->archFlags = eARM_ARCHFLAGS_T; // has Thumb
arm7_core_reset(device);
}
static CPU_EXIT( arm7 )
@ -324,7 +336,7 @@ CPU_GET_INFO( arm7 )
/* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "ARM7"); break;
case DEVINFO_STR_FAMILY: strcpy(info->s, "Acorn Risc Machine"); break;
case DEVINFO_STR_VERSION: strcpy(info->s, "1.3"); break;
case DEVINFO_STR_VERSION: strcpy(info->s, "2.0"); break;
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Steve Ellenoff, sellenoff@hotmail.com"); break;
@ -391,29 +403,196 @@ CPU_GET_INFO( arm7 )
}
}
/* TEST COPROC CALLBACK HANDLERS - Used for example on how to implement only */
#if TEST_COPROC_FUNCS
static WRITE32_HANDLER(test_do_callback)
CPU_GET_INFO( arm9 )
{
LOG(("test_do_callback opcode=%x, =%x\n", offset, data));
switch (state)
{
case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(arm9); break;
case DEVINFO_STR_NAME: strcpy(info->s, "ARM9"); break;
default: CPU_GET_INFO_CALL(arm7);
break;
}
}
static READ32_HANDLER(test_rt_r_callback)
/* ARM system coprocessor support */
#define LOG(x) logerror x
static WRITE32_DEVICE_HANDLER( arm7_do_callback )
{
UINT32 data=0;
LOG(("test_rt_r_callback opcode=%x\n", offset));
}
static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
{
arm_state *cpustate = device->token;
UINT32 opcode = offset;
UINT8 cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT;
UINT8 op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT;
UINT8 op3 = opcode & INSN_COPRO_OP3;
UINT32 data = 0;
switch( cReg )
{
case 4:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
// RESERVED
LOG( ( "arm7_rt_r_callback CR%d, RESERVED\n", cReg ) );
break;
case 0: // ID
switch (cpustate->archRev)
{
case 3: // ARM6 32-bit
data = 0x41;
break;
case 4: // ARM7/SA11xx
data = 0x41 | (1 << 23) | (7 << 12);
break;
case 5: // ARM9/10/XScale
data = 0x41 | (9 << 12);
if (cpustate->archFlags & eARM_ARCHFLAGS_T)
{
if (cpustate->archFlags & eARM_ARCHFLAGS_E)
{
if (cpustate->archFlags & eARM_ARCHFLAGS_J)
{
data |= (6<<16); // v5TEJ
}
else
{
data |= (5<<16); // v5TE
}
}
else
{
data |= (4<<16); // v5T
}
}
break;
case 6: // ARM11
data = 0x41 | (10<< 12) | (7<<16); // v6
break;
}
LOG( ( "arm7_rt_r_callback, ID\n" ) );
break;
case 1: // Control
LOG( ( "arm7_rt_r_callback, Control\n" ) );
data = COPRO_CTRL;
break;
case 2: // Translation Table Base
LOG( ( "arm7_rt_r_callback, TLB Base\n" ) );
data = COPRO_TLB_BASE;
break;
case 3: // Domain Access Control
LOG( ( "arm7_rt_r_callback, Domain Access Control\n" ) );
break;
case 5: // Fault Status
LOG( ( "arm7_rt_r_callback, Fault Status\n" ) );
break;
case 6: // Fault Address
LOG( ( "arm7_rt_r_callback, Fault Address\n" ) );
break;
case 13: // Read Process ID (PID)
LOG( ( "arm7_rt_r_callback, Read PID\n" ) );
break;
case 14: // Read Breakpoint
LOG( ( "arm7_rt_r_callback, Read Breakpoint\n" ) );
break;
case 15: // Test, Clock, Idle
LOG( ( "arm7_rt_r_callback, Test / Clock / Idle \n" ) );
break;
}
op2 = 0;
op3 = 0;
return data;
}
static WRITE32_HANDLER(test_rt_w_callback)
static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
{
LOG(("test_rt_w_callback opcode=%x, data from ARM7 register=%x\n", offset, data));
arm_state *cpustate = device->token;
UINT32 opcode = offset;
UINT8 cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT;
UINT8 op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT;
UINT8 op3 = opcode & INSN_COPRO_OP3;
switch( cReg )
{
case 0:
case 4:
case 10:
case 11:
case 12:
// RESERVED
LOG( ( "arm7_rt_w_callback CR%d, RESERVED = %08x\n", cReg, data) );
break;
case 1: // Control
LOG( ( "arm7_rt_w_callback Control = %08x (%d) (%d)\n", data, op2, op3 ) );
LOG( ( " MMU:%d, Address Fault:%d, Data Cache:%d, Write Buffer:%d\n",
data & COPRO_CTRL_MMU_EN, ( data & COPRO_CTRL_ADDRFAULT_EN ) >> COPRO_CTRL_ADDRFAULT_EN_SHIFT,
( data & COPRO_CTRL_DCACHE_EN ) >> COPRO_CTRL_DCACHE_EN_SHIFT,
( data & COPRO_CTRL_WRITEBUF_EN ) >> COPRO_CTRL_WRITEBUF_EN_SHIFT ) );
LOG( ( " Endianness:%d, System:%d, ROM:%d, Instruction Cache:%d\n",
( data & COPRO_CTRL_ENDIAN ) >> COPRO_CTRL_ENDIAN_SHIFT,
( data & COPRO_CTRL_SYSTEM ) >> COPRO_CTRL_SYSTEM_SHIFT,
( data & COPRO_CTRL_ROM ) >> COPRO_CTRL_ROM_SHIFT,
( data & COPRO_CTRL_ICACHE_EN ) >> COPRO_CTRL_ICACHE_EN_SHIFT ) );
LOG( ( " Int Vector Adjust:%d\n", ( data & COPRO_CTRL_INTVEC_ADJUST ) >> COPRO_CTRL_INTVEC_ADJUST_SHIFT ) );
COPRO_CTRL = data & COPRO_CTRL_MASK;
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
// change_pc(arm7_tlb_translate(R15));
}
break;
case 2: // Translation Table Base
LOG( ( "arm7_rt_w_callback TLB Base = %08x (%d) (%d)\n", data, op2, op3 ) );
COPRO_TLB_BASE = data;
break;
case 3: // Domain Access Control
LOG( ( "arm7_rt_w_callback Domain Access Control = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 5: // Fault Status
LOG( ( "arm7_rt_w_callback Fault Status = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 6: // Fault Address
LOG( ( "arm7_rt_w_callback Fault Address = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 7: // Cache Operations
LOG( ( "arm7_rt_w_callback Cache Ops = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 8: // TLB Operations
LOG( ( "arm7_rt_w_callback TLB Ops = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 9: // Read Buffer Operations
LOG( ( "arm7_rt_w_callback Read Buffer Ops = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 13: // Write Process ID (PID)
LOG( ( "arm7_rt_w_callback Write PID = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 14: // Write Breakpoint
LOG( ( "arm7_rt_w_callback Write Breakpoint = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
case 15: // Test, Clock, Idle
LOG( ( "arm7_rt_w_callback Test / Clock / Idle = %08x (%d) (%d)\n", data, op2, op3 ) );
break;
}
op2 = 0;
op3 = 0;
}
static void test_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr))
void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr))
{
LOG(("test_dt_r_callback: insn = %x\n", insn));
}
static void test_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data))
void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data))
{
LOG(("test_dt_w_callback: opcode = %x\n", insn));
}
#endif

View File

@ -41,4 +41,7 @@
extern CPU_GET_INFO( arm7 );
#define CPU_ARM7 CPU_GET_INFO_NAME( arm7 )
extern CPU_GET_INFO( arm9 );
#define CPU_ARM9 CPU_GET_INFO_NAME( arm9 )
#endif /* __ARM7_H__ */

View File

@ -117,9 +117,9 @@ INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, offs_t addr);
/* Static Vars */
// Note: for multi-cpu implementation, this approach won't work w/o modification
write32_space_func arm7_coproc_do_callback; // holder for the co processor Data Operations Callback func.
read32_space_func arm7_coproc_rt_r_callback; // holder for the co processor Register Transfer Read Callback func.
write32_space_func arm7_coproc_rt_w_callback; // holder for the co processor Register Transfer Write Callback Callback func.
write32_device_func arm7_coproc_do_callback; // holder for the co processor Data Operations Callback func.
read32_device_func arm7_coproc_rt_r_callback; // holder for the co processor Register Transfer Read Callback func.
write32_device_func arm7_coproc_rt_w_callback; // holder for the co processor Register Transfer Write Callback Callback func.
// holder for the co processor Data Transfer Read & Write Callback funcs
void (*arm7_coproc_dt_r_callback)(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
void (*arm7_coproc_dt_w_callback)(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));
@ -674,7 +674,7 @@ static void HandleCoProcDO(arm_state *cpustate, UINT32 insn)
{
// This instruction simply instructs the co-processor to do something, no data is returned to ARM7 core
if (arm7_coproc_do_callback)
arm7_coproc_do_callback(cpustate->program, insn, 0, 0); // simply pass entire opcode to callback - since data format is actually dependent on co-proc implementation
arm7_coproc_do_callback(cpustate->device, insn, 0, 0); // simply pass entire opcode to callback - since data format is actually dependent on co-proc implementation
else
LOG(("%08x: Co-Processor Data Operation executed, but no callback defined!\n", R15));
}
@ -690,7 +690,7 @@ static void HandleCoProcRT(arm_state *cpustate, UINT32 insn)
{
if (arm7_coproc_rt_r_callback)
{
UINT32 res = arm7_coproc_rt_r_callback(cpustate->program, insn, 0); // RT Read handler must parse opcode & return appropriate result
UINT32 res = arm7_coproc_rt_r_callback(cpustate->device, insn, 0); // RT Read handler must parse opcode & return appropriate result
SET_REGISTER(cpustate, (insn >> 12) & 0xf, res);
}
else
@ -700,7 +700,7 @@ static void HandleCoProcRT(arm_state *cpustate, UINT32 insn)
else
{
if (arm7_coproc_rt_r_callback)
arm7_coproc_rt_w_callback(cpustate->program, insn, GET_REGISTER(cpustate, (insn >> 12) & 0xf), 0);
arm7_coproc_rt_w_callback(cpustate->device, insn, GET_REGISTER(cpustate, (insn >> 12) & 0xf), 0);
else
LOG(("%08x: Co-Processor Register Transfer executed, but no RT Write callback defined!\n", R15));
}

View File

@ -90,6 +90,66 @@ enum
kNumRegisters
};
/* Coprocessor-related macros */
#define COPRO_TLB_BASE cpustate->tlbBase
#define COPRO_TLB_BASE_MASK 0xffffc000
#define COPRO_TLB_VADDR_FLTI_MASK 0xfff00000
#define COPRO_TLB_VADDR_FLTI_MASK_SHIFT 18
#define COPRO_TLB_VADDR_CSLTI_MASK 0x000ff000
#define COPRO_TLB_VADDR_CSLTI_MASK_SHIFT 10
#define COPRO_TLB_VADDR_FSLTI_MASK 0x000ffc00
#define COPRO_TLB_VADDR_FSLTI_MASK_SHIFT 8
#define COPRO_TLB_CFLD_ADDR_MASK 0xfffffc00
#define COPRO_TLB_CFLD_ADDR_MASK_SHIFT 10
#define COPRO_TLB_SECTION_PAGE_MASK 0xfff00000
#define COPRO_TLB_LARGE_PAGE_MASK 0xffff0000
#define COPRO_TLB_SMALL_PAGE_MASK 0xfffff000
#define COPRO_TLB_TINY_PAGE_MASK 0xfffffc00
#define COPRO_TLB_UNMAPPED 0
#define COPRO_TLB_LARGE_PAGE 1
#define COPRO_TLB_SMALL_PAGE 2
#define COPRO_TLB_TINY_PAGE 3
#define COPRO_TLB_COARSE_TABLE 1
#define COPRO_TLB_SECTION_TABLE 2
#define COPRO_TLB_FINE_TABLE 3
#define COPRO_CTRL cpustate->control
#define COPRO_CTRL_MMU_EN 0x00000001
#define COPRO_CTRL_ADDRFAULT_EN 0x00000002
#define COPRO_CTRL_DCACHE_EN 0x00000004
#define COPRO_CTRL_WRITEBUF_EN 0x00000008
#define COPRO_CTRL_ENDIAN 0x00000080
#define COPRO_CTRL_SYSTEM 0x00000100
#define COPRO_CTRL_ROM 0x00000200
#define COPRO_CTRL_ICACHE_EN 0x00001000
#define COPRO_CTRL_INTVEC_ADJUST 0x00002000
#define COPRO_CTRL_ADDRFAULT_EN_SHIFT 1
#define COPRO_CTRL_DCACHE_EN_SHIFT 2
#define COPRO_CTRL_WRITEBUF_EN_SHIFT 3
#define COPRO_CTRL_ENDIAN_SHIFT 7
#define COPRO_CTRL_SYSTEM_SHIFT 8
#define COPRO_CTRL_ROM_SHIFT 9
#define COPRO_CTRL_ICACHE_EN_SHIFT 12
#define COPRO_CTRL_INTVEC_ADJUST_SHIFT 13
#define COPRO_CTRL_LITTLE_ENDIAN 0
#define COPRO_CTRL_BIG_ENDIAN 1
#define COPRO_CTRL_INTVEC_0 0
#define COPRO_CTRL_INTVEC_F 1
#define COPRO_CTRL_MASK 0x0000338f
/* Coprocessor Registers */
#define ARM7COPRO_REGS \
UINT32 control; \
UINT32 tlbBase;
enum
{
eARM_ARCHFLAGS_T = 1, // Thumb present
eARM_ARCHFLAGS_E = 2, // extended DSP operations present (only for v5+)
eARM_ARCHFLAGS_J = 4, // "Jazelle" (direct execution of Java bytecode)
eARM_ARCHFLAGS_MMU = 8, // has on-board MMU (traditional ARM style like the SA1110)
};
#define ARM7CORE_REGS \
UINT32 sArmRegister[kNumRegisters]; \
UINT8 pendingIrq; \
@ -107,7 +167,12 @@ enum
/* CPU state struct */
typedef struct
{
ARM7CORE_REGS // these must be included in your cpu specific register implementation
ARM7CORE_REGS // these must be included in your cpu specific register implementation
ARM7COPRO_REGS
UINT8 archRev; // ARM architecture revision (3, 4, and 5 are valid)
UINT8 archFlags; // architecture flags
} arm_state;
/****************************************************************************************************
@ -278,6 +343,16 @@ static const int sRegisterTable[ARM7_NUM_MODES][18] =
#define INSN_RD_SHIFT 12
#define INSN_COND_SHIFT 28
#define INSN_COPRO_N ((UINT32) 0x00100000u)
#define INSN_COPRO_CREG ((UINT32) 0x000f0000u)
#define INSN_COPRO_AREG ((UINT32) 0x0000f000u)
#define INSN_COPRO_OP2 ((UINT32) 0x000000e0u)
#define INSN_COPRO_OP3 ((UINT32) 0x0000000fu)
#define INSN_COPRO_N_SHIFT 20
#define INSN_COPRO_CREG_SHIFT 16
#define INSN_COPRO_AREG_SHIFT 12
#define INSN_COPRO_OP2_SHIFT 5
#define THUMB_INSN_TYPE ((UINT16)0xf000)
#define THUMB_COND_TYPE ((UINT16)0x0f00)
#define THUMB_GROUP4_TYPE ((UINT16)0x0c00)
@ -403,11 +478,11 @@ enum
#define SET_REGISTER(state, reg, val) SetRegister(state, reg, val)
#define ARM7_CHECKIRQ arm7_check_irq_state(cpustate)
extern write32_space_func arm7_coproc_do_callback;
extern read32_space_func arm7_coproc_rt_r_callback;
extern write32_space_func arm7_coproc_rt_w_callback;
extern void (*arm7_coproc_dt_r_callback)(arm_state *cpustate, UINT32 insn, UINT32* prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
extern void (*arm7_coproc_dt_w_callback)(arm_state *cpustate, UINT32 insn, UINT32* prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));
extern write32_device_func arm7_coproc_do_callback;
extern read32_device_func arm7_coproc_rt_r_callback;
extern write32_device_func arm7_coproc_rt_w_callback;
extern void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
extern void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));
extern UINT32 arm7_disasm(char *pBuf, UINT32 pc, UINT32 opcode);
extern UINT32 thumb_disasm(char *pBuf, UINT32 pc, UINT16 opcode);

View File

@ -65,7 +65,7 @@ static MACHINE_START(39in1)
}
static MACHINE_DRIVER_START( 39in1 )
MDRV_CPU_ADD("maincpu", ARM7, 200000000) // actually Xscale PXA255, but ARM7 is a compatible subset
MDRV_CPU_ADD("maincpu", ARM9, 200000000) // actually Xscale PXA255, but ARM9 is a compatible subset
MDRV_CPU_PROGRAM_MAP(39in1_map)
MDRV_PALETTE_LENGTH(32768)