summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/emu/cpu/arm7/arm7.c85
-rw-r--r--src/emu/cpu/arm7/arm7.h1
-rw-r--r--src/emu/cpu/arm7/arm7core.c211
-rw-r--r--src/emu/cpu/arm7/arm7core.h17
-rw-r--r--src/emu/cpu/arm7/arm7exec.c19
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 */