summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2010-12-31 16:14:01 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2010-12-31 16:14:01 +0000
commit3517c80e37c3945b1c7e1e7b96756a82fcefa66b (patch)
tree95152b5e33490f84e12655e0c5f90e1ca3aa2ac1
parente25860ffdcf67126ee46150947022dd423e6a176 (diff)
ARM7+ updates: [Tim Schuerewegen]
- Enhanced MMU with page fault support - Preliminary 26-bit mode support - Fixed bugs with S-flag operations on R15 - Fixed STRH involving R15 - Support for ARM models 7500 and 920T.
-rw-r--r--src/emu/cpu/arm7/arm7.c143
-rw-r--r--src/emu/cpu/arm7/arm7.h1
-rw-r--r--src/emu/cpu/arm7/arm7core.c205
-rw-r--r--src/emu/cpu/arm7/arm7core.h14
-rw-r--r--src/emu/cpu/arm7/arm7exec.c14
5 files changed, 304 insertions, 73 deletions
diff --git a/src/emu/cpu/arm7/arm7.c b/src/emu/cpu/arm7/arm7.c
index 37a99bad0a2..044a4f30c6a 100644
--- a/src/emu/cpu/arm7/arm7.c
+++ b/src/emu/cpu/arm7/arm7.c
@@ -71,7 +71,7 @@ void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*wr
INLINE arm_state *get_safe_token(running_device *device)
{
assert(device != NULL);
- assert(device->type() == ARM7 || device->type() == ARM7_BE || device->type() == ARM9 || device->type() == PXA255);
+ assert(device->type() == ARM7 || device->type() == ARM7_BE || device->type() == ARM9 || device->type() == ARM920T || device->type() == PXA255);
return (arm_state *)downcast<legacy_cpu_device *>(device)->token();
}
@@ -128,25 +128,94 @@ INLINE UINT32 arm7_tlb_get_second_level_descriptor( arm_state *cpustate, UINT32
return cpustate->program->read_dword( desc_lvl2 );
}
-INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr)
+static UINT32 r15_mmu_enable_addr = 1;
+
+INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
{
- UINT32 desc_lvl1 = arm7_tlb_get_first_level_descriptor( cpustate, vaddr );
+ UINT32 desc_lvl1;
UINT32 desc_lvl2 = 0;
- UINT32 paddr = vaddr;
+ UINT32 paddr;
+ UINT8 domain, permission;
+
+ if (vaddr < 32 * 1024 * 1024)
+ {
+ UINT32 pid = ((COPRO_FCSE_PID >> 25) & 0x7F);
+ if (pid > 0)
+ {
+ //LOG( ( "ARM7: FCSE PID vaddr %08X -> %08X\n", vaddr, vaddr + (pid * (32 * 1024 * 1024))) );
+ vaddr = vaddr + (((COPRO_FCSE_PID >> 25) & 0x7F) * (32 * 1024 * 1024));
+ }
+ }
+
+ desc_lvl1 = arm7_tlb_get_first_level_descriptor( cpustate, vaddr );
+
+ paddr = vaddr;
+
+ if ((R15 == (r15_mmu_enable_addr + 4)) || (R15 == (r15_mmu_enable_addr + 8)))
+ {
+ LOG( ( "ARM7: fetch flat, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
+ return vaddr;
+ }
+ else
+ {
+ r15_mmu_enable_addr = 1;
+ }
+
+ domain = (desc_lvl1 >> 5) & 0xF;
+ permission = (COPRO_DOMAIN_ACCESS_CONTROL >> (domain << 1)) & 3;
switch( desc_lvl1 & 3 )
{
case COPRO_TLB_UNMAPPED:
// Unmapped, generate a translation fault
- LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
+ if (mode == 0)
+ {
+ LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
+ COPRO_FAULT_STATUS = (5 << 0);
+ COPRO_FAULT_ADDRESS = vaddr;
+ cpustate->pendingAbtD = 1;
+ }
+ else if (mode == 1)
+ {
+ LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
+ cpustate->pendingAbtP = 1;
+ }
break;
case COPRO_TLB_COARSE_TABLE:
// Entry is the physical address of a coarse second-level table
- desc_lvl2 = arm7_tlb_get_second_level_descriptor( cpustate, TLB_COARSE, desc_lvl1, vaddr );
+ if (permission == 1)
+ {
+ desc_lvl2 = arm7_tlb_get_second_level_descriptor( cpustate, TLB_COARSE, desc_lvl1, vaddr );
+ }
+ else
+ {
+ LOG( ( "domain %d permission = %d\n", domain, permission ) );
+ LOG( ( "ARM7: Coarse Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", vaddr, domain, R15 ) );
+ }
break;
case COPRO_TLB_SECTION_TABLE:
// Entry is a section
- paddr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SECTION_PAGE_MASK );
+ if ((permission == 1) || (permission == 3))
+ {
+ paddr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SECTION_PAGE_MASK );
+ }
+ else
+ {
+ if (mode == 0)
+ {
+ LOG( ( "domain %d permission = %d\n", domain, permission ) );
+ LOG( ( "ARM7: Section Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", vaddr, domain, R15 ) );
+ COPRO_FAULT_STATUS = (9 << 0);
+ COPRO_FAULT_ADDRESS = vaddr;
+ cpustate->pendingAbtD = 1;
+ }
+ else if (mode == 1)
+ {
+ LOG( ( "domain %d permission = %d\n", domain, permission ) );
+ LOG( ( "ARM7: Section Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", vaddr, domain, R15 ) );
+ cpustate->pendingAbtP = 1;
+ }
+ }
break;
case COPRO_TLB_FINE_TABLE:
// Entry is the physical address of a fine second-level table
@@ -163,7 +232,18 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr)
{
case COPRO_TLB_UNMAPPED:
// Unmapped, generate a translation fault
- LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, vaddr = %08x\n", vaddr ) );
+ if (mode == 0)
+ {
+ LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) );
+ COPRO_FAULT_STATUS = (7 << 0);
+ COPRO_FAULT_ADDRESS = vaddr;
+ cpustate->pendingAbtD = 1;
+ }
+ else if (mode == 1)
+ {
+ LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) );
+ cpustate->pendingAbtP = 1;
+ }
break;
case COPRO_TLB_LARGE_PAGE:
// Large page descriptor
@@ -194,7 +274,7 @@ static CPU_TRANSLATE( arm7 )
/* only applies to the program address space and only does something if the MMU's enabled */
if( space == ADDRESS_SPACE_PROGRAM && ( COPRO_CTRL & COPRO_CTRL_MMU_EN ) )
{
- *address = arm7_tlb_translate(cpustate, *address);
+ *address = arm7_tlb_translate(cpustate, *address, 2);
}
return TRUE;
}
@@ -256,6 +336,17 @@ static CPU_RESET( arm9 )
cpustate->archFlags = eARM_ARCHFLAGS_T | eARM_ARCHFLAGS_E; // has TE extensions
}
+static CPU_RESET( arm920t )
+{
+ arm_state *cpustate = get_safe_token(device);
+
+ // must call core reset
+ arm7_core_reset(device);
+
+ cpustate->archRev = 4; // ARMv4
+ cpustate->archFlags = eARM_ARCHFLAGS_T; // has T extension
+}
+
static CPU_RESET( pxa255 )
{
arm_state *cpustate = get_safe_token(device);
@@ -599,6 +690,17 @@ CPU_GET_INFO( arm9 )
}
}
+CPU_GET_INFO( arm920t )
+{
+ switch (state)
+ {
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(arm920t); break;
+ case DEVINFO_STR_NAME: strcpy(info->s, "ARM920T"); break;
+ default: CPU_GET_INFO_CALL(arm7);
+ break;
+ }
+}
+
CPU_GET_INFO( pxa255 )
{
switch (state)
@@ -666,7 +768,9 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
}
else
{
- fatalerror("ARM7: Unhandled coprocessor %d (archFlags %x)\n", cpnum, cpustate->archFlags);
+ LOG( ("ARM7: Unhandled coprocessor %d (archFlags %x)\n", cpnum, cpustate->archFlags) );
+ cpustate->pendingUnd = 1;
+ return 0;
}
}
@@ -703,6 +807,7 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
else
{
data = 0x41 | (1 << 23) | (7 << 12);
+ //data = (0x41 << 24) | (1 << 20) | (2 << 16) | (0x920 << 4) | (0 << 0); // ARM920T (S3C24xx)
}
break;
@@ -735,6 +840,7 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
break;
case 1: // cache type
data = 0x0f0d2112; // HACK: value expected by ARMWrestler (probably Nintendo DS ARM9's value)
+ //data = (6 << 25) | (1 << 24) | (0x172 << 12) | (0x172 << 0); // ARM920T (S3C24xx)
break;
case 2: // TCM type
data = 0;
@@ -756,15 +862,19 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
break;
case 3: // Domain Access Control
LOG( ( "arm7_rt_r_callback, Domain Access Control\n" ) );
+ data = COPRO_DOMAIN_ACCESS_CONTROL;
break;
case 5: // Fault Status
LOG( ( "arm7_rt_r_callback, Fault Status\n" ) );
+ data = COPRO_FAULT_STATUS;
break;
case 6: // Fault Address
LOG( ( "arm7_rt_r_callback, Fault Address\n" ) );
+ data = COPRO_FAULT_ADDRESS;
break;
case 13: // Read Process ID (PID)
LOG( ( "arm7_rt_r_callback, Read PID\n" ) );
+ data = COPRO_FCSE_PID;
break;
case 14: // Read Breakpoint
LOG( ( "arm7_rt_r_callback, Read Breakpoint\n" ) );
@@ -825,6 +935,14 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
( 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 ) );
+ if (((data & COPRO_CTRL_MMU_EN) != 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) == 0))
+ {
+ r15_mmu_enable_addr = R15;
+ }
+ if (((data & COPRO_CTRL_MMU_EN) == 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) != 0))
+ {
+ R15 = arm7_tlb_translate( cpustate, R15, 0);
+ }
COPRO_CTRL = data & COPRO_CTRL_MASK;
break;
case 2: // Translation Table Base
@@ -833,12 +951,15 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
break;
case 3: // Domain Access Control
LOG( ( "arm7_rt_w_callback Domain Access Control = %08x (%d) (%d)\n", data, op2, op3 ) );
+ COPRO_DOMAIN_ACCESS_CONTROL = data;
break;
case 5: // Fault Status
LOG( ( "arm7_rt_w_callback Fault Status = %08x (%d) (%d)\n", data, op2, op3 ) );
+ COPRO_FAULT_STATUS = data;
break;
case 6: // Fault Address
LOG( ( "arm7_rt_w_callback Fault Address = %08x (%d) (%d)\n", data, op2, op3 ) );
+ COPRO_FAULT_ADDRESS = data;
break;
case 7: // Cache Operations
// LOG( ( "arm7_rt_w_callback Cache Ops = %08x (%d) (%d)\n", data, op2, op3 ) );
@@ -851,6 +972,7 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
break;
case 13: // Write Process ID (PID)
LOG( ( "arm7_rt_w_callback Write PID = %08x (%d) (%d)\n", data, op2, op3 ) );
+ COPRO_FCSE_PID = data;
break;
case 14: // Write Breakpoint
LOG( ( "arm7_rt_w_callback Write Breakpoint = %08x (%d) (%d)\n", data, op2, op3 ) );
@@ -874,5 +996,6 @@ void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*wr
DEFINE_LEGACY_CPU_DEVICE(ARM7, arm7);
DEFINE_LEGACY_CPU_DEVICE(ARM7_BE, arm7_be);
DEFINE_LEGACY_CPU_DEVICE(ARM9, arm9);
+DEFINE_LEGACY_CPU_DEVICE(ARM920T, arm920t);
DEFINE_LEGACY_CPU_DEVICE(PXA255, pxa255);
DEFINE_LEGACY_CPU_DEVICE(SA1110, sa1110);
diff --git a/src/emu/cpu/arm7/arm7.h b/src/emu/cpu/arm7/arm7.h
index 5ab6b51d0fc..1deef008a22 100644
--- a/src/emu/cpu/arm7/arm7.h
+++ b/src/emu/cpu/arm7/arm7.h
@@ -41,6 +41,7 @@
DECLARE_LEGACY_CPU_DEVICE(ARM7, arm7);
DECLARE_LEGACY_CPU_DEVICE(ARM7_BE, arm7_be);
DECLARE_LEGACY_CPU_DEVICE(ARM9, arm9);
+DECLARE_LEGACY_CPU_DEVICE(ARM920T, arm920t);
DECLARE_LEGACY_CPU_DEVICE(PXA255, pxa255);
DECLARE_LEGACY_CPU_DEVICE(SA1110, sa1110);
diff --git a/src/emu/cpu/arm7/arm7core.c b/src/emu/cpu/arm7/arm7core.c
index c5b8d10be3d..8eb3f2095c1 100644
--- a/src/emu/cpu/arm7/arm7core.c
+++ b/src/emu/cpu/arm7/arm7core.c
@@ -131,7 +131,7 @@ INLINE void arm7_cpu_write32(arm_state *cpustate, UINT32 addr, UINT32 data)
{
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
addr &= ~3;
@@ -146,7 +146,7 @@ INLINE void arm7_cpu_write16(arm_state *cpustate, UINT32 addr, UINT16 data)
{
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
addr &= ~1;
@@ -160,7 +160,7 @@ INLINE void arm7_cpu_write8(arm_state *cpustate, UINT32 addr, UINT8 data)
{
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
if ( cpustate->endian == ENDIANNESS_BIG )
@@ -175,7 +175,7 @@ INLINE UINT32 arm7_cpu_read32(arm_state *cpustate, offs_t addr)
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
if (addr & 3)
@@ -203,7 +203,7 @@ INLINE UINT16 arm7_cpu_read16(arm_state *cpustate, offs_t addr)
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
if ( cpustate->endian == ENDIANNESS_BIG )
@@ -223,7 +223,7 @@ INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, offs_t addr)
{
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- addr = arm7_tlb_translate( cpustate, addr );
+ addr = arm7_tlb_translate( cpustate, addr, 0 );
}
// Handle through normal 8 bit handler (for 32 bit cpu)
@@ -460,6 +460,7 @@ static UINT32 decodeShift(arm_state *cpustate, UINT32 insn, UINT32 *pCarry)
static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
{
int i, result;
+ UINT32 data;
result = 0;
rbv &= ~3;
@@ -467,13 +468,15 @@ static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
{
if ((pat >> i) & 1)
{
+ data = READ32(rbv += 4);
+ if (cpustate->pendingAbtD != 0) break;
if (i == 15) {
if (s) /* Pull full contents from stack */
- SET_REGISTER(cpustate, 15, READ32(rbv += 4));
+ SET_REGISTER(cpustate, 15, data);
else /* Pull only address, preserve mode & status flags */
- SET_REGISTER(cpustate, 15, READ32(rbv += 4));
+ SET_REGISTER(cpustate, 15, data);
} else
- SET_REGISTER(cpustate, i, READ32(rbv += 4));
+ SET_REGISTER(cpustate, i, data);
result++;
}
@@ -484,6 +487,7 @@ static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
{
int i, result;
+ UINT32 data;
result = 0;
rbv &= ~3;
@@ -491,14 +495,16 @@ static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
{
if ((pat >> i) & 1)
{
+ data = READ32(rbv -= 4);
+ if (cpustate->pendingAbtD != 0) break;
if (i == 15) {
if (s) /* Pull full contents from stack */
- SET_REGISTER(cpustate, 15, READ32(rbv -= 4));
+ SET_REGISTER(cpustate, 15, data);
else /* Pull only address, preserve mode & status flags */
- SET_REGISTER(cpustate, 15, READ32(rbv -= 4));
+ SET_REGISTER(cpustate, 15, data);
}
else
- SET_REGISTER(cpustate, i, READ32(rbv -= 4));
+ SET_REGISTER(cpustate, i, data);
result++;
}
}
@@ -606,11 +612,12 @@ static void arm7_check_irq_state(arm_state *cpustate)
// Data Abort
if (cpustate->pendingAbtD) {
SwitchMode(cpustate, eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 8 + 8); /* save PC to R14 */
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
SET_CPSR(GET_CPSR & ~T_MASK);
R15 = 0x10; /* IRQ Vector address */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
cpustate->pendingAbtD = 0;
return;
}
@@ -618,33 +625,36 @@ static void arm7_check_irq_state(arm_state *cpustate)
// FIQ
if (cpustate->pendingFiq && (cpsr & F_MASK) == 0) {
SwitchMode(cpustate, eARM7_MODE_FIQ); /* Set FIQ mode so PC is saved to correct R14 bank */
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK | F_MASK); /* Mask both IRQ & FIQ */
SET_CPSR(GET_CPSR & ~T_MASK);
R15 = 0x1c; /* IRQ Vector address */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
return;
}
// IRQ
if (cpustate->pendingIrq && (cpsr & I_MASK) == 0) {
SwitchMode(cpustate, eARM7_MODE_IRQ); /* Set IRQ mode so PC is saved to correct R14 bank */
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
SET_CPSR(GET_CPSR & ~T_MASK);
R15 = 0x18; /* IRQ Vector address */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
return;
}
// Prefetch Abort
if (cpustate->pendingAbtP) {
SwitchMode(cpustate, eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
SET_CPSR(GET_CPSR & ~T_MASK);
R15 = 0x0c; /* IRQ Vector address */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
cpustate->pendingAbtP = 0;
return;
}
@@ -652,11 +662,19 @@ static void arm7_check_irq_state(arm_state *cpustate)
// Undefined instruction
if (cpustate->pendingUnd) {
SwitchMode(cpustate, eARM7_MODE_UND); /* Set UND mode so PC is saved to correct R14 bank */
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ if (T_IS_SET(GET_CPSR))
+ {
+ SET_REGISTER(cpustate, 14, pc - 4 + 2); /* save PC to R14 */
+ }
+ else
+ {
+ SET_REGISTER(cpustate, 14, pc - 4 + 4 - 4); /* save PC to R14 */
+ }
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
SET_CPSR(GET_CPSR & ~T_MASK);
R15 = 0x04; /* IRQ Vector address */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
cpustate->pendingUnd = 0;
return;
}
@@ -667,16 +685,17 @@ static void arm7_check_irq_state(arm_state *cpustate)
// compensate for prefetch (should this also be done for normal IRQ?)
if (T_IS_SET(GET_CPSR))
{
- SET_REGISTER(cpustate, 14, pc-2); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 4 + 2); /* save PC to R14 */
}
else
{
- SET_REGISTER(cpustate, 14, pc); /* save PC to R14 */
+ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */
}
SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */
SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */
SET_CPSR(GET_CPSR & ~T_MASK); /* Go to ARM mode */
R15 = 0x08; /* Jump to the SWI vector */
+ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000;
cpustate->pendingSwi = 0;
return;
}
@@ -744,7 +763,7 @@ static void HandleCoProcRT(arm_state *cpustate, UINT32 insn)
// Store (MCR) data from ARM7 to Co-Proc register
else
{
- if (arm7_coproc_rt_r_callback)
+ if (arm7_coproc_rt_w_callback)
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));
@@ -837,7 +856,7 @@ INLINE void HandleBranch(arm_state *cpustate, UINT32 insn)
static void HandleMemSingle(arm_state *cpustate, UINT32 insn)
{
- UINT32 rn, rnv, off, rd;
+ UINT32 rn, rnv, off, rd, rnv_old = 0;
/* Fetch the offset */
if (insn & INSN_I)
@@ -868,6 +887,7 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn)
if (insn & INSN_SDT_W)
{
+ rnv_old = GET_REGISTER(cpustate, rn);
SET_REGISTER(cpustate, rn, rnv);
// check writeback???
@@ -897,20 +917,27 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn)
/* Load */
if (insn & INSN_SDT_B)
{
- SET_REGISTER(cpustate, rd, (UINT32)READ8(rnv));
+ UINT32 data = READ8(rnv);
+ if (cpustate->pendingAbtD == 0)
+ {
+ SET_REGISTER(cpustate, rd, data);
+ }
}
else
{
- if (rd == eR15)
- {
- R15 = READ32(rnv);
- R15 -= 4;
- // LDR, PC takes 2S + 2N + 1I (5 total cycles)
- ARM7_ICOUNT -= 2;
- }
- else
+ UINT32 data = READ32(rnv);
+ if (cpustate->pendingAbtD == 0)
{
- SET_REGISTER(cpustate, rd, READ32(rnv));
+ if (rd == eR15)
+ {
+ R15 = data - 4;
+ // LDR, PC takes 2S + 2N + 1I (5 total cycles)
+ ARM7_ICOUNT -= 2;
+ }
+ else
+ {
+ SET_REGISTER(cpustate, rd, data);
+ }
}
}
}
@@ -940,6 +967,16 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn)
ARM7_ICOUNT += 1;
}
+ if (cpustate->pendingAbtD != 0)
+ {
+ if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W))
+ {
+ SET_REGISTER(cpustate, rn, rnv_old);
+ }
+ }
+ else
+ {
+
/* Do post-indexing writeback */
if (!(insn & INSN_SDT_P)/* && (insn & INSN_SDT_W)*/)
{
@@ -975,13 +1012,15 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn)
}
}
+ }
+
// ARM7_CHECKIRQ
} /* HandleMemSingle */
static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
{
- UINT32 rn, rnv, off, rd;
+ UINT32 rn, rnv, off, rd, rnv_old = 0;
// Immediate or Register Offset?
if (insn & 0x400000) { // Bit 22 - 1 = immediate, 0 = register
@@ -1010,6 +1049,7 @@ static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
if (insn & INSN_SDT_W)
{
+ rnv_old = GET_REGISTER(cpustate, rn);
SET_REGISTER(cpustate, rn, rnv);
// check writeback???
@@ -1059,6 +1099,9 @@ static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
newval = (UINT32)(signbyte << 8)|databyte;
}
+ if (cpustate->pendingAbtD == 0)
+ {
+
// PC?
if (rd == eR15)
{
@@ -1072,19 +1115,38 @@ static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
SET_REGISTER(cpustate, rd, newval);
R15 += 4;
}
+
+ }
+ else
+ {
+ R15 += 4;
+ }
+
}
// Unsigned Half Word
else
{
+ UINT32 newval = READ16(rnv);
+
+ if (cpustate->pendingAbtD == 0)
+ {
+
if (rd == eR15)
{
- R15 = READ16(rnv) + 8;
+ R15 = newval + 8;
}
else
{
- SET_REGISTER(cpustate, rd, READ16(rnv));
+ SET_REGISTER(cpustate, rd, newval);
R15 += 4;
}
+
+ }
+ else
+ {
+ R15 += 4;
+ }
+
}
@@ -1108,14 +1170,25 @@ static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
{
// WRITE16(rnv, rd == eR15 ? R15 + 8 : GET_REGISTER(cpustate, rd));
WRITE16(rnv, rd == eR15 ? R15 + 8 + 4 : GET_REGISTER(cpustate, rd)); // manual says STR RD=PC, +12 of address
- if (rn != eR15)
- R15 += 4;
+
+ // if R15 is not increased then e.g. "STRH R10, [R15,#$10]" will be executed over and over again
+ //if (rn != eR15)
+ R15 += 4;
+
// STRH takes 2 cycles, so we add + 1
ARM7_ICOUNT += 1;
}
}
-
+ if (cpustate->pendingAbtD != 0)
+ {
+ if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W))
+ {
+ SET_REGISTER(cpustate, rn, rnv_old);
+ }
+ }
+ else
+ {
// SJE: No idea if this writeback code works or makes sense here..
@@ -1153,6 +1226,9 @@ static void HandleHalfWordDT(arm_state *cpustate, UINT32 insn)
}
}
}
+
+ }
+
}
static void HandleSwap(arm_state *cpustate, UINT32 insn)
@@ -1411,12 +1487,17 @@ static void HandleALU(arm_state *cpustate, UINT32 insn)
else
{
// Rd = 15 and S Flag IS set, Result is placed in R15, and current mode SPSR moved to CPSR
- if (rdn == eR15) {
-
- // Update CPSR from SPSR
- SET_CPSR(GET_REGISTER(cpustate, SPSR));
- SwitchMode(cpustate, GET_MODE);
-
+ if (rdn == eR15)
+ {
+ // When Rd is R15 and the S flag is set the result of the operation is placed in R15 and the SPSR corresponding to
+ // the current mode is moved to the CPSR. This allows state changes which automatically restore both PC and
+ // CPSR. --> This form of instruction should not be used in User mode. <--
+ if (GET_MODE != eARM7_MODE_USER)
+ {
+ // Update CPSR from SPSR
+ SET_CPSR(GET_REGISTER(cpustate, SPSR));
+ SwitchMode(cpustate, GET_MODE);
+ }
R15 = rd;
/* IRQ masks may have changed in this instruction */
@@ -1567,9 +1648,6 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
LOG(("%08x: Unaligned Mem Transfer @ %08x\n", R15, rbp));
#endif
- // We will specify the cycle count for each case, so remove the -3 that occurs at the end
- ARM7_ICOUNT += 3;
-
if (insn & INSN_BDT_L)
{
/* Loading */
@@ -1595,7 +1673,7 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
else
result = loadInc(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
- if (insn & INSN_BDT_W)
+ if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
{
#if ARM7_DEBUG_CORE
if (rb == 15)
@@ -1605,16 +1683,18 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
}
// R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!)
- if (insn & 0x8000) {
+ if ((insn & 0x8000) && (cpustate->pendingAbtD == 0)) {
R15 -= 4; // SJE: I forget why i did this?
// S - Flag Set? Signals transfer of current mode SPSR->CPSR
- if (insn & INSN_BDT_S) {
+ if (insn & INSN_BDT_S)
+ {
SET_CPSR(GET_REGISTER(cpustate, SPSR));
SwitchMode(cpustate, GET_MODE);
}
+
+ // LDM PC - takes 1 extra cycle
+ ARM7_ICOUNT -= 1;
}
- // LDM PC - takes 1 extra cycle
- ARM7_ICOUNT -= 1;
}
else
{
@@ -1638,7 +1718,7 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
else
result = loadDec(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
- if (insn & INSN_BDT_W)
+ if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
{
if (rb == 0xf)
LOG(("%08x: Illegal LDRM writeback to r15\n", R15));
@@ -1646,10 +1726,11 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
}
// R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!)
- if (insn & 0x8000) {
+ if ((insn & 0x8000) && (cpustate->pendingAbtD == 0)) {
R15 -= 4; // SJE: I forget why i did this?
// S - Flag Set? Signals transfer of current mode SPSR->CPSR
- if (insn & INSN_BDT_S) {
+ if (insn & INSN_BDT_S)
+ {
SET_CPSR(GET_REGISTER(cpustate, SPSR));
SwitchMode(cpustate, GET_MODE);
}
@@ -1680,8 +1761,8 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
rbp = rbp + (- 4);
}
- // S Flag Set, but R15 not in list = User Bank Transfer
- if (insn & INSN_BDT_S && (insn & 0x8000) == 0)
+ // S Flag Set = User Bank Transfer
+ if (insn & INSN_BDT_S)
{
// todo: needs to be tested..
@@ -1696,7 +1777,7 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
else
result = storeInc(cpustate, insn & 0xffff, rbp);
- if (insn & INSN_BDT_W)
+ if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
{
SET_REGISTER(cpustate, rb, GET_REGISTER(cpustate, rb) + result * 4);
}
@@ -1709,8 +1790,8 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
rbp = rbp - (-4);
}
- // S Flag Set, but R15 not in list = User Bank Transfer
- if (insn & INSN_BDT_S && (insn & 0x8000) == 0)
+ // S Flag Set = User Bank Transfer
+ if (insn & INSN_BDT_S)
{
// set to user mode - then do the transfer, and set back
int curmode = GET_MODE;
@@ -1723,7 +1804,7 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
else
result = storeDec(cpustate, insn & 0xffff, rbp);
- if (insn & INSN_BDT_W)
+ if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
{
SET_REGISTER(cpustate, rb, GET_REGISTER(cpustate, rb) - result * 4);
}
@@ -1734,4 +1815,8 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
// STM takes (n+1)S+2N+1I cycles (n = # of register transfers)
ARM7_ICOUNT -= (result + 1) + 2 + 1;
}
+
+ // We will specify the cycle count for each case, so remove the -3 that occurs at the end
+ ARM7_ICOUNT += 3;
+
} /* HandleMemBlock */
diff --git a/src/emu/cpu/arm7/arm7core.h b/src/emu/cpu/arm7/arm7core.h
index 4d0a50f0404..fea3e8c7b67 100644
--- a/src/emu/cpu/arm7/arm7core.h
+++ b/src/emu/cpu/arm7/arm7core.h
@@ -136,10 +136,22 @@ enum
#define COPRO_CTRL_INTVEC_F 1
#define COPRO_CTRL_MASK 0x0000338f
+#define COPRO_DOMAIN_ACCESS_CONTROL cpustate->domainAccessControl
+
+#define COPRO_FAULT_STATUS cpustate->faultStatus
+
+#define COPRO_FAULT_ADDRESS cpustate->faultAddress
+
+#define COPRO_FCSE_PID cpustate->fcsePID
+
/* Coprocessor Registers */
#define ARM7COPRO_REGS \
UINT32 control; \
- UINT32 tlbBase;
+ UINT32 tlbBase; \
+ UINT32 faultStatus; \
+ UINT32 faultAddress; \
+ UINT32 fcsePID; \
+ UINT32 domainAccessControl;
enum
{
diff --git a/src/emu/cpu/arm7/arm7exec.c b/src/emu/cpu/arm7/arm7exec.c
index d1edb7a6d24..64cfa39fcb0 100644
--- a/src/emu/cpu/arm7/arm7exec.c
+++ b/src/emu/cpu/arm7/arm7exec.c
@@ -60,7 +60,11 @@
raddr = pc & (~1);
if ( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- raddr = arm7_tlb_translate(cpustate, raddr);
+ raddr = arm7_tlb_translate(cpustate, raddr, 1);
+ if (cpustate->pendingAbtP != 0)
+ {
+ goto skip_exec;
+ }
}
insn = cpustate->direct->read_decrypted_word(raddr);
ARM7_ICOUNT -= (3 - thumbCycles[insn >> 8]);
@@ -1170,7 +1174,11 @@
pc = R15;
if ( COPRO_CTRL & COPRO_CTRL_MMU_EN )
{
- pc = arm7_tlb_translate(cpustate, pc);
+ pc = arm7_tlb_translate(cpustate, pc, 1);
+ if (cpustate->pendingAbtP != 0)
+ {
+ goto skip_exec;
+ }
}
insn = cpustate->direct->read_decrypted_dword(pc);
@@ -1597,6 +1605,8 @@
}
}
+skip_exec:
+
ARM7_CHECKIRQ;
/* All instructions remove 3 cycles.. Others taking less / more will have adjusted this # prior to here */