mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
-arm7: Added rudimentary TLB support. Allows HP Jornada 720 to boot further. [Ryan Holtz]
This commit is contained in:
parent
d7ef8a48f2
commit
e6d4824a8d
@ -41,8 +41,9 @@ TODO:
|
||||
#define LOG_COPRO_WRITES (1 << 3)
|
||||
#define LOG_COPRO_UNKNOWN (1 << 4)
|
||||
#define LOG_COPRO_RESERVED (1 << 5)
|
||||
#define LOG_TLB (1 << 6)
|
||||
|
||||
#define VERBOSE (0) // (LOG_MMU | LOG_COPRO_READS | LOG_COPRO_WRITES | LOG_COPRO_UNKNOWN | LOG_COPRO_RESERVED)
|
||||
#define VERBOSE (0) // (LOG_COPRO_READS | LOG_COPRO_WRITES | LOG_COPRO_UNKNOWN | LOG_COPRO_RESERVED)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define PRINT_HAPYFSH2 (0)
|
||||
@ -103,6 +104,8 @@ arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type
|
||||
memset(m_insn_prefetch_valid, 0, sizeof(bool) * 3);
|
||||
m_insn_prefetch_count = 0;
|
||||
m_insn_prefetch_index = 0;
|
||||
m_tlb_log = 0;
|
||||
m_actual_log = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -347,7 +350,7 @@ enum
|
||||
|
||||
|
||||
// COARSE, desc_level1, vaddr
|
||||
uint32_t arm7_cpu_device::arm7_tlb_get_second_level_descriptor( uint32_t granularity, uint32_t first_desc, uint32_t vaddr )
|
||||
uint32_t arm7_cpu_device::get_lvl2_desc_from_page_table( uint32_t granularity, uint32_t first_desc, uint32_t vaddr )
|
||||
{
|
||||
uint32_t desc_lvl2 = vaddr;
|
||||
|
||||
@ -355,9 +358,13 @@ uint32_t arm7_cpu_device::arm7_tlb_get_second_level_descriptor( uint32_t granula
|
||||
{
|
||||
case TLB_COARSE:
|
||||
desc_lvl2 = (first_desc & COPRO_TLB_CFLD_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_CSLTI_MASK) >> COPRO_TLB_VADDR_CSLTI_MASK_SHIFT);
|
||||
if (m_tlb_log)
|
||||
LOGMASKED(LOG_TLB, "%s: get_lvl2_desc_from_page_table: coarse descriptor, lvl2 address is %08x\n", machine().describe_context(), desc_lvl2);
|
||||
break;
|
||||
case TLB_FINE:
|
||||
desc_lvl2 = (first_desc & COPRO_TLB_FPTB_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_FSLTI_MASK) >> COPRO_TLB_VADDR_FSLTI_MASK_SHIFT);
|
||||
if (m_tlb_log)
|
||||
LOGMASKED(LOG_TLB, "%s: get_lvl2_desc_from_page_table: fine descriptor, lvl2 address is %08x\n", machine().describe_context(), desc_lvl2);
|
||||
break;
|
||||
default:
|
||||
// We shouldn't be here
|
||||
@ -444,148 +451,376 @@ int arm7_cpu_device::detect_fault(int desc_lvl1, int ap, int flags)
|
||||
return FAULT_NONE;
|
||||
}
|
||||
|
||||
|
||||
bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags)
|
||||
arm7_cpu_device::tlb_entry *arm7_cpu_device::tlb_map_entry(const offs_t vaddr, const int flags)
|
||||
{
|
||||
if (addr < 0x2000000)
|
||||
{
|
||||
addr += m_pid_offset;
|
||||
}
|
||||
const uint32_t bucket = (vaddr >> (COPRO_TLB_VADDR_FLTI_MASK_SHIFT + 2)) & 0x1F;
|
||||
tlb_entry *entries = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entries : m_itlb_entries;
|
||||
const uint32_t start = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_start[bucket] : m_itlb_entry_start[bucket];
|
||||
uint32_t index = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_index[bucket] : m_itlb_entry_index[bucket];
|
||||
|
||||
uint32_t desc_lvl1 = m_program->read_dword(m_tlb_base_mask | ((addr & COPRO_TLB_VADDR_FLTI_MASK) >> COPRO_TLB_VADDR_FLTI_MASK_SHIFT));
|
||||
bool entry_found = false;
|
||||
|
||||
#if ARM7_MMU_ENABLE_HACK
|
||||
if ((m_r[eR15] == (m_mmu_enable_addr + 4)) || (m_r[eR15] == (m_mmu_enable_addr + 8)))
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: fetch flat, PC = %08x, vaddr = %08x\n", m_r[eR15], addr);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mmu_enable_addr = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t tlb_type = desc_lvl1 & 3;
|
||||
if (tlb_type == COPRO_TLB_SECTION_TABLE)
|
||||
{
|
||||
// Entry is a section
|
||||
int fault = detect_fault(desc_lvl1, (desc_lvl1 >> 10) & 3, flags);
|
||||
if (fault == FAULT_NONE)
|
||||
index = (index + 1) & 1;
|
||||
if (!entries[start + index].valid)
|
||||
{
|
||||
addr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( addr & ~COPRO_TLB_SECTION_PAGE_MASK );
|
||||
entry_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry_found)
|
||||
{
|
||||
index = (index + 1) & 1;
|
||||
}
|
||||
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
m_dtlb_entry_index[bucket] = index;
|
||||
else
|
||||
m_itlb_entry_index[bucket] = index;
|
||||
|
||||
return &entries[start + index];
|
||||
}
|
||||
|
||||
arm7_cpu_device::tlb_entry *arm7_cpu_device::tlb_probe(const offs_t vaddr, const int flags)
|
||||
{
|
||||
const uint32_t bucket = (vaddr >> (COPRO_TLB_VADDR_FLTI_MASK_SHIFT + 2)) & 0x1F;
|
||||
tlb_entry *entries = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entries : m_itlb_entries;
|
||||
const uint32_t start = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_start[bucket] : m_itlb_entry_start[bucket];
|
||||
uint32_t index = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_index[bucket] : m_itlb_entry_index[bucket];
|
||||
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
{
|
||||
uint32_t position = start + index;
|
||||
if (entries[position].valid)
|
||||
{
|
||||
switch (entries[position].type)
|
||||
{
|
||||
case COPRO_TLB_TYPE_SECTION:
|
||||
if (entries[position].table_bits == (vaddr & COPRO_TLB_STABLE_MASK))
|
||||
return &entries[position];
|
||||
break;
|
||||
case COPRO_TLB_TYPE_LARGE:
|
||||
case COPRO_TLB_TYPE_SMALL:
|
||||
if (entries[position].table_bits == (vaddr & COPRO_TLB_LSTABLE_MASK))
|
||||
return &entries[position];
|
||||
break;
|
||||
case COPRO_TLB_TYPE_TINY:
|
||||
if (entries[position].table_bits == (vaddr & COPRO_TLB_TTABLE_MASK))
|
||||
return &entries[position];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index = (index - 1) & 1;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t arm7_cpu_device::get_fault_from_permissions(const uint8_t access, const uint8_t domain, const uint8_t type, int flags)
|
||||
{
|
||||
const uint8_t domain_bits = m_decoded_access_control[domain];
|
||||
switch (domain_bits)
|
||||
{
|
||||
case COPRO_DOMAIN_NO_ACCESS:
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_DOMAIN_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_DOMAIN_PAGE;
|
||||
case COPRO_DOMAIN_CLIENT:
|
||||
{
|
||||
const uint32_t mode = GET_CPSR & 0xF;
|
||||
switch (access)
|
||||
{
|
||||
case 0: // Check System/ROM bit
|
||||
{
|
||||
const uint32_t sr = (COPRO_CTRL >> COPRO_CTRL_SYSTEM_SHIFT) & 3;
|
||||
switch (sr)
|
||||
{
|
||||
case 0: // No Access
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_PERM_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_PERM_PAGE;
|
||||
case 1: // No User Access, Read-Only System Access
|
||||
if (mode == 0 || (flags & ARM7_TLB_WRITE))
|
||||
{
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_PERM_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_PERM_PAGE;
|
||||
}
|
||||
return COPRO_FAULT_NONE;
|
||||
case 2: // Read-Only Access
|
||||
if (flags & ARM7_TLB_WRITE)
|
||||
{
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_PERM_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_PERM_PAGE;
|
||||
}
|
||||
return COPRO_FAULT_NONE;
|
||||
case 3: // Unpredictable Access
|
||||
LOGMASKED(LOG_MMU, "%s: get_fault_from_permissions: Unpredictable access permissions (AP bits are 0, SR bits are 3).", machine().describe_context());
|
||||
return COPRO_FAULT_NONE;
|
||||
}
|
||||
return COPRO_FAULT_NONE;
|
||||
}
|
||||
case 1: // No User Access
|
||||
if (mode != 0)
|
||||
return COPRO_FAULT_NONE;
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_PERM_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_PERM_PAGE;
|
||||
case 2: // Read-Only User Access
|
||||
if (mode != 0 || (flags & ARM7_TLB_READ))
|
||||
return COPRO_FAULT_NONE;
|
||||
if (type == COPRO_TLB_TYPE_SECTION)
|
||||
return (domain << 4) | COPRO_FAULT_PERM_SECTION;
|
||||
return (domain << 4) | COPRO_FAULT_PERM_PAGE;
|
||||
case 3: // Full Access
|
||||
return COPRO_FAULT_NONE;
|
||||
}
|
||||
return COPRO_FAULT_NONE;
|
||||
}
|
||||
case COPRO_DOMAIN_RESV:
|
||||
LOGMASKED(LOG_MMU, "%s: get_fault_from_permissions: Domain type marked as Reserved.\n", machine().describe_context());
|
||||
return COPRO_FAULT_NONE;
|
||||
default:
|
||||
return COPRO_FAULT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t arm7_cpu_device::tlb_check_permissions(tlb_entry *entry, const int flags)
|
||||
{
|
||||
return get_fault_from_permissions(entry->access, entry->domain, entry->type, flags);
|
||||
}
|
||||
|
||||
offs_t arm7_cpu_device::tlb_translate(tlb_entry *entry, const offs_t vaddr)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case COPRO_TLB_TYPE_SECTION:
|
||||
return entry->base_addr | (vaddr & ~COPRO_TLB_SECTION_PAGE_MASK);
|
||||
case COPRO_TLB_TYPE_LARGE:
|
||||
return entry->base_addr | (vaddr & ~COPRO_TLB_LARGE_PAGE_MASK);
|
||||
case COPRO_TLB_TYPE_SMALL:
|
||||
return entry->base_addr | (vaddr & ~COPRO_TLB_SMALL_PAGE_MASK);
|
||||
case COPRO_TLB_TYPE_TINY:
|
||||
return entry->base_addr | (vaddr & ~COPRO_TLB_TINY_PAGE_MASK);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool arm7_cpu_device::page_table_finish_translation(offs_t &vaddr, const uint8_t type, const uint32_t lvl1, const uint32_t lvl2, const int flags, const uint32_t lvl1a, const uint32_t lvl2a)
|
||||
{
|
||||
const uint8_t domain = (uint8_t)(lvl1 >> 5) & 0xF;
|
||||
uint8_t access = 0;
|
||||
uint32_t table_bits = 0;
|
||||
switch (type)
|
||||
{
|
||||
case COPRO_TLB_TYPE_SECTION:
|
||||
access = (uint8_t)((lvl2 >> 10) & 3);
|
||||
table_bits = vaddr & COPRO_TLB_STABLE_MASK;
|
||||
break;
|
||||
case COPRO_TLB_TYPE_LARGE:
|
||||
{
|
||||
const uint8_t subpage_shift = 4 + (uint8_t)((vaddr >> 13) & 6);
|
||||
access = (uint8_t)((lvl2 >> subpage_shift) & 3);
|
||||
table_bits = vaddr & COPRO_TLB_LSTABLE_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
case COPRO_TLB_TYPE_SMALL:
|
||||
{
|
||||
const uint8_t subpage_shift = 4 + (uint8_t)((vaddr >> 9) & 6);
|
||||
access = (uint8_t)((lvl2 >> subpage_shift) & 3);
|
||||
table_bits = vaddr & COPRO_TLB_LSTABLE_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
case COPRO_TLB_TYPE_TINY:
|
||||
access = (uint8_t)((lvl2 >> 4) & 3);
|
||||
table_bits = vaddr & COPRO_TLB_TTABLE_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
const uint32_t access_result = get_fault_from_permissions(access, domain, type, flags);
|
||||
if (access_result != 0)
|
||||
{
|
||||
if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page walk, Potential prefetch abort, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", vaddr, lvl1a, lvl1, lvl2a, lvl2);
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
uint8_t domain = (desc_lvl1 >> 5) & 0xF;
|
||||
LOGMASKED(LOG_MMU, "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15]);
|
||||
m_faultStatus[0] = ((fault == FAULT_DOMAIN) ? (9 << 0) : (13 << 0)) | (domain << 4); // 9 = section domain fault, 13 = section permission fault
|
||||
m_faultAddress = addr;
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page walk, Data abort, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", vaddr, lvl1a, lvl1, lvl2a, lvl2);
|
||||
LOGMASKED(LOG_MMU, "access: %d, domain: %d, type: %d\n", access, domain, type);
|
||||
m_faultStatus[0] = access_result;
|
||||
m_faultAddress = vaddr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
LOGMASKED(LOG_MMU, "vaddr %08X desc_lvl1 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n",
|
||||
addr, desc_lvl1, domain, (m_domainAccessControl >> ((desc_lvl1 >> 4) & 0x1e)) & 3, (desc_lvl1 >> 10) & 3, (m_control & COPRO_CTRL_SYSTEM) ? 1 : 0, (m_control & COPRO_CTRL_ROM) ? 1 : 0,
|
||||
m_r[eCPSR] & MODE_FLAG, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uint32_t s_page_masks[4] = { COPRO_TLB_SECTION_PAGE_MASK, COPRO_TLB_LARGE_PAGE_MASK, COPRO_TLB_SMALL_PAGE_MASK, COPRO_TLB_TINY_PAGE_MASK };
|
||||
const uint32_t base_addr = lvl2 & s_page_masks[type];
|
||||
const uint32_t paddr = base_addr | (vaddr & ~s_page_masks[type]);
|
||||
|
||||
if (flags)
|
||||
{
|
||||
tlb_entry *entry = tlb_map_entry(vaddr, flags);
|
||||
|
||||
entry->valid = true;
|
||||
entry->domain = domain;
|
||||
entry->access = access;
|
||||
entry->table_bits = table_bits;
|
||||
entry->base_addr = base_addr;
|
||||
entry->type = type;
|
||||
}
|
||||
|
||||
vaddr = paddr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool arm7_cpu_device::page_table_translate(offs_t &vaddr, const int flags)
|
||||
{
|
||||
const uint32_t lvl1_addr = m_tlb_base_mask | ((vaddr & COPRO_TLB_VADDR_FLTI_MASK) >> COPRO_TLB_VADDR_FLTI_MASK_SHIFT);
|
||||
const uint32_t lvl1_desc = m_program->read_dword(lvl1_addr);
|
||||
|
||||
switch (lvl1_desc & 3)
|
||||
{
|
||||
case 0: // Unmapped
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (D), PC %08x, lvl1 unmapped, vaddr = %08x, lvl1A = %08x, lvl1D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc);
|
||||
m_faultStatus[0] = COPRO_FAULT_TRANSLATE_SECTION;
|
||||
m_faultAddress = vaddr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (P), PC %08x, lvl1 unmapped, vaddr = %08x, lvl1A = %08x, lvl1D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc);
|
||||
}
|
||||
return false;
|
||||
|
||||
case 1: // Coarse Table
|
||||
{
|
||||
const uint32_t lvl2_addr = (lvl1_desc & COPRO_TLB_CFLD_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_CSLTI_MASK) >> COPRO_TLB_VADDR_CSLTI_MASK_SHIFT);
|
||||
const uint32_t lvl2_desc = m_program->read_dword(lvl2_addr);
|
||||
|
||||
switch (lvl2_desc & 3)
|
||||
{
|
||||
case 0: // Unmapped
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (D), coarse lvl2 unmapped, PC %08x, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc);
|
||||
m_faultStatus[0] = ((lvl1_desc >> 1) & 0xF0) | COPRO_FAULT_TRANSLATE_PAGE;
|
||||
m_faultAddress = vaddr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (P), coarse lvl2 unmapped, PC %08x, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc);
|
||||
}
|
||||
return false;
|
||||
|
||||
case 1: // Large Page
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_LARGE, lvl1_desc, lvl2_desc, flags, lvl1_addr, lvl2_addr);
|
||||
|
||||
case 2: // Small Page
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_SMALL, lvl1_desc, lvl2_desc, flags, lvl1_addr, lvl2_addr);
|
||||
|
||||
case 3: // Tiny Page (invalid)
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed, tiny page present in coarse lvl2 table, PC %08x, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
|
||||
case 2: // Section Descriptor
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_SECTION, lvl1_desc, lvl1_desc, flags, lvl1_addr, lvl1_addr);
|
||||
|
||||
case 3: // Fine Table
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15]);
|
||||
const uint32_t lvl2_addr = (lvl1_desc & COPRO_TLB_FPTB_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_FSLTI_MASK) >> COPRO_TLB_VADDR_FSLTI_MASK_SHIFT);
|
||||
const uint32_t lvl2_desc = m_program->read_dword(lvl2_addr);
|
||||
|
||||
switch (lvl2_desc & 3)
|
||||
{
|
||||
case 0: // Unmapped
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (D), fine lvl2 unmapped, PC %08x, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc);
|
||||
m_faultStatus[0] = ((lvl1_desc >> 1) & 0xF0) | COPRO_FAULT_TRANSLATE_PAGE;
|
||||
m_faultAddress = vaddr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table Translation failed (P), fine lvl2 unmapped, PC %08x, vaddr = %08x, lvl1A = %08x, lvl1D = %08x, lvl2A = %08x, lvl2D = %08x\n", m_r[eR15], vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc);
|
||||
}
|
||||
return false;
|
||||
|
||||
case 1: // Large Page
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_LARGE, lvl1_desc, lvl2_desc, flags, lvl1_addr, lvl2_addr);
|
||||
|
||||
case 2: // Small Page
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_SMALL, lvl1_desc, lvl2_desc, flags, lvl1_addr, lvl2_addr);
|
||||
|
||||
case 3: // Tiny Page
|
||||
return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_TINY, lvl1_desc, lvl2_desc, flags, lvl1_addr, lvl2_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (tlb_type == COPRO_TLB_UNMAPPED)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arm7_cpu_device::translate_vaddr_to_paddr(offs_t &vaddr, const int flags)
|
||||
{
|
||||
if (m_tlb_log)
|
||||
LOGMASKED(LOG_TLB, "%s: translate_vaddr_to_paddr: vaddr %08x, flags %08x\n", machine().describe_context(), vaddr, flags);
|
||||
|
||||
if (vaddr < 0x2000000)
|
||||
{
|
||||
// Unmapped, generate a translation fault
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
vaddr += m_pid_offset;
|
||||
if (m_tlb_log)
|
||||
LOGMASKED(LOG_TLB, "%s: translate_vaddr_to_paddr: vaddr < 32M, adding PID (%08x) = %08x\n", machine().describe_context(), m_pid_offset, vaddr);
|
||||
}
|
||||
|
||||
tlb_entry *entry = tlb_probe(vaddr, flags);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
const uint32_t access_result = tlb_check_permissions(entry, flags);
|
||||
if (access_result == 0)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Translation fault on unmapped virtual address (D), PC = %08x, vaddr = %08x\n", m_r[eR15], addr);
|
||||
m_faultStatus[0] = (5 << 0); // 5 = section translation fault
|
||||
m_faultAddress = addr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
vaddr = tlb_translate(entry, vaddr);
|
||||
return true;
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Translation fault on unmapped virtual address (P), PC = %08x, vaddr = %08x\n", m_r[eR15], addr);
|
||||
LOGMASKED(LOG_MMU, "ARM7: TLB, Potential prefetch abort, vaddr = %08x\n", vaddr);
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: TLB, Data abort, vaddr = %08x\n", vaddr);
|
||||
m_faultStatus[0] = access_result;
|
||||
m_faultAddress = vaddr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Entry is the physical address of a coarse second-level table
|
||||
uint8_t permission = (m_domainAccessControl >> ((desc_lvl1 >> 4) & 0x1e)) & 3;
|
||||
uint32_t desc_lvl2 = arm7_tlb_get_second_level_descriptor( (desc_lvl1 & 3) == COPRO_TLB_COARSE_TABLE ? TLB_COARSE : TLB_FINE, desc_lvl1, addr );
|
||||
if ((permission != 1) && (permission != 3))
|
||||
{
|
||||
uint8_t domain = (desc_lvl1 >> 5) & 0xF;
|
||||
fatalerror("ARM7: Not Yet Implemented: Coarse Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", addr, domain, m_r[eR15]);
|
||||
}
|
||||
|
||||
switch (desc_lvl2 & 3)
|
||||
{
|
||||
case COPRO_TLB_UNMAPPED:
|
||||
// Unmapped, generate a translation fault
|
||||
if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
uint8_t domain = (desc_lvl1 >> 5) & 0xF;
|
||||
LOGMASKED(LOG_MMU, "ARM7: Translation fault on unmapped virtual address (D), lvl2, vaddr = %08x, PC %08X\n", addr, m_r[eR15]);
|
||||
m_faultStatus[0] = (7 << 0) | (domain << 4); // 7 = page translation fault
|
||||
m_faultAddress = addr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Translation fault on unmapped virtual address (P), lvl2, vaddr = %08x, PC %08X\n", addr, m_r[eR15]);
|
||||
}
|
||||
return false;
|
||||
case COPRO_TLB_LARGE_PAGE:
|
||||
// Large page descriptor
|
||||
addr = ( desc_lvl2 & COPRO_TLB_LARGE_PAGE_MASK ) | ( addr & ~COPRO_TLB_LARGE_PAGE_MASK );
|
||||
break;
|
||||
case COPRO_TLB_SMALL_PAGE:
|
||||
// Small page descriptor
|
||||
{
|
||||
uint8_t ap = ((((desc_lvl2 >> 4) & 0xFF) >> (((addr >> 10) & 3) << 1)) & 3);
|
||||
int fault = detect_fault(desc_lvl1, ap, flags);
|
||||
if (fault == FAULT_NONE)
|
||||
{
|
||||
addr = (desc_lvl2 & COPRO_TLB_SMALL_PAGE_MASK) | (addr & ~COPRO_TLB_SMALL_PAGE_MASK);
|
||||
break;
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_D)
|
||||
{
|
||||
uint8_t domain = (desc_lvl1 >> 5) & 0xF;
|
||||
// hapyfish expects a data abort when something tries to write to a read-only memory location from user mode
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15]);
|
||||
m_faultStatus[0] = ((fault == FAULT_DOMAIN) ? (11 << 0) : (15 << 0)) | (domain << 4); // 11 = page domain fault, 15 = page permission fault
|
||||
m_faultAddress = addr;
|
||||
m_pendingAbtD = true;
|
||||
update_irq_state();
|
||||
LOGMASKED(LOG_MMU, "vaddr %08X desc_lvl2 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n",
|
||||
addr, desc_lvl2, domain, permission, ap, (m_control & COPRO_CTRL_SYSTEM) ? 1 : 0, (m_control & COPRO_CTRL_ROM) ? 1 : 0,
|
||||
m_r[eCPSR] & MODE_FLAG, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0);
|
||||
}
|
||||
else if (flags & ARM7_TLB_ABORT_P)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case COPRO_TLB_TINY_PAGE:
|
||||
// Tiny page descriptor
|
||||
if ((desc_lvl1 & 3) == 1)
|
||||
{
|
||||
LOGMASKED(LOG_MMU, "ARM7: It would appear that we're looking up a tiny page from a coarse TLB lookup. This is bad. vaddr = %08x\n", addr);
|
||||
}
|
||||
addr = (desc_lvl2 & COPRO_TLB_TINY_PAGE_MASK) | (addr & ~COPRO_TLB_TINY_PAGE_MASK);
|
||||
break;
|
||||
}
|
||||
return page_table_translate(vaddr, flags);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -594,7 +829,28 @@ bool arm7_cpu_device::memory_translate(int spacenum, int intention, offs_t &addr
|
||||
/* only applies to the program address space and only does something if the MMU's enabled */
|
||||
if (spacenum == AS_PROGRAM && (m_control & COPRO_CTRL_MMU_EN))
|
||||
{
|
||||
return arm7_tlb_translate(address, 0);
|
||||
int intention_type = intention & TRANSLATE_TYPE_MASK;
|
||||
|
||||
const int flags = (intention_type & TRANSLATE_FETCH) ? ARM7_TLB_ABORT_P : ARM7_TLB_ABORT_D;
|
||||
if (address < 0x2000000)
|
||||
address += m_pid_offset;
|
||||
|
||||
tlb_entry *entry = tlb_probe(address, flags);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
const uint32_t access_result = tlb_check_permissions(entry, flags);
|
||||
if (access_result == 0)
|
||||
{
|
||||
address = tlb_translate(entry, address);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return page_table_translate(address, 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -632,6 +888,8 @@ void arm7_cpu_device::device_start()
|
||||
save_item(NAME(m_insn_prefetch_buffer));
|
||||
save_item(NAME(m_insn_prefetch_address));
|
||||
save_item(NAME(m_insn_prefetch_valid));
|
||||
save_item(NAME(m_tlb_log));
|
||||
save_item(NAME(m_actual_log));
|
||||
save_item(NAME(m_r));
|
||||
save_item(NAME(m_pendingIrq));
|
||||
save_item(NAME(m_pendingFiq));
|
||||
@ -649,8 +907,28 @@ void arm7_cpu_device::device_start()
|
||||
save_item(NAME(m_pid_offset));
|
||||
save_item(NAME(m_domainAccessControl));
|
||||
save_item(NAME(m_decoded_access_control));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, valid));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, domain));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, access));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, table_bits));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, base_addr));
|
||||
save_item(STRUCT_MEMBER(m_dtlb_entries, type));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, valid));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, domain));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, access));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, table_bits));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, base_addr));
|
||||
save_item(STRUCT_MEMBER(m_itlb_entries, type));
|
||||
save_item(NAME(m_dtlb_entry_index));
|
||||
save_item(NAME(m_itlb_entry_index));
|
||||
machine().save().register_postload(save_prepost_delegate(FUNC(arm7_cpu_device::postload), this));
|
||||
|
||||
for (uint32_t i = 0; i < 32; i++)
|
||||
{
|
||||
m_dtlb_entry_start[i] = i * 2;
|
||||
m_itlb_entry_start[i] = i * 2;
|
||||
}
|
||||
|
||||
set_icountptr(m_icount);
|
||||
|
||||
state_add( ARM7_PC, "PC", m_pc).callexport().formatstr("%08X");
|
||||
@ -700,6 +978,7 @@ void arm7_cpu_device::device_start()
|
||||
state_add( ARM7_UR13, "UR13", m_r[eR13_UND] ).formatstr("%08X");
|
||||
state_add( ARM7_UR14, "UR14", m_r[eR14_UND] ).formatstr("%08X");
|
||||
state_add( ARM7_USPSR, "UR16", m_r[eSPSR_UND]).formatstr("%08X");
|
||||
state_add( ARM7_LOGTLB, "LOGTLB", m_actual_log).formatstr("%01X");
|
||||
|
||||
state_add(STATE_GENFLAGS, "GENFLAGS", m_r[eCPSR]).formatstr("%13s").noshow();
|
||||
}
|
||||
@ -780,6 +1059,11 @@ void arm7_cpu_device::device_reset()
|
||||
m_r[eR15] = 0 | m_vectorbase;
|
||||
|
||||
m_impstate.cache_dirty = true;
|
||||
|
||||
memset(m_dtlb_entries, 0, sizeof(tlb_entry) * ARRAY_LENGTH(m_dtlb_entries));
|
||||
memset(m_itlb_entries, 0, sizeof(tlb_entry) * ARRAY_LENGTH(m_itlb_entries));
|
||||
memset(m_dtlb_entry_index, 0, ARRAY_LENGTH(m_dtlb_entry_index));
|
||||
memset(m_itlb_entry_index, 0, ARRAY_LENGTH(m_itlb_entry_index));
|
||||
}
|
||||
|
||||
void arm1176jzf_s_cpu_device::device_reset()
|
||||
@ -814,7 +1098,7 @@ void arm7_cpu_device::update_insn_prefetch(uint32_t curr_pc)
|
||||
uint32_t index = (i + start_index) % m_insn_prefetch_depth;
|
||||
m_insn_prefetch_valid[index] = true;
|
||||
offs_t physical_pc = pc;
|
||||
if ((m_control & COPRO_CTRL_MMU_EN) && !arm7_tlb_translate(physical_pc, ARM7_TLB_ABORT_P | ARM7_TLB_READ))
|
||||
if ((m_control & COPRO_CTRL_MMU_EN) && !translate_vaddr_to_paddr(physical_pc, ARM7_TLB_ABORT_P | ARM7_TLB_READ))
|
||||
{
|
||||
m_insn_prefetch_valid[index] = false;
|
||||
break;
|
||||
@ -854,6 +1138,8 @@ bool arm7_cpu_device::insn_fetch_arm(uint32_t pc, uint32_t &out_insn)
|
||||
|
||||
void arm7_cpu_device::execute_run()
|
||||
{
|
||||
m_tlb_log = m_actual_log;
|
||||
|
||||
uint32_t insn;
|
||||
|
||||
do
|
||||
@ -1054,7 +1340,9 @@ void arm7_cpu_device::execute_run()
|
||||
#endif
|
||||
update_insn_prefetch(pc);
|
||||
|
||||
m_tlb_log = 0;
|
||||
debugger_instruction_hook(pc);
|
||||
m_tlb_log = m_actual_log;
|
||||
|
||||
/* handle Thumb instructions if active */
|
||||
if (T_IS_SET(m_r[eCPSR]))
|
||||
@ -1173,6 +1461,8 @@ skip_exec:
|
||||
/* All instructions remove 3 cycles.. Others taking less / more will have adjusted this # prior to here */
|
||||
m_icount -= 3;
|
||||
} while (m_icount > 0);
|
||||
|
||||
m_tlb_log = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1314,7 +1604,7 @@ uint32_t arm7_cpu_device::arm7_rt_r_callback(offs_t offset)
|
||||
data = COPRO_DOMAIN_ACCESS_CONTROL;
|
||||
break;
|
||||
case 5: // Fault Status
|
||||
LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Fault Status, PC = %08x\n", m_r[eR15]);
|
||||
LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Fault Status, PC = %08x, op3 %d, FSR0 = %08x, FSR1 = %08x\n", m_r[eR15], op3, COPRO_FAULT_STATUS_D, COPRO_FAULT_STATUS_P);
|
||||
switch (op3)
|
||||
{
|
||||
case 0: data = COPRO_FAULT_STATUS_D; break;
|
||||
@ -1322,7 +1612,7 @@ uint32_t arm7_cpu_device::arm7_rt_r_callback(offs_t offset)
|
||||
}
|
||||
break;
|
||||
case 6: // Fault Address
|
||||
LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Fault Address, PC = %08x\n", m_r[eR15]);
|
||||
LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Fault Address, PC = %08x, FAR = %08x\n", m_r[eR15], COPRO_FAULT_ADDRESS);
|
||||
data = COPRO_FAULT_ADDRESS;
|
||||
break;
|
||||
case 13: // Read Process ID (PID)
|
||||
@ -1394,7 +1684,7 @@ void arm7_cpu_device::arm7_rt_w_callback(offs_t offset, uint32_t data)
|
||||
}
|
||||
if (((data & COPRO_CTRL_MMU_EN) == 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) != 0))
|
||||
{
|
||||
if (!arm7_tlb_translate( R15, 0))
|
||||
if (!translate_vaddr_to_paddr( R15, 0))
|
||||
{
|
||||
fatalerror("ARM7_MMU_ENABLE_HACK translate failed\n");
|
||||
}
|
||||
@ -1432,6 +1722,54 @@ void arm7_cpu_device::arm7_rt_w_callback(offs_t offset, uint32_t data)
|
||||
break;
|
||||
case 8: // TLB Operations
|
||||
LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Ops = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]);
|
||||
switch (op2)
|
||||
{
|
||||
case 0:
|
||||
switch (op3)
|
||||
{
|
||||
case 5:
|
||||
// Flush I
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
{
|
||||
m_itlb_entries[i].valid = false;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
// Flush D
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
{
|
||||
m_dtlb_entries[i].valid = false;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
// Flush I+D
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
{
|
||||
m_dtlb_entries[i].valid = false;
|
||||
m_itlb_entries[i].valid = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Unsupported TLB Op\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (op3 == 6)
|
||||
{
|
||||
// Flush D single entry
|
||||
tlb_entry *entry = tlb_map_entry(m_r[op3], ARM7_TLB_ABORT_D);
|
||||
if (entry)
|
||||
{
|
||||
entry->valid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Unsupported TLB Op\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 9: // Read Buffer Operations
|
||||
LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Read Buffer Ops = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]);
|
||||
@ -1801,7 +2139,7 @@ void arm7_cpu_device::arm7_cpu_write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1816,7 +2154,7 @@ void arm7_cpu_device::arm7_cpu_write16(uint32_t addr, uint16_t data)
|
||||
{
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1830,7 +2168,7 @@ void arm7_cpu_device::arm7_cpu_write8(uint32_t addr, uint8_t data)
|
||||
{
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1845,7 +2183,7 @@ uint32_t arm7_cpu_device::arm7_cpu_read32(uint32_t addr)
|
||||
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -1870,7 +2208,7 @@ uint32_t arm7_cpu_device::arm7_cpu_read16(uint32_t addr)
|
||||
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -1890,7 +2228,7 @@ uint8_t arm7_cpu_device::arm7_cpu_read8(uint32_t addr)
|
||||
{
|
||||
if( COPRO_CTRL & COPRO_CTRL_MMU_EN )
|
||||
{
|
||||
if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
if (!translate_vaddr_to_paddr( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ ))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,6 +158,24 @@ protected:
|
||||
bool m_insn_prefetch_valid[3];
|
||||
const uint32_t m_prefetch_word0_shift;
|
||||
const uint32_t m_prefetch_word1_shift;
|
||||
int m_tlb_log;
|
||||
int m_actual_log;
|
||||
|
||||
struct tlb_entry
|
||||
{
|
||||
bool valid;
|
||||
uint8_t domain;
|
||||
uint8_t access;
|
||||
uint32_t table_bits;
|
||||
uint32_t base_addr;
|
||||
uint8_t type;
|
||||
};
|
||||
tlb_entry m_dtlb_entries[64];
|
||||
tlb_entry m_itlb_entries[64];
|
||||
uint8_t m_dtlb_entry_start[32];
|
||||
uint8_t m_itlb_entry_start[32];
|
||||
uint8_t m_dtlb_entry_index[32];
|
||||
uint8_t m_itlb_entry_index[32];
|
||||
|
||||
bool m_pendingIrq;
|
||||
bool m_pendingFiq;
|
||||
@ -235,8 +253,15 @@ protected:
|
||||
void arm9ops_e(uint32_t insn);
|
||||
|
||||
void set_cpsr(uint32_t val);
|
||||
bool arm7_tlb_translate(offs_t &addr, int flags);
|
||||
uint32_t arm7_tlb_get_second_level_descriptor( uint32_t granularity, uint32_t first_desc, uint32_t vaddr );
|
||||
bool translate_vaddr_to_paddr(offs_t &addr, const int flags);
|
||||
bool page_table_finish_translation(offs_t &vaddr, const uint8_t type, const uint32_t lvl1, const uint32_t lvl2, const int flags, const uint32_t lvl1a, const uint32_t lvl2a);
|
||||
bool page_table_translate(offs_t &vaddr, const int flags);
|
||||
tlb_entry *tlb_map_entry(const offs_t vaddr, const int flags);
|
||||
tlb_entry *tlb_probe(const offs_t vaddr, const int flags);
|
||||
uint32_t get_fault_from_permissions(const uint8_t access, const uint8_t domain, const uint8_t type, const int flags);
|
||||
uint32_t tlb_check_permissions(tlb_entry *entry, const int flags);
|
||||
offs_t tlb_translate(tlb_entry *entry, const offs_t vaddr);
|
||||
uint32_t get_lvl2_desc_from_page_table(uint32_t granularity, uint32_t first_desc, uint32_t vaddr);
|
||||
int detect_fault(int desc_lvl1, int ap, int flags);
|
||||
void arm7_check_irq_state();
|
||||
void update_irq_state();
|
||||
|
@ -48,7 +48,7 @@ enum
|
||||
ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15,
|
||||
ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14,
|
||||
ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR,
|
||||
ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR
|
||||
ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR, ARM7_LOGTLB
|
||||
};
|
||||
|
||||
/* There are 36 Unique - 32 bit processor registers */
|
||||
@ -83,6 +83,19 @@ enum
|
||||
};
|
||||
|
||||
/* Coprocessor-related macros */
|
||||
#define COPRO_DOMAIN_NO_ACCESS 0
|
||||
#define COPRO_DOMAIN_CLIENT 1
|
||||
#define COPRO_DOMAIN_RESV 2
|
||||
#define COPRO_DOMAIN_MANAGER 3
|
||||
|
||||
#define COPRO_FAULT_NONE 0
|
||||
#define COPRO_FAULT_TRANSLATE_SECTION 5
|
||||
#define COPRO_FAULT_TRANSLATE_PAGE 7
|
||||
#define COPRO_FAULT_DOMAIN_SECTION 9
|
||||
#define COPRO_FAULT_DOMAIN_PAGE 11
|
||||
#define COPRO_FAULT_PERM_SECTION 13
|
||||
#define COPRO_FAULT_PERM_PAGE 15
|
||||
|
||||
#define COPRO_TLB_BASE m_tlbBase
|
||||
#define COPRO_TLB_BASE_MASK 0xffffc000
|
||||
#define COPRO_TLB_VADDR_FLTI_MASK 0xfff00000
|
||||
@ -99,6 +112,9 @@ enum
|
||||
#define COPRO_TLB_LARGE_PAGE_MASK 0xffff0000
|
||||
#define COPRO_TLB_SMALL_PAGE_MASK 0xfffff000
|
||||
#define COPRO_TLB_TINY_PAGE_MASK 0xfffffc00
|
||||
#define COPRO_TLB_STABLE_MASK 0xfff00000
|
||||
#define COPRO_TLB_LSTABLE_MASK 0xfffff000
|
||||
#define COPRO_TLB_TTABLE_MASK 0xfffffc00
|
||||
#define COPRO_TLB_UNMAPPED 0
|
||||
#define COPRO_TLB_LARGE_PAGE 1
|
||||
#define COPRO_TLB_SMALL_PAGE 2
|
||||
@ -106,6 +122,10 @@ enum
|
||||
#define COPRO_TLB_COARSE_TABLE 1
|
||||
#define COPRO_TLB_SECTION_TABLE 2
|
||||
#define COPRO_TLB_FINE_TABLE 3
|
||||
#define COPRO_TLB_TYPE_SECTION 0
|
||||
#define COPRO_TLB_TYPE_LARGE 1
|
||||
#define COPRO_TLB_TYPE_SMALL 2
|
||||
#define COPRO_TLB_TYPE_TINY 3
|
||||
|
||||
#define COPRO_CTRL m_control
|
||||
#define COPRO_CTRL_MMU_EN 0x00000001
|
||||
|
Loading…
Reference in New Issue
Block a user