diff options
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 |
commit | 3517c80e37c3945b1c7e1e7b96756a82fcefa66b (patch) | |
tree | 95152b5e33490f84e12655e0c5f90e1ca3aa2ac1 | |
parent | e25860ffdcf67126ee46150947022dd423e6a176 (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.c | 143 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7.h | 1 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7core.c | 205 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7core.h | 14 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7exec.c | 14 |
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 */ |