diff options
-rw-r--r-- | src/emu/cpu/arm7/arm7.c | 85 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7.h | 1 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7core.c | 211 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7core.h | 17 | ||||
-rw-r--r-- | src/emu/cpu/arm7/arm7exec.c | 19 |
5 files changed, 264 insertions, 69 deletions
diff --git a/src/emu/cpu/arm7/arm7.c b/src/emu/cpu/arm7/arm7.c index 11e6f48ede7..f6f7e608e35 100644 --- a/src/emu/cpu/arm7/arm7.c +++ b/src/emu/cpu/arm7/arm7.c @@ -71,10 +71,37 @@ void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*wr INLINE arm_state *get_safe_token(device_t *device) { assert(device != NULL); - assert(device->type() == ARM7 || device->type() == ARM7_BE || device->type() == ARM9 || device->type() == ARM920T || device->type() == PXA255); + assert(device->type() == ARM7 || device->type() == ARM7_BE || device->type() == ARM7500 || device->type() == ARM9 || device->type() == ARM920T || device->type() == PXA255); return (arm_state *)downcast<legacy_cpu_device *>(device)->token(); } +void set_cpsr( arm_state *cpustate, UINT32 val) +{ + if ((val & 0x10) != (ARM7REG(eCPSR) & 0x10)) + { + if (val & 0x10) + { + // 26 -> 32 + val = (val & 0x0FFFFF3F) | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; + R15 = R15 & 0x03FFFFFC; + } + else + { + // 32 -> 26 + R15 = (R15 & 0x03FFFFFC) /* PC */ | (val & 0xF0000000) /* N Z C V */ | ((val & 0x000000C0) << (26 - 6)) /* I F */ | (val & 0x00000003) /* M1 M0 */; + } + } + else + { + if (!(val & 0x10)) + { + // mirror bits in pc + R15 = (R15 & 0x03FFFFFF) | (val & 0xF0000000) /* N Z C V */ | ((val & 0x000000C0) << (26 - 6)) /* I F */; + } + } + ARM7REG(eCPSR) = val; +} + INLINE INT64 saturate_qbit_overflow(arm_state *cpustate, INT64 res) { if (res > 2147483647) // INT32_MAX @@ -128,8 +155,6 @@ INLINE UINT32 arm7_tlb_get_second_level_descriptor( arm_state *cpustate, UINT32 return cpustate->program->read_dword( desc_lvl2 ); } -static UINT32 r15_mmu_enable_addr = 1; - INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) { UINT32 desc_lvl1; @@ -151,15 +176,17 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) paddr = vaddr; - if ((R15 == (r15_mmu_enable_addr + 4)) || (R15 == (r15_mmu_enable_addr + 8))) +#if ARM7_MMU_ENABLE_HACK + if ((R15 == (cpustate->mmu_enable_addr + 4)) || (R15 == (cpustate->mmu_enable_addr + 8))) { LOG( ( "ARM7: fetch flat, PC = %08x, vaddr = %08x\n", R15, vaddr ) ); return vaddr; } else { - r15_mmu_enable_addr = 1; + cpustate->mmu_enable_addr = 1; } +#endif domain = (desc_lvl1 >> 5) & 0xF; permission = (COPRO_DOMAIN_ACCESS_CONTROL >> (domain << 1)) & 3; @@ -168,14 +195,14 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) { case COPRO_TLB_UNMAPPED: // Unmapped, generate a translation fault - if (mode == 0) + if (mode == ARM7_TLB_ABORT_D) { 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) + else if (mode == ARM7_TLB_ABORT_P) { LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) ); cpustate->pendingAbtP = 1; @@ -201,7 +228,7 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) } else { - if (mode == 0) + if (mode == ARM7_TLB_ABORT_D) { 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 ) ); @@ -209,7 +236,7 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) COPRO_FAULT_ADDRESS = vaddr; cpustate->pendingAbtD = 1; } - else if (mode == 1) + else if (mode == ARM7_TLB_ABORT_P) { 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 ) ); @@ -232,14 +259,14 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode) { case COPRO_TLB_UNMAPPED: // Unmapped, generate a translation fault - if (mode == 0) + if (mode == ARM7_TLB_ABORT_D) { 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) + else if (mode == ARM7_TLB_ABORT_P) { LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) ); cpustate->pendingAbtP = 1; @@ -274,7 +301,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, 2); + *address = arm7_tlb_translate(cpustate, *address, ARM7_TLB_NO_ABORT); } return TRUE; } @@ -325,6 +352,17 @@ static CPU_RESET( arm7_be ) cpustate->endian = ENDIANNESS_BIG; } +static CPU_RESET( arm7500 ) +{ + arm_state *cpustate = get_safe_token(device); + + // must call core reset + arm7_core_reset(device); + + cpustate->archRev = 3; // ARMv3 + cpustate->archFlags = 0; +} + static CPU_RESET( arm9 ) { arm_state *cpustate = get_safe_token(device); @@ -551,7 +589,7 @@ CPU_GET_INFO( arm7 ) case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* not implemented */ break; case CPUINFO_INT_PC: - case CPUINFO_INT_REGISTER + ARM7_PC: info->i = R15; break; + case CPUINFO_INT_REGISTER + ARM7_PC: info->i = GET_PC; break; case CPUINFO_INT_SP: info->i = GetRegister(cpustate, 13); break; /* FIRQ Mode Shadowed Registers */ @@ -616,7 +654,7 @@ CPU_GET_INFO( arm7 ) break; /* registers shared by all operating modes */ - case CPUINFO_STR_REGISTER + ARM7_PC: sprintf(info->s, "PC :%08x", R15); break; + case CPUINFO_STR_REGISTER + ARM7_PC: sprintf(info->s, "PC :%08x", GET_PC); break; case CPUINFO_STR_REGISTER + ARM7_R0: sprintf(info->s, "R0 :%08x", ARM7REG( 0)); break; case CPUINFO_STR_REGISTER + ARM7_R1: sprintf(info->s, "R1 :%08x", ARM7REG( 1)); break; case CPUINFO_STR_REGISTER + ARM7_R2: sprintf(info->s, "R2 :%08x", ARM7REG( 2)); break; @@ -679,6 +717,17 @@ CPU_GET_INFO( arm7_be ) } } +CPU_GET_INFO( arm7500 ) +{ + switch (state) + { + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(arm7500); break; + case DEVINFO_STR_NAME: strcpy(info->s, "ARM7500"); break; + default: CPU_GET_INFO_CALL(arm7); + break; + } +} + CPU_GET_INFO( arm9 ) { switch (state) @@ -808,6 +857,7 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback ) { data = 0x41 | (1 << 23) | (7 << 12); //data = (0x41 << 24) | (1 << 20) | (2 << 16) | (0x920 << 4) | (0 << 0); // ARM920T (S3C24xx) + //data = (0x41 << 24) | (0 << 20) | (1 << 16) | (0x710 << 4) | (0 << 0); // ARM7500 } break; @@ -935,14 +985,16 @@ 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 ARM7_MMU_ENABLE_HACK if (((data & COPRO_CTRL_MMU_EN) != 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) == 0)) { - r15_mmu_enable_addr = R15; + cpustate->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); + R15 = arm7_tlb_translate( cpustate, R15, ARM7_TLB_NO_ABORT); } +#endif COPRO_CTRL = data & COPRO_CTRL_MASK; break; case 2: // Translation Table Base @@ -995,6 +1047,7 @@ 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(ARM7500, arm7500); DEFINE_LEGACY_CPU_DEVICE(ARM9, arm9); DEFINE_LEGACY_CPU_DEVICE(ARM920T, arm920t); DEFINE_LEGACY_CPU_DEVICE(PXA255, pxa255); diff --git a/src/emu/cpu/arm7/arm7.h b/src/emu/cpu/arm7/arm7.h index 1deef008a22..c1d7cc11a12 100644 --- a/src/emu/cpu/arm7/arm7.h +++ b/src/emu/cpu/arm7/arm7.h @@ -40,6 +40,7 @@ DECLARE_LEGACY_CPU_DEVICE(ARM7, arm7); DECLARE_LEGACY_CPU_DEVICE(ARM7_BE, arm7_be); +DECLARE_LEGACY_CPU_DEVICE(ARM7500, arm7500); DECLARE_LEGACY_CPU_DEVICE(ARM9, arm9); DECLARE_LEGACY_CPU_DEVICE(ARM920T, arm920t); DECLARE_LEGACY_CPU_DEVICE(PXA255, pxa255); diff --git a/src/emu/cpu/arm7/arm7core.c b/src/emu/cpu/arm7/arm7core.c index 4b2cd61a55a..8c0d73cdc80 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } 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, 0 ); + addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D ); } // Handle through normal 8 bit handler (for 32 bit cpu) @@ -474,7 +474,12 @@ static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s) if (s) /* Pull full contents from stack */ SET_REGISTER(cpustate, 15, data); else /* Pull only address, preserve mode & status flags */ - SET_REGISTER(cpustate, 15, data); + if (MODE32) + SET_REGISTER(cpustate, 15, data); + else + { + SET_REGISTER(cpustate, 15, (GET_REGISTER(cpustate, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC)); + } } else SET_REGISTER(cpustate, i, data); @@ -501,7 +506,12 @@ static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s) if (s) /* Pull full contents from stack */ SET_REGISTER(cpustate, 15, data); else /* Pull only address, preserve mode & status flags */ - SET_REGISTER(cpustate, 15, data); + if (MODE32) + SET_REGISTER(cpustate, 15, data); + else + { + SET_REGISTER(cpustate, 15, (GET_REGISTER(cpustate, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC)); + } } else SET_REGISTER(cpustate, i, data); @@ -584,8 +594,8 @@ static void arm7_core_reset(legacy_cpu_device *device) cpustate->direct = &cpustate->program->direct(); /* start up in SVC mode with interrupts disabled. */ + ARM7REG(eCPSR) = I_MASK | F_MASK | 0x10; SwitchMode(cpustate, eARM7_MODE_SVC); - SET_CPSR(GET_CPSR | I_MASK | F_MASK | 0x10); R15 = 0; } @@ -611,6 +621,7 @@ static void arm7_check_irq_state(arm_state *cpustate) // Data Abort if (cpustate->pendingAbtD) { + if (MODE26) fatalerror( "pendingAbtD (todo)"); SwitchMode(cpustate, eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */ SET_REGISTER(cpustate, 14, pc - 8 + 8); /* save PC to R14 */ SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */ @@ -624,6 +635,7 @@ static void arm7_check_irq_state(arm_state *cpustate) // FIQ if (cpustate->pendingFiq && (cpsr & F_MASK) == 0) { + if (MODE26) fatalerror( "pendingFiq (todo)"); SwitchMode(cpustate, eARM7_MODE_FIQ); /* Set FIQ mode so PC is saved to correct R14 bank */ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */ SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */ @@ -637,17 +649,28 @@ static void arm7_check_irq_state(arm_state *cpustate) // 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 - 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 */ + SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */ + if (MODE32) + { + 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 */ + } + else + { + UINT32 temp; + R15 = (pc & 0xF4000000) /* N Z C V F */ | 0x18 | 0x00000002 /* IRQ */ | 0x08000000 /* I */; + temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; + SET_CPSR(temp); /* Mask IRQ */ + } if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; return; } // Prefetch Abort if (cpustate->pendingAbtP) { + if (MODE26) fatalerror( "pendingAbtP (todo)"); SwitchMode(cpustate, eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */ SET_REGISTER(cpustate, 14, pc - 4 + 4); /* save PC to R14 */ SET_REGISTER(cpustate, SPSR, cpsr); /* Save current CPSR */ @@ -661,7 +684,9 @@ static void arm7_check_irq_state(arm_state *cpustate) // Undefined instruction if (cpustate->pendingUnd) { + if (MODE26) fatalerror( "pendingUnd (todo)"); SwitchMode(cpustate, eARM7_MODE_UND); /* Set UND mode so PC is saved to correct R14 bank */ + // compensate for prefetch (should this also be done for normal IRQ?) if (T_IS_SET(GET_CPSR)) { SET_REGISTER(cpustate, 14, pc - 4 + 2); /* save PC to R14 */ @@ -691,10 +716,21 @@ static void arm7_check_irq_state(arm_state *cpustate) { 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 (MODE32) + { + 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 */ + } + else + { + UINT32 temp; + R15 = (pc & 0xF4000000) /* N Z C V F */ | 0x08 | 0x00000003 /* SVC */ | 0x08000000 /* I */; + temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; + SET_CPSR(temp); /* Mask IRQ */ + } + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; cpustate->pendingSwi = 0; return; @@ -846,11 +882,17 @@ INLINE void HandleBranch(arm_state *cpustate, UINT32 insn) /* Sign-extend the 24-bit offset in our calculations */ if (off & 0x2000000u) { - R15 -= ((~(off | 0xfc000000u)) + 1) - 8; + if (MODE32) + R15 -= ((~(off | 0xfc000000u)) + 1) - 8; + else + R15 = ((R15 - (((~(off | 0xfc000000u)) + 1) - 8)) & 0x03FFFFFC) | (R15 & ~0x03FFFFFC); } else { - R15 += off + 8; + if (MODE32) + R15 += off + 8; + else + R15 = ((R15 + (off + 8)) & 0x03FFFFFC) | (R15 & ~0x03FFFFFC); } } @@ -878,11 +920,17 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn) /* Pre-indexed addressing */ if (insn & INSN_SDT_U) { - rnv = (GET_REGISTER(cpustate, rn) + off); + if ((MODE32) || (rn != eR15)) + rnv = (GET_REGISTER(cpustate, rn) + off); + else + rnv = (GET_PC + off); } else { - rnv = (GET_REGISTER(cpustate, rn) - off); + if ((MODE32) || (rn != eR15)) + rnv = (GET_REGISTER(cpustate, rn) - off); + else + rnv = (GET_PC - off); } if (insn & INSN_SDT_W) @@ -902,7 +950,10 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn) /* Post-indexed addressing */ if (rn == eR15) { - rnv = R15 + 8; + if (MODE32) + rnv = R15 + 8; + else + rnv = GET_PC + 8; } else { @@ -930,8 +981,11 @@ static void HandleMemSingle(arm_state *cpustate, UINT32 insn) { if (rd == eR15) { - R15 = data - 4; - // LDR, PC takes 2S + 2N + 1I (5 total cycles) + if (MODE32) + R15 = data - 4; + else + R15 = (R15 & ~0x03FFFFFC) /* N Z C V I F M1 M0 */ | ((data - 4) & 0x03FFFFFC); + // LDR, PC takes 2S + 2N + 1I (5 total cycles) ARM7_ICOUNT -= 2; } else @@ -1171,9 +1225,11 @@ 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 R15 is not increased then e.g. "STRH R10, [R15,#$10]" will be executed over and over again - //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 0 + if (rn != eR15) +#endif + R15 += 4; // STRH takes 2 cycles, so we add + 1 ARM7_ICOUNT += 1; @@ -1340,11 +1396,16 @@ static void HandlePSRTransfer(arm_state *cpustate, UINT32 insn) } } +#if 0 // force valid mode newval |= 0x10; +#endif // Update the Register - SET_REGISTER(cpustate, reg, newval); + if (reg == eCPSR) + SET_CPSR(newval); + else + SET_REGISTER(cpustate, reg, newval); // Switch to new mode if changed if ((newval & MODE_FLAG) != oldmode) @@ -1406,7 +1467,10 @@ static void HandleALU(arm_state *cpustate, UINT32 insn) #if ARM7_DEBUG_CORE LOG(("%08x: Pipelined R15 (Shift %d)\n", R15, (insn & INSN_I ? 8 : insn & 0x10u ? 12 : 12))); #endif - rn = R15 + 8; + if (MODE32) + rn = R15 + 8; + else + rn = GET_PC + 8; } else { @@ -1482,24 +1546,45 @@ static void HandleALU(arm_state *cpustate, UINT32 insn) // If Rd = R15, but S Flag not set, Result is placed in R15, but CPSR is not affected (page 44) if (rdn == eR15 && !(insn & INSN_S)) { - R15 = rd; + if (MODE32) + { + R15 = rd; + } + else + { + R15 = (R15 & ~0x03FFFFFC) | (rd & 0x03FFFFFC); + } } else { // Rd = 15 and S Flag IS set, Result is placed in R15, and current mode SPSR moved to CPSR - 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 (rdn == eR15) { + + if (MODE32) + { + // 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); - } + // Update CPSR from SPSR + SET_CPSR(GET_REGISTER(cpustate, SPSR)); + SwitchMode(cpustate, GET_MODE); + } + R15 = rd; + } + else + { + UINT32 temp; + R15 = rd; //(R15 & 0x03FFFFFC) | (rd & 0xFC000003); + temp = (GET_CPSR & 0x0FFFFF20) | (rd & 0xF0000000) /* N Z C V */ | ((rd & 0x0C000000) >> (26 - 6)) /* I F */ | (rd & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode( cpustate, temp & 3); + } + /* IRQ masks may have changed in this instruction */ // ARM7_CHECKIRQ; } @@ -1516,7 +1601,16 @@ static void HandleALU(arm_state *cpustate, UINT32 insn) #if ARM7_DEBUG_CORE LOG(("%08x: TST class on R15 s bit set\n", R15)); #endif - R15 = rd; + if (MODE32) + R15 = rd; + else + { + UINT32 temp; + R15 = (R15 & 0x03FFFFFC) | (rd & ~0x03FFFFFC); + temp = (GET_CPSR & 0x0FFFFF20) | (rd & 0xF0000000) /* N Z C V */ | ((rd & 0x0C000000) >> (26 - 6)) /* I F */ | (rd & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode( cpustate, temp & 3); + } /* IRQ masks may have changed in this instruction */ // ARM7_CHECKIRQ; @@ -1688,12 +1782,22 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn) // S - Flag Set? Signals transfer of current mode SPSR->CPSR if (insn & INSN_BDT_S) { - SET_CPSR(GET_REGISTER(cpustate, SPSR)); - SwitchMode(cpustate, GET_MODE); + if (MODE32) + { + SET_CPSR(GET_REGISTER(cpustate, SPSR)); + SwitchMode(cpustate, GET_MODE); + } + else + { + UINT32 temp; +// LOG(("LDM + S | R15 %08X CPSR %08X\n", R15, GET_CPSR)); + temp = (GET_CPSR & 0x0FFFFF20) | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */ | (R15 & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode(cpustate, temp & 3); + } } - - // LDM PC - takes 1 extra cycle - ARM7_ICOUNT -= 1; + // LDM PC - takes 1 extra cycle + ARM7_ICOUNT -= 1; } } else @@ -1731,8 +1835,19 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn) // S - Flag Set? Signals transfer of current mode SPSR->CPSR if (insn & INSN_BDT_S) { - SET_CPSR(GET_REGISTER(cpustate, SPSR)); - SwitchMode(cpustate, GET_MODE); + if (MODE32) + { + SET_CPSR(GET_REGISTER(cpustate, SPSR)); + SwitchMode(cpustate, GET_MODE); + } + else + { + UINT32 temp; +// LOG(("LDM + S | R15 %08X CPSR %08X\n", R15, GET_CPSR)); + temp = (GET_CPSR & 0x0FFFFF20) /* N Z C V I F M4 M3 M2 M1 M0 */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */ | (R15 & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode(cpustate, temp & 3); + } } // LDM PC - takes 1 extra cycle ARM7_ICOUNT -= 1; diff --git a/src/emu/cpu/arm7/arm7core.h b/src/emu/cpu/arm7/arm7core.h index fea3e8c7b67..fd82bbbdffa 100644 --- a/src/emu/cpu/arm7/arm7core.h +++ b/src/emu/cpu/arm7/arm7core.h @@ -33,6 +33,7 @@ #ifndef __ARM7CORE_H__ #define __ARM7CORE_H__ +#define ARM7_MMU_ENABLE_HACK 0 /**************************************************************************************************** * INTERRUPT LINES/EXCEPTIONS @@ -188,6 +189,9 @@ typedef struct UINT8 archRev; // ARM architecture revision (3, 4, and 5 are valid) UINT8 archFlags; // architecture flags +#if ARM7_MMU_ENABLE_HACK + UINT32 mmu_enable_addr; // workaround for "MMU is enabled when PA != VA" problem +#endif } arm_state; /**************************************************************************************************** @@ -485,7 +489,7 @@ enum #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 SET_CPSR(v) set_cpsr(cpustate,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)) @@ -494,6 +498,17 @@ enum #define THUMB_SIGN_BIT ((UINT32)(1 << 31)) #define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31) +#define MODE32 (GET_CPSR & 0x10) +#define MODE26 (!(GET_CPSR & 0x10)) +#define GET_PC (MODE32 ? R15 : R15 & 0x03FFFFFC) + +enum +{ + ARM7_TLB_NO_ABORT, + ARM7_TLB_ABORT_D, + ARM7_TLB_ABORT_P +}; + /* At one point I thought these needed to be cpu implementation specific, but they don't.. */ #define GET_REGISTER(state, reg) GetRegister(state, reg) #define SET_REGISTER(state, reg, val) SetRegister(state, reg, val) diff --git a/src/emu/cpu/arm7/arm7exec.c b/src/emu/cpu/arm7/arm7exec.c index 64cfa39fcb0..1db86c46c81 100644 --- a/src/emu/cpu/arm7/arm7exec.c +++ b/src/emu/cpu/arm7/arm7exec.c @@ -47,7 +47,7 @@ do { - debugger_instruction_hook(cpustate->device, R15); + debugger_instruction_hook(cpustate->device, GET_PC); /* handle Thumb instructions if active */ if (T_IS_SET(GET_CPSR)) @@ -60,7 +60,7 @@ raddr = pc & (~1); if ( COPRO_CTRL & COPRO_CTRL_MMU_EN ) { - raddr = arm7_tlb_translate(cpustate, raddr, 1); + raddr = arm7_tlb_translate(cpustate, raddr, ARM7_TLB_ABORT_P); if (cpustate->pendingAbtP != 0) { goto skip_exec; @@ -1171,15 +1171,26 @@ { /* load 32 bit instruction */ - pc = R15; + pc = GET_PC; if ( COPRO_CTRL & COPRO_CTRL_MMU_EN ) { - pc = arm7_tlb_translate(cpustate, pc, 1); + pc = arm7_tlb_translate(cpustate, pc, ARM7_TLB_ABORT_P); if (cpustate->pendingAbtP != 0) { goto skip_exec; } } + +#if 0 + if (MODE26) + { + UINT32 temp1, temp2; + temp1 = GET_CPSR & 0xF00000C3; + temp2 = (R15 & 0xF0000000) | ((R15 & 0x0C000000) >> (26 - 6)) | (R15 & 0x00000003); + if (temp1 != temp2) fatalerror( "%08X: 32-bit and 26-bit modes are out of sync (%08X %08X)", pc, temp1, temp2); + } +#endif + insn = cpustate->direct->read_decrypted_dword(pc); /* process condition codes for this instruction */ |