mirror of
https://github.com/holub/mame
synced 2025-05-23 06:08:48 +03:00
arm7: implemented MMU permission faults [Tim Schuerewegen]
arm7: return correct MMU ID Code register values for ARM920T/ARM7500 [Tim Schuerewegen]
This commit is contained in:
parent
6fe73755b8
commit
08e03939c9
@ -135,6 +135,13 @@ enum
|
||||
TLB_FINE,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FAULT_NONE = 0,
|
||||
FAULT_DOMAIN,
|
||||
FAULT_PERMISSION,
|
||||
};
|
||||
|
||||
INLINE UINT32 arm7_tlb_get_first_level_descriptor( arm_state *cpustate, UINT32 vaddr )
|
||||
{
|
||||
UINT32 entry_paddr = ( COPRO_TLB_BASE & COPRO_TLB_BASE_MASK ) | ( ( vaddr & COPRO_TLB_VADDR_FLTI_MASK ) >> COPRO_TLB_VADDR_FLTI_MASK_SHIFT );
|
||||
@ -162,11 +169,96 @@ 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, int mode)
|
||||
INLINE int detect_fault( arm_state *cpustate, int permission, int ap, int flags)
|
||||
{
|
||||
switch (permission)
|
||||
{
|
||||
case 0 : // "No access - Any access generates a domain fault"
|
||||
{
|
||||
return FAULT_DOMAIN;
|
||||
}
|
||||
break;
|
||||
case 1 : // "Client - Accesses are checked against the access permission bits in the section or page descriptor"
|
||||
{
|
||||
switch (ap)
|
||||
{
|
||||
case 0 :
|
||||
{
|
||||
int s = (COPRO_CTRL & COPRO_CTRL_SYSTEM) ? 1 : 0;
|
||||
int r = (COPRO_CTRL & COPRO_CTRL_ROM) ? 1 : 0;
|
||||
if (s == 0)
|
||||
{
|
||||
if (r == 0) // "Any access generates a permission fault"
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
else // "Any write generates a permission fault"
|
||||
{
|
||||
if (flags & ARM7_TLB_WRITE)
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r == 0) // "Only Supervisor read permitted"
|
||||
{
|
||||
if ((GET_MODE == eARM7_MODE_USER) || (flags & ARM7_TLB_WRITE))
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
}
|
||||
else // "Reserved" -> assume same behaviour as S=0/R=0 case
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1 : // "Access allowed only in Supervisor mode"
|
||||
{
|
||||
if (GET_MODE == eARM7_MODE_USER)
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2 : // "Writes in User mode cause permission fault"
|
||||
{
|
||||
if ((GET_MODE == eARM7_MODE_USER) && (flags & ARM7_TLB_WRITE))
|
||||
{
|
||||
return FAULT_PERMISSION;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3 : // "All access types permitted in both modes"
|
||||
{
|
||||
return FAULT_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2 : // "Reserved - Reserved. Currently behaves like the no access mode"
|
||||
{
|
||||
return FAULT_DOMAIN;
|
||||
}
|
||||
break;
|
||||
case 3 : // "Manager - Accesses are not checked against the access permission bits so a permission fault cannot be generated"
|
||||
{
|
||||
return FAULT_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FAULT_NONE;
|
||||
}
|
||||
|
||||
INLINE int arm7_tlb_translate(arm_state *cpustate, UINT32 *addr, int flags)
|
||||
{
|
||||
UINT32 desc_lvl1;
|
||||
UINT32 desc_lvl2 = 0;
|
||||
UINT32 paddr;
|
||||
UINT32 paddr, vaddr = *addr;
|
||||
UINT8 domain, permission;
|
||||
|
||||
if (vaddr < 32 * 1024 * 1024)
|
||||
@ -187,7 +279,8 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
|
||||
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;
|
||||
*addr = vaddr;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -202,58 +295,64 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
|
||||
{
|
||||
case COPRO_TLB_UNMAPPED:
|
||||
// Unmapped, generate a translation fault
|
||||
if (mode == ARM7_TLB_ABORT_D)
|
||||
if (flags & 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);
|
||||
LOG( ( "ARM7: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
|
||||
COPRO_FAULT_STATUS_D = (5 << 0); // 5 = section translation fault
|
||||
COPRO_FAULT_ADDRESS = vaddr;
|
||||
cpustate->pendingAbtD = 1;
|
||||
}
|
||||
else if (mode == ARM7_TLB_ABORT_P)
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
|
||||
LOG( ( "ARM7: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
|
||||
cpustate->pendingAbtP = 1;
|
||||
}
|
||||
return FALSE;
|
||||
break;
|
||||
case COPRO_TLB_COARSE_TABLE:
|
||||
// Entry is the physical address of a coarse second-level table
|
||||
if (permission == 1)
|
||||
if ((permission == 1) || (permission == 3))
|
||||
{
|
||||
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 ) );
|
||||
fatalerror("ARM7: Not Yet Implemented: Coarse Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x", vaddr, domain, R15);
|
||||
}
|
||||
break;
|
||||
case COPRO_TLB_SECTION_TABLE:
|
||||
{
|
||||
// Entry is a section
|
||||
if ((permission == 1) || (permission == 3))
|
||||
UINT8 ap = (desc_lvl1 >> 10) & 3;
|
||||
int fault = detect_fault( cpustate, permission, ap, flags);
|
||||
if (fault == FAULT_NONE)
|
||||
{
|
||||
paddr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SECTION_PAGE_MASK );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == ARM7_TLB_ABORT_D)
|
||||
if (flags & 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 ) );
|
||||
COPRO_FAULT_STATUS = (9 << 0);
|
||||
LOG( ( "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, R15 ) );
|
||||
COPRO_FAULT_STATUS_D = ((fault == FAULT_DOMAIN) ? (9 << 0) : (13 << 0)) | (domain << 4); // 9 = section domain fault, 13 = section permission fault
|
||||
COPRO_FAULT_ADDRESS = vaddr;
|
||||
cpustate->pendingAbtD = 1;
|
||||
LOG( ( "vaddr %08X desc_lvl1 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n",
|
||||
vaddr, desc_lvl1, domain, permission, ap, (COPRO_CTRL & COPRO_CTRL_SYSTEM) ? 1 : 0, (COPRO_CTRL & COPRO_CTRL_ROM) ? 1 : 0,
|
||||
GET_MODE, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0) );
|
||||
}
|
||||
else if (mode == ARM7_TLB_ABORT_P)
|
||||
else if (flags & 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 ) );
|
||||
LOG( ( "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, R15 ) );
|
||||
cpustate->pendingAbtP = 1;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COPRO_TLB_FINE_TABLE:
|
||||
// Entry is the physical address of a fine second-level table
|
||||
LOG( ( "ARM7: Not Yet Implemented: fine second-level TLB lookup, PC = %08x, vaddr = %08x\n", R15, vaddr ) );
|
||||
fatalerror("ARM7: Not Yet Implemented: fine second-level TLB lookup, PC = %08x, vaddr = %08x", R15, vaddr);
|
||||
break;
|
||||
default:
|
||||
// Entry is the physical address of a three-legged termite-eaten table
|
||||
@ -266,18 +365,19 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
|
||||
{
|
||||
case COPRO_TLB_UNMAPPED:
|
||||
// Unmapped, generate a translation fault
|
||||
if (mode == ARM7_TLB_ABORT_D)
|
||||
if (flags & 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);
|
||||
LOG( ( "ARM7: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) );
|
||||
COPRO_FAULT_STATUS_D = (7 << 0) | (domain << 4); // 7 = page translation fault
|
||||
COPRO_FAULT_ADDRESS = vaddr;
|
||||
cpustate->pendingAbtD = 1;
|
||||
}
|
||||
else if (mode == ARM7_TLB_ABORT_P)
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOG( ( "ARM7: Not Yet Implemented: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) );
|
||||
LOG( ( "ARM7: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, R15 ) );
|
||||
cpustate->pendingAbtP = 1;
|
||||
}
|
||||
return FALSE;
|
||||
break;
|
||||
case COPRO_TLB_LARGE_PAGE:
|
||||
// Large page descriptor
|
||||
@ -285,7 +385,34 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
|
||||
break;
|
||||
case COPRO_TLB_SMALL_PAGE:
|
||||
// Small page descriptor
|
||||
paddr = ( desc_lvl2 & COPRO_TLB_SMALL_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SMALL_PAGE_MASK );
|
||||
{
|
||||
UINT8 ap = ((((desc_lvl2 >> 4) & 0xFF) >> (((vaddr >> 10) & 3) << 1)) & 3);
|
||||
int fault = detect_fault( cpustate, permission, ap, flags);
|
||||
if (fault == FAULT_NONE)
|
||||
{
|
||||
paddr = ( desc_lvl2 & COPRO_TLB_SMALL_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SMALL_PAGE_MASK );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
// hapyfish expects a data abort when something tries to write to a read-only memory location from user mode
|
||||
LOG( ( "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, R15 ) );
|
||||
COPRO_FAULT_STATUS_D = ((fault == FAULT_DOMAIN) ? (11 << 0) : (15 << 0)) | (domain << 4); // 11 = page domain fault, 15 = page permission fault
|
||||
COPRO_FAULT_ADDRESS = vaddr;
|
||||
cpustate->pendingAbtD = 1;
|
||||
LOG( ( "vaddr %08X desc_lvl2 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n",
|
||||
vaddr, desc_lvl2, domain, permission, ap, (COPRO_CTRL & COPRO_CTRL_SYSTEM) ? 1 : 0, (COPRO_CTRL & COPRO_CTRL_ROM) ? 1 : 0,
|
||||
GET_MODE, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0) );
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOG( ( "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, R15 ) );
|
||||
cpustate->pendingAbtP = 1;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COPRO_TLB_TINY_PAGE:
|
||||
// Tiny page descriptor
|
||||
@ -297,8 +424,8 @@ INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr, int mode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return paddr;
|
||||
*addr = paddr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static CPU_TRANSLATE( arm7 )
|
||||
@ -308,7 +435,7 @@ static CPU_TRANSLATE( arm7 )
|
||||
/* only applies to the program address space and only does something if the MMU's enabled */
|
||||
if( space == AS_PROGRAM && ( COPRO_CTRL & COPRO_CTRL_MMU_EN ) )
|
||||
{
|
||||
*address = arm7_tlb_translate(cpustate, *address, ARM7_TLB_NO_ABORT);
|
||||
return arm7_tlb_translate(cpustate, address, 0);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@ -783,6 +910,8 @@ CPU_GET_INFO( sa1110 )
|
||||
|
||||
static WRITE32_DEVICE_HANDLER( arm7_do_callback )
|
||||
{
|
||||
arm_state *cpustate = get_safe_token(device);
|
||||
cpustate->pendingUnd = 1;
|
||||
}
|
||||
|
||||
static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
|
||||
@ -791,7 +920,7 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
|
||||
UINT32 opcode = offset;
|
||||
UINT8 cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT;
|
||||
UINT8 op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT;
|
||||
// UINT8 op3 = opcode & INSN_COPRO_OP3;
|
||||
UINT8 op3 = opcode & INSN_COPRO_OP3;
|
||||
UINT8 cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT;
|
||||
UINT32 data = 0;
|
||||
|
||||
@ -862,9 +991,18 @@ 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)
|
||||
//data = (0x41 << 24) | (0 << 20) | (1 << 16) | (0x710 << 4) | (0 << 0); // ARM7500
|
||||
if (device->type() == ARM920T)
|
||||
{
|
||||
data = (0x41 << 24) | (1 << 20) | (2 << 16) | (0x920 << 4) | (0 << 0); // ARM920T (S3C24xx)
|
||||
}
|
||||
else if (device->type() == ARM7500)
|
||||
{
|
||||
data = (0x41 << 24) | (0 << 20) | (1 << 16) | (0x710 << 4) | (0 << 0); // ARM7500
|
||||
}
|
||||
else
|
||||
{
|
||||
data = 0x41 | (1 << 23) | (7 << 12); // <-- where did this come from?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -923,7 +1061,11 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
|
||||
break;
|
||||
case 5: // Fault Status
|
||||
LOG( ( "arm7_rt_r_callback, Fault Status\n" ) );
|
||||
data = COPRO_FAULT_STATUS;
|
||||
switch (op3)
|
||||
{
|
||||
case 0: data = COPRO_FAULT_STATUS_D; break;
|
||||
case 1: data = COPRO_FAULT_STATUS_P; break;
|
||||
}
|
||||
break;
|
||||
case 6: // Fault Address
|
||||
LOG( ( "arm7_rt_r_callback, Fault Address\n" ) );
|
||||
@ -966,7 +1108,9 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
|
||||
}
|
||||
else
|
||||
{
|
||||
fatalerror("ARM7: Unhandled coprocessor %d\n", cpnum);
|
||||
LOG( ("ARM7: Unhandled coprocessor %d\n", cpnum) );
|
||||
cpustate->pendingUnd = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -999,7 +1143,10 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
|
||||
}
|
||||
if (((data & COPRO_CTRL_MMU_EN) == 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) != 0))
|
||||
{
|
||||
R15 = arm7_tlb_translate( cpustate, R15, ARM7_TLB_NO_ABORT);
|
||||
if (!arm7_tlb_translate( cpustate, &R15, 0))
|
||||
{
|
||||
fatalerror("ARM7_MMU_ENABLE_HACK translate failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
COPRO_CTRL = data & COPRO_CTRL_MASK;
|
||||
@ -1014,7 +1161,11 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
|
||||
break;
|
||||
case 5: // Fault Status
|
||||
LOG( ( "arm7_rt_w_callback Fault Status = %08x (%d) (%d)\n", data, op2, op3 ) );
|
||||
COPRO_FAULT_STATUS = data;
|
||||
switch (op3)
|
||||
{
|
||||
case 0: COPRO_FAULT_STATUS_D = data; break;
|
||||
case 1: COPRO_FAULT_STATUS_P = data; break;
|
||||
}
|
||||
break;
|
||||
case 6: // Fault Address
|
||||
LOG( ( "arm7_rt_w_callback Fault Address = %08x (%d) (%d)\n", data, op2, op3 ) );
|
||||
@ -1046,10 +1197,12 @@ static WRITE32_DEVICE_HANDLER( arm7_rt_w_callback )
|
||||
|
||||
void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr))
|
||||
{
|
||||
cpustate->pendingUnd = 1;
|
||||
}
|
||||
|
||||
void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data))
|
||||
{
|
||||
cpustate->pendingUnd = 1;
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_CPU_DEVICE(ARM7, arm7);
|
||||
|
@ -105,7 +105,7 @@ INLINE void arm7_cpu_write16(arm_state *cpustate, UINT32 addr, UINT16 data);
|
||||
INLINE void arm7_cpu_write8(arm_state *cpustate, UINT32 addr, UINT8 data);
|
||||
INLINE UINT32 arm7_cpu_read32(arm_state *cpustate, UINT32 addr);
|
||||
INLINE UINT16 arm7_cpu_read16(arm_state *cpustate, UINT32 addr);
|
||||
INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, offs_t addr);
|
||||
INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, UINT32 addr);
|
||||
|
||||
/* Static Vars */
|
||||
// Note: for multi-cpu implementation, this approach won't work w/o modification
|
||||
@ -131,7 +131,10 @@ 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, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addr &= ~3;
|
||||
@ -146,7 +149,10 @@ 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, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addr &= ~1;
|
||||
@ -160,7 +166,10 @@ 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, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( cpustate->endian == ENDIANNESS_BIG )
|
||||
@ -169,13 +178,16 @@ INLINE void arm7_cpu_write8(arm_state *cpustate, UINT32 addr, UINT8 data)
|
||||
cpustate->program->write_byte(addr, data);
|
||||
}
|
||||
|
||||
INLINE UINT32 arm7_cpu_read32(arm_state *cpustate, offs_t addr)
|
||||
INLINE UINT32 arm7_cpu_read32(arm_state *cpustate, UINT32 addr)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr & 3)
|
||||
@ -197,13 +209,16 @@ INLINE UINT32 arm7_cpu_read32(arm_state *cpustate, offs_t addr)
|
||||
return result;
|
||||
}
|
||||
|
||||
INLINE UINT16 arm7_cpu_read16(arm_state *cpustate, offs_t addr)
|
||||
INLINE UINT16 arm7_cpu_read16(arm_state *cpustate, UINT32 addr)
|
||||
{
|
||||
UINT16 result;
|
||||
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( cpustate->endian == ENDIANNESS_BIG )
|
||||
@ -219,11 +234,14 @@ INLINE UINT16 arm7_cpu_read16(arm_state *cpustate, offs_t addr)
|
||||
return result;
|
||||
}
|
||||
|
||||
INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, offs_t addr)
|
||||
INLINE UINT8 arm7_cpu_read8(arm_state *cpustate, UINT32 addr)
|
||||
{
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
addr = arm7_tlb_translate( cpustate, addr, ARM7_TLB_ABORT_D );
|
||||
if (!arm7_tlb_translate( cpustate, &addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle through normal 8 bit handler (for 32 bit cpu)
|
||||
@ -310,6 +328,9 @@ static const char *GetModeText(int cpsr)
|
||||
#define GetRegister(cpustate, rIndex) ARM7REG(sRegisterTable[GET_MODE][rIndex])
|
||||
#define SetRegister(cpustate, rIndex, value) ARM7REG(sRegisterTable[GET_MODE][rIndex]) = value
|
||||
|
||||
#define GetModeRegister(cpustate, mode, rIndex) ARM7REG(sRegisterTable[mode][rIndex])
|
||||
#define SetModeRegister(cpustate, mode, rIndex, value) ARM7REG(sRegisterTable[mode][rIndex]) = value
|
||||
|
||||
// I could prob. convert to macro, but Switchmode shouldn't occur that often in emulated code..
|
||||
INLINE void SwitchMode(arm_state *cpustate, int cpsr_mode_val)
|
||||
{
|
||||
@ -458,7 +479,7 @@ static UINT32 decodeShift(arm_state *cpustate, UINT32 insn, UINT32 *pCarry)
|
||||
} /* decodeShift */
|
||||
|
||||
|
||||
static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
|
||||
static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s, int mode)
|
||||
{
|
||||
int i, result;
|
||||
UINT32 data;
|
||||
@ -469,28 +490,29 @@ static int loadInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
|
||||
{
|
||||
if ((pat >> i) & 1)
|
||||
{
|
||||
if (cpustate->pendingAbtD == 0) // "Overwriting of registers stops when the abort happens."
|
||||
{
|
||||
data = READ32(rbv += 4);
|
||||
if (cpustate->pendingAbtD != 0) break;
|
||||
if (i == 15) {
|
||||
if (s) /* Pull full contents from stack */
|
||||
SET_REGISTER(cpustate, 15, data);
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, data);
|
||||
else /* Pull only address, preserve mode & status flags */
|
||||
if (MODE32)
|
||||
SET_REGISTER(cpustate, 15, data);
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, data);
|
||||
else
|
||||
{
|
||||
SET_REGISTER(cpustate, 15, (GET_REGISTER(cpustate, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC));
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, (GET_MODE_REGISTER(cpustate, mode, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC));
|
||||
}
|
||||
} else
|
||||
SET_REGISTER(cpustate, i, data);
|
||||
|
||||
SET_MODE_REGISTER(cpustate, mode, i, data);
|
||||
}
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
|
||||
static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s, int mode)
|
||||
{
|
||||
int i, result;
|
||||
UINT32 data;
|
||||
@ -501,28 +523,30 @@ static int loadDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, UINT32 s)
|
||||
{
|
||||
if ((pat >> i) & 1)
|
||||
{
|
||||
if (cpustate->pendingAbtD == 0) // "Overwriting of registers stops when the abort happens."
|
||||
{
|
||||
data = READ32(rbv -= 4);
|
||||
if (cpustate->pendingAbtD != 0) break;
|
||||
if (i == 15) {
|
||||
if (s) /* Pull full contents from stack */
|
||||
SET_REGISTER(cpustate, 15, data);
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, data);
|
||||
else /* Pull only address, preserve mode & status flags */
|
||||
if (MODE32)
|
||||
SET_REGISTER(cpustate, 15, data);
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, data);
|
||||
else
|
||||
{
|
||||
SET_REGISTER(cpustate, 15, (GET_REGISTER(cpustate, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC));
|
||||
SET_MODE_REGISTER(cpustate, mode, 15, (GET_MODE_REGISTER(cpustate, mode, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC));
|
||||
}
|
||||
}
|
||||
else
|
||||
SET_REGISTER(cpustate, i, data);
|
||||
SET_MODE_REGISTER(cpustate, mode, i, data);
|
||||
}
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int storeInc(arm_state *cpustate, UINT32 pat, UINT32 rbv)
|
||||
static int storeInc(arm_state *cpustate, UINT32 pat, UINT32 rbv, int mode)
|
||||
{
|
||||
int i, result;
|
||||
|
||||
@ -535,14 +559,14 @@ static int storeInc(arm_state *cpustate, UINT32 pat, UINT32 rbv)
|
||||
if (i == 15) /* R15 is plus 12 from address of STM */
|
||||
LOG(("%08x: StoreInc on R15\n", R15));
|
||||
#endif
|
||||
WRITE32(rbv += 4, GET_REGISTER(cpustate, i));
|
||||
WRITE32(rbv += 4, GET_MODE_REGISTER(cpustate, mode, i));
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} /* storeInc */
|
||||
|
||||
static int storeDec(arm_state *cpustate, UINT32 pat, UINT32 rbv)
|
||||
static int storeDec(arm_state *cpustate, UINT32 pat, UINT32 rbv, int mode)
|
||||
{
|
||||
int i, result;
|
||||
|
||||
@ -555,7 +579,7 @@ static int storeDec(arm_state *cpustate, UINT32 pat, UINT32 rbv)
|
||||
if (i == 15) /* R15 is plus 12 from address of STM */
|
||||
LOG(("%08x: StoreDec on R15\n", R15));
|
||||
#endif
|
||||
WRITE32(rbv -= 4, GET_REGISTER(cpustate, i));
|
||||
WRITE32(rbv -= 4, GET_MODE_REGISTER(cpustate, mode, i));
|
||||
result++;
|
||||
}
|
||||
}
|
||||
@ -791,7 +815,10 @@ static void HandleCoProcRT(arm_state *cpustate, UINT32 insn)
|
||||
if (arm7_coproc_rt_r_callback)
|
||||
{
|
||||
UINT32 res = arm7_coproc_rt_r_callback(cpustate->device, insn, 0); // RT Read handler must parse opcode & return appropriate result
|
||||
SET_REGISTER(cpustate, (insn >> 12) & 0xf, res);
|
||||
if (cpustate->pendingUnd == 0)
|
||||
{
|
||||
SET_REGISTER(cpustate, (insn >> 12) & 0xf, res);
|
||||
}
|
||||
}
|
||||
else
|
||||
LOG(("%08x: Co-Processor Register Transfer executed, but no RT Read callback defined!\n", R15));
|
||||
@ -864,6 +891,8 @@ static void HandleCoProcDT(arm_state *cpustate, UINT32 insn)
|
||||
LOG(("%08x: Co-Processer Data Transfer executed, but no WRITE callback defined!\n", R15));
|
||||
}
|
||||
|
||||
if (cpustate->pendingUnd != 0) return;
|
||||
|
||||
// If writeback not used - ensure the original value of RN is restored in case co-proc callback changed value
|
||||
if ((insn & 0x200000) == 0)
|
||||
SET_REGISTER(cpustate, rn, ornv);
|
||||
@ -1826,16 +1855,17 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
|
||||
// S Flag Set, but R15 not in list = User Bank Transfer
|
||||
if (insn & INSN_BDT_S && (insn & 0x8000) == 0)
|
||||
{
|
||||
// !! actually switching to user mode triggers a section permission fault in Happy Fish 302-in-1 (BP C0030DF4, press F5 ~16 times) !!
|
||||
// set to user mode - then do the transfer, and set back
|
||||
int curmode = GET_MODE;
|
||||
SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
//int curmode = GET_MODE;
|
||||
//SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15));
|
||||
result = loadInc(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
|
||||
result = loadInc(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S, eARM7_MODE_USER);
|
||||
// todo - not sure if Writeback occurs on User registers also..
|
||||
SwitchMode(cpustate, curmode);
|
||||
//SwitchMode(cpustate, curmode);
|
||||
}
|
||||
else
|
||||
result = loadInc(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
|
||||
result = loadInc(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S, GET_MODE);
|
||||
|
||||
if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
|
||||
{
|
||||
@ -1887,15 +1917,15 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
|
||||
if (insn & INSN_BDT_S && ((insn & 0x8000) == 0))
|
||||
{
|
||||
// set to user mode - then do the transfer, and set back
|
||||
int curmode = GET_MODE;
|
||||
SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
//int curmode = GET_MODE;
|
||||
//SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15));
|
||||
result = loadDec(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
|
||||
result = loadDec(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S, eARM7_MODE_USER);
|
||||
// todo - not sure if Writeback occurs on User registers also..
|
||||
SwitchMode(cpustate, curmode);
|
||||
//SwitchMode(cpustate, curmode);
|
||||
}
|
||||
else
|
||||
result = loadDec(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S);
|
||||
result = loadDec(cpustate, insn & 0xffff, rbp, insn & INSN_BDT_S, GET_MODE);
|
||||
|
||||
if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
|
||||
{
|
||||
@ -1960,15 +1990,15 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
|
||||
// todo: needs to be tested..
|
||||
|
||||
// set to user mode - then do the transfer, and set back
|
||||
int curmode = GET_MODE;
|
||||
SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
//int curmode = GET_MODE;
|
||||
//SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15));
|
||||
result = storeInc(cpustate, insn & 0xffff, rbp);
|
||||
result = storeInc(cpustate, insn & 0xffff, rbp, eARM7_MODE_USER);
|
||||
// todo - not sure if Writeback occurs on User registers also..
|
||||
SwitchMode(cpustate, curmode);
|
||||
//SwitchMode(cpustate, curmode);
|
||||
}
|
||||
else
|
||||
result = storeInc(cpustate, insn & 0xffff, rbp);
|
||||
result = storeInc(cpustate, insn & 0xffff, rbp, GET_MODE);
|
||||
|
||||
if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
|
||||
{
|
||||
@ -1987,15 +2017,15 @@ static void HandleMemBlock(arm_state *cpustate, UINT32 insn)
|
||||
if (insn & INSN_BDT_S)
|
||||
{
|
||||
// set to user mode - then do the transfer, and set back
|
||||
int curmode = GET_MODE;
|
||||
SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
//int curmode = GET_MODE;
|
||||
//SwitchMode(cpustate, eARM7_MODE_USER);
|
||||
LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15));
|
||||
result = storeDec(cpustate, insn & 0xffff, rbp);
|
||||
result = storeDec(cpustate, insn & 0xffff, rbp, eARM7_MODE_USER);
|
||||
// todo - not sure if Writeback occurs on User registers also..
|
||||
SwitchMode(cpustate, curmode);
|
||||
//SwitchMode(cpustate, curmode);
|
||||
}
|
||||
else
|
||||
result = storeDec(cpustate, insn & 0xffff, rbp);
|
||||
result = storeDec(cpustate, insn & 0xffff, rbp, GET_MODE);
|
||||
|
||||
if ((insn & INSN_BDT_W) && (cpustate->pendingAbtD == 0))
|
||||
{
|
||||
|
@ -139,7 +139,8 @@ enum
|
||||
|
||||
#define COPRO_DOMAIN_ACCESS_CONTROL cpustate->domainAccessControl
|
||||
|
||||
#define COPRO_FAULT_STATUS cpustate->faultStatus
|
||||
#define COPRO_FAULT_STATUS_D cpustate->faultStatus[0]
|
||||
#define COPRO_FAULT_STATUS_P cpustate->faultStatus[1]
|
||||
|
||||
#define COPRO_FAULT_ADDRESS cpustate->faultAddress
|
||||
|
||||
@ -149,7 +150,7 @@ enum
|
||||
#define ARM7COPRO_REGS \
|
||||
UINT32 control; \
|
||||
UINT32 tlbBase; \
|
||||
UINT32 faultStatus; \
|
||||
UINT32 faultStatus[2]; \
|
||||
UINT32 faultAddress; \
|
||||
UINT32 fcsePID; \
|
||||
UINT32 domainAccessControl;
|
||||
@ -503,16 +504,16 @@ enum
|
||||
#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
|
||||
};
|
||||
#define ARM7_TLB_ABORT_D (1 << 0)
|
||||
#define ARM7_TLB_ABORT_P (1 << 1)
|
||||
#define ARM7_TLB_READ (1 << 2)
|
||||
#define ARM7_TLB_WRITE (1 << 3)
|
||||
|
||||
/* 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)
|
||||
#define GET_MODE_REGISTER(state, mode, reg) GetModeRegister(state, mode, reg)
|
||||
#define SET_MODE_REGISTER(state, mode, reg, val) SetModeRegister(state, mode, reg, val)
|
||||
#define ARM7_CHECKIRQ arm7_check_irq_state(cpustate)
|
||||
|
||||
extern write32_device_func arm7_coproc_do_callback;
|
||||
|
@ -63,12 +63,12 @@
|
||||
|
||||
if ( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
raddr = arm7_tlb_translate(cpustate, raddr, ARM7_TLB_ABORT_P);
|
||||
if (cpustate->pendingAbtP != 0)
|
||||
if (!arm7_tlb_translate(cpustate, &raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ))
|
||||
{
|
||||
goto skip_exec;
|
||||
}
|
||||
}
|
||||
|
||||
insn = cpustate->direct->read_decrypted_word(raddr);
|
||||
ARM7_ICOUNT -= (3 - thumbCycles[insn >> 8]);
|
||||
switch ((insn & THUMB_INSN_TYPE) >> THUMB_INSN_TYPE_SHIFT)
|
||||
@ -1196,8 +1196,7 @@
|
||||
|
||||
if ( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
raddr = arm7_tlb_translate(cpustate, raddr, ARM7_TLB_ABORT_P);
|
||||
if (cpustate->pendingAbtP != 0)
|
||||
if (!arm7_tlb_translate(cpustate, &raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ))
|
||||
{
|
||||
goto skip_exec;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user