diff options
Diffstat (limited to 'src/devices/cpu/arm7/arm7.cpp')
-rw-r--r-- | src/devices/cpu/arm7/arm7.cpp | 1274 |
1 files changed, 1007 insertions, 267 deletions
diff --git a/src/devices/cpu/arm7/arm7.cpp b/src/devices/cpu/arm7/arm7.cpp index 4cf3b5fe351..46ffa46e41a 100644 --- a/src/devices/cpu/arm7/arm7.cpp +++ b/src/devices/cpu/arm7/arm7.cpp @@ -2,10 +2,10 @@ // copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz /***************************************************************************** * - * arm7.c + * arm7.cpp * Portable CPU Emulator for 32-bit ARM v3/4/5/6 * - * Copyright Steve Ellenoff, all rights reserved. + * Copyright Steve Ellenoff * Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz. * * This work is based on: @@ -29,12 +29,33 @@ TODO: - Fix and finish the DRC code, or remove it entirely *****************************************************************************/ + #include "emu.h" -#include "debugger.h" #include "arm7.h" + #include "arm7core.h" //include arm7 core #include "arm7help.h" +#include "debug/debugcon.h" +#include "debugger.h" + +#include <cassert> + +#define LOG_MMU (1U << 1) +#define LOG_DSP (1U << 2) +#define LOG_COPRO_READS (1U << 3) +#define LOG_COPRO_WRITES (1U << 4) +#define LOG_COPRO_UNKNOWN (1U << 5) +#define LOG_COPRO_RESERVED (1U << 6) +#define LOG_TLB (1U << 7) +#define LOG_TLB_MISS (1U << 8) +#define LOG_PREFETCH (1U << 9) + +#define VERBOSE (0) // (LOG_COPRO_READS | LOG_COPRO_WRITES | LOG_COPRO_UNKNOWN | LOG_COPRO_RESERVED) +#include "logmacro.h" + +#define PRINT_HAPYFSH2 (0) +#define PRINT_CE_KERNEL (0) /* prototypes of coprocessor functions */ void arm7_dt_r_callback(arm_state *arm, uint32_t insn, uint32_t *prn, uint32_t (*read32)(arm_state *arm, uint32_t addr)); @@ -48,13 +69,17 @@ void (*arm7_coproc_dt_w_callback)(arm_state *arm, uint32_t insn, uint32_t *prn, DEFINE_DEVICE_TYPE(ARM7, arm7_cpu_device, "arm7_le", "ARM7 (little)") DEFINE_DEVICE_TYPE(ARM7_BE, arm7_be_cpu_device, "arm7_be", "ARM7 (big)") DEFINE_DEVICE_TYPE(ARM710A, arm710a_cpu_device, "arm710a", "ARM710a") +DEFINE_DEVICE_TYPE(ARM710T, arm710t_cpu_device, "arm710t", "ARM710T") DEFINE_DEVICE_TYPE(ARM7500, arm7500_cpu_device, "arm7500", "ARM7500") DEFINE_DEVICE_TYPE(ARM9, arm9_cpu_device, "arm9", "ARM9") DEFINE_DEVICE_TYPE(ARM920T, arm920t_cpu_device, "arm920t", "ARM920T") DEFINE_DEVICE_TYPE(ARM946ES, arm946es_cpu_device, "arm946es", "ARM946ES") DEFINE_DEVICE_TYPE(ARM11, arm11_cpu_device, "arm11", "ARM11") DEFINE_DEVICE_TYPE(ARM1176JZF_S, arm1176jzf_s_cpu_device, "arm1176jzf_s", "ARM1176JZF-S") +DEFINE_DEVICE_TYPE(PXA250, pxa250_cpu_device, "pxa250", "Intel XScale PXA250") DEFINE_DEVICE_TYPE(PXA255, pxa255_cpu_device, "pxa255", "Intel XScale PXA255") +DEFINE_DEVICE_TYPE(PXA270, pxa270_cpu_device, "pxa270", "Intel XScale PXA270") +DEFINE_DEVICE_TYPE(SA1100, sa1100_cpu_device, "sa1100", "Intel StrongARM SA-1100") DEFINE_DEVICE_TYPE(SA1110, sa1110_cpu_device, "sa1110", "Intel StrongARM SA-1110") DEFINE_DEVICE_TYPE(IGS036, igs036_cpu_device, "igs036", "IGS036") @@ -63,9 +88,17 @@ arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, const char *tag, { } -arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t archRev, uint32_t archFlags, endianness_t endianness) +arm7_cpu_device::arm7_cpu_device( + const machine_config &mconfig, + device_type type, + const char *tag, device_t *owner, + uint32_t clock, + uint8_t archRev, + uint32_t archFlags, + endianness_t endianness, + address_map_constructor internal_map) : cpu_device(mconfig, type, tag, owner, clock) - , m_program_config("program", endianness, 32, 32, 0) + , m_program_config("program", endianness, 32, 32, 0, internal_map) , m_prefetch_word0_shift(endianness == ENDIANNESS_LITTLE ? 0 : 16) , m_prefetch_word1_shift(endianness == ENDIANNESS_LITTLE ? 16 : 0) , m_endian(endianness) @@ -74,7 +107,7 @@ arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type , m_vectorbase(0) , m_pc(0) { - memset(m_r, 0x00, sizeof(m_r)); + std::fill(std::begin(m_r), std::end(m_r), 0); uint32_t arch = ARM9_COPRO_ID_ARCH_V4; if (m_archFlags & ARCHFLAG_T) arch = ARM9_COPRO_ID_ARCH_V4T; @@ -84,10 +117,17 @@ arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type // TODO[RH]: Default to 3-instruction prefetch for unknown ARM variants. Derived cores should set the appropriate value in their constructors. m_insn_prefetch_depth = 3; - memset(m_insn_prefetch_buffer, 0, sizeof(uint32_t) * 3); - memset(m_insn_prefetch_address, 0, sizeof(uint32_t) * 3); + std::fill_n(&m_insn_prefetch_buffer[0], 3, 0); + std::fill_n(&m_insn_prefetch_address[0], 3, 0); + std::fill_n(&m_insn_prefetch_valid[0], 3, false); m_insn_prefetch_count = 0; m_insn_prefetch_index = 0; + m_tlb_log = 0; + m_actual_log = 0; +} + +arm7_cpu_device::~arm7_cpu_device() +{ } @@ -106,6 +146,15 @@ arm710a_cpu_device::arm710a_cpu_device(const machine_config &mconfig, const char } +arm710t_cpu_device::arm710t_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : arm7_cpu_device(mconfig, ARM710T, tag, owner, clock, 4, ARCHFLAG_MODE26, ENDIANNESS_LITTLE) +{ + m_copro_id = ARM9_COPRO_ID_MFR_ARM + | ARM9_COPRO_ID_PART_ARM710 + | 0x00800000; +} + + arm7500_cpu_device::arm7500_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : arm7_cpu_device(mconfig, ARM7500, tag, owner, clock, 4, ARCHFLAG_MODE26, ENDIANNESS_LITTLE) { @@ -168,8 +217,8 @@ arm946es_cpu_device::arm946es_cpu_device(const machine_config &mconfig, device_t | ARM9_COPRO_ID_PART_ARM946 | ARM9_COPRO_ID_STEP_ARM946_A0; - memset(ITCM, 0, 0x8000); - memset(DTCM, 0, 0x4000); + std::fill_n(&ITCM[0], 0x8000, 0); + std::fill_n(&DTCM[0], 0x4000, 0); cp15_itcm_base = 0xffffffff; cp15_itcm_size = 0; @@ -215,16 +264,43 @@ igs036_cpu_device::igs036_cpu_device(const machine_config &mconfig, const char * { } +pxa250_cpu_device::pxa250_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : arm7_cpu_device(mconfig, PXA250, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E | ARCHFLAG_XSCALE, ENDIANNESS_LITTLE) +{ + m_copro_id = ARM9_COPRO_ID_MFR_INTEL + | ARM9_COPRO_ID_ARCH_V5TE + | ARM9_COPRO_ID_PART_PXA250 + | ARM9_COPRO_ID_STEP_PXA255_A0; +} + pxa255_cpu_device::pxa255_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : arm7_cpu_device(mconfig, PXA255, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E | ARCHFLAG_XSCALE, ENDIANNESS_LITTLE) { m_copro_id = ARM9_COPRO_ID_MFR_INTEL | ARM9_COPRO_ID_ARCH_V5TE - | ARM9_COPRO_ID_PXA255_CORE_GEN_XSCALE - | (3 << ARM9_COPRO_ID_PXA255_CORE_REV_SHIFT) + | ARM9_COPRO_ID_PART_PXA255 + | ARM9_COPRO_ID_STEP_PXA255_A0; +} + +pxa270_cpu_device::pxa270_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : arm7_cpu_device(mconfig, PXA270, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E | ARCHFLAG_XSCALE, ENDIANNESS_LITTLE) +{ + m_copro_id = ARM9_COPRO_ID_MFR_INTEL + | ARM9_COPRO_ID_ARCH_V5TE + | ARM9_COPRO_ID_PART_PXA270 | ARM9_COPRO_ID_STEP_PXA255_A0; } +sa1100_cpu_device::sa1100_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : arm7_cpu_device(mconfig, SA1100, tag, owner, clock, 4, ARCHFLAG_SA, ENDIANNESS_LITTLE) + // has StrongARM, no Thumb, no Enhanced DSP +{ + m_copro_id = ARM9_COPRO_ID_MFR_DEC + | ARM9_COPRO_ID_ARCH_V4 + | ARM9_COPRO_ID_PART_SA1100 + | ARM9_COPRO_ID_STEP_SA1100_A; +} + sa1110_cpu_device::sa1110_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : arm7_cpu_device(mconfig, SA1110, tag, owner, clock, 4, ARCHFLAG_SA, ENDIANNESS_LITTLE) // has StrongARM, no Thumb, no Enhanced DSP @@ -232,7 +308,7 @@ sa1110_cpu_device::sa1110_cpu_device(const machine_config &mconfig, const char * m_copro_id = ARM9_COPRO_ID_MFR_INTEL | ARM9_COPRO_ID_ARCH_V4 | ARM9_COPRO_ID_PART_SA1110 - | ARM9_COPRO_ID_STEP_SA1110_A0; + | ARM9_COPRO_ID_STEP_SA1110_B4; } device_memory_interface::space_config_vector arm7_cpu_device::memory_space_config() const @@ -250,6 +326,7 @@ void arm7_cpu_device::update_reg_ptr() void arm7_cpu_device::set_cpsr(uint32_t val) { uint8_t old_mode = GET_CPSR & MODE_FLAG; + bool call_hook = false; if (m_archFlags & ARCHFLAG_MODE26) { if ((val & 0x10) != (m_r[eCPSR] & 0x10)) @@ -265,6 +342,7 @@ void arm7_cpu_device::set_cpsr(uint32_t val) // 32 -> 26 m_r[eR15] = (m_r[eR15] & 0x03FFFFFC) /* PC */ | (val & 0xF0000000) /* N Z C V */ | ((val & 0x000000C0) << (26 - 6)) /* I F */ | (val & 0x00000003) /* M1 M0 */; } + call_hook = true; } else { @@ -279,11 +357,17 @@ void arm7_cpu_device::set_cpsr(uint32_t val) { val |= 0x10; // force valid mode } + if ((val & T_MASK) != (m_r[eCPSR] & T_MASK)) + call_hook = true; m_r[eCPSR] = val; if ((GET_CPSR & MODE_FLAG) != old_mode) { + if ((GET_CPSR & MODE_FLAG) == eARM7_MODE_USER || old_mode == eARM7_MODE_USER) + call_hook = true; update_reg_ptr(); } + if (call_hook) + debugger_privilege_hook(); } @@ -306,7 +390,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; @@ -314,13 +398,17 @@ 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 - LOG( ( "ARM7: Attempting to get second-level TLB descriptor of invalid granularity (%d)\n", granularity ) ); + LOGMASKED(LOG_MMU, "ARM7: Attempting to get second-level TLB descriptor of invalid granularity (%d)\n", granularity); break; } @@ -403,182 +491,456 @@ int arm7_cpu_device::detect_fault(int desc_lvl1, int ap, int flags) return FAULT_NONE; } +arm7_cpu_device::tlb_entry *arm7_cpu_device::tlb_map_entry(const offs_t vaddr, const int flags) +{ + const uint32_t section = (vaddr >> (COPRO_TLB_VADDR_FLTI_MASK_SHIFT + 2)) & 0xFFF; + tlb_entry *entries = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entries : m_itlb_entries; + const uint32_t start = section << 1; + uint32_t index = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_index[section] : m_itlb_entry_index[section]; + + bool entry_found = false; + + for (uint32_t i = 0; i < 2; i++) + { + index = (index + 1) & 1; + if (!entries[start + index].valid) + { + entry_found = true; + break; + } + } + + if (!entry_found) + { + index = (index + 1) & 1; + } + + if (flags & ARM7_TLB_ABORT_D) + m_dtlb_entry_index[section] = index; + else + m_itlb_entry_index[section] = index; -bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags, bool no_exception) + return &entries[start + index]; +} + +arm7_cpu_device::tlb_entry *arm7_cpu_device::tlb_probe(const offs_t vaddr, const int flags) { - if (addr < 0x2000000) + const uint32_t section = (vaddr >> (COPRO_TLB_VADDR_FLTI_MASK_SHIFT + 2)) & 0xFFF; + tlb_entry *entries = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entries : m_itlb_entries; + const uint32_t start = section << 1; + uint32_t index = (flags & ARM7_TLB_ABORT_D) ? m_dtlb_entry_index[section] : m_itlb_entry_index[section]; + + if (m_tlb_log) + LOGMASKED(LOG_TLB, "%s: tlb_probe: vaddr %08x, section %02x, start %02x, index %d\n", machine().describe_context(), vaddr, section, start, index); + + for (uint32_t i = 0; i < 2; i++) { - addr += m_pid_offset; + 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; + } + } + if (m_tlb_log) + { + LOGMASKED(LOG_TLB, "%s: tlb_probe: skipped due to mismatch (valid %d, domain %02x, access %d, table_bits %08x, base_addr %08x, type %d\n", + machine().describe_context(), entries[position].valid ? 1 : 0, entries[position].domain, entries[position].access, + entries[position].table_bits, entries[position].base_addr, entries[position].type); + } + + index = (index - 1) & 1; } - uint32_t desc_lvl1 = m_program->read_dword(m_tlb_base_mask | ((addr & COPRO_TLB_VADDR_FLTI_MASK) >> COPRO_TLB_VADDR_FLTI_MASK_SHIFT)); + return nullptr; +} -#if ARM7_MMU_ENABLE_HACK - if ((m_r[eR15] == (m_mmu_enable_addr + 4)) || (m_r[eR15] == (m_mmu_enable_addr + 8))) +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) { - LOG( ( "ARM7: fetch flat, PC = %08x, vaddr = %08x\n", m_r[eR15], addr ) ); - return true; + 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; } - else +} + +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) { - m_mmu_enable_addr = 1; + 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; } -#endif +} - uint8_t tlb_type = desc_lvl1 & 3; - if (tlb_type == COPRO_TLB_SECTION_TABLE) +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) { - // Entry is a section - int fault = detect_fault(desc_lvl1, (desc_lvl1 >> 10) & 3, flags); - if (fault == FAULT_NONE) + case COPRO_TLB_TYPE_SECTION: + access = (uint8_t)((lvl2 >> 10) & 3); + table_bits = vaddr & COPRO_TLB_STABLE_MASK; + break; + case COPRO_TLB_TYPE_LARGE: { - addr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( addr & ~COPRO_TLB_SECTION_PAGE_MASK ); + 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; } - else + + case COPRO_TLB_TYPE_SMALL: { - if (no_exception) - return false; + 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) + { + 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(); + } + 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); + + LOGMASKED(LOG_MMU, "ARM7: Translating page table entry for %08x, lvl1_addr %08x, lvl1_desc %08x\n", vaddr, lvl1_addr, lvl1_desc); + + switch (lvl1_desc & 3) + { + case 0: // Unmapped + LOGMASKED(LOG_MMU, "ARM7: Translating page table entry for %08x, Unmapped, lvl1a %08x, lvl1d %08x\n", vaddr, lvl1_addr, lvl1_desc); if (flags & ARM7_TLB_ABORT_D) { - uint8_t domain = (desc_lvl1 >> 5) & 0xF; - LOG( ( "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 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(); - LOG( ( "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) ); } else if (flags & ARM7_TLB_ABORT_P) { - LOG( ( "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15] ) ); - m_pendingAbtP = true; - update_irq_state(); + 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); + + LOGMASKED(LOG_MMU, "ARM7: Translating page table entry for %08x, Coarse, lvl1a %08x, lvl1d %08x, lvl2a %08x, lvl2d %08x\n", vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc); + + 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; + } + + case 2: // Section Descriptor + LOGMASKED(LOG_MMU, "ARM7: Translating page table entry for %08x, Section, lvl1a %08x, lvl1d %08x\n", vaddr, lvl1_addr, lvl1_desc); + return page_table_finish_translation(vaddr, COPRO_TLB_TYPE_SECTION, lvl1_desc, lvl1_desc, flags, lvl1_addr, lvl1_addr); + + case 3: // Fine Table + { + 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); + + LOGMASKED(LOG_MMU, "ARM7: Translating page table entry for %08x, Fine, lvl1a %08x, lvl1d %08x, lvl2a %08x, lvl2d %08x\n", vaddr, lvl1_addr, lvl1_desc, lvl2_addr, lvl2_desc); + + 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) + { + 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) { - if (no_exception) - return false; + if (m_tlb_log) + { + LOGMASKED(LOG_TLB, "%s: translate_vaddr_to_paddr: found entry (domain %02x, access %d, table_bits %08x, base_addr %08x, type %d\n", + machine().describe_context(), entry->domain, entry->access, entry->table_bits, entry->base_addr, entry->type); + } - // Unmapped, generate a translation fault - if (flags & ARM7_TLB_ABORT_D) + const uint32_t access_result = tlb_check_permissions(entry, flags); + if (access_result == 0) { - LOG( ( "ARM7: Translation fault on unmapped virtual address, 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) { - LOG( ( "ARM7: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", m_r[eR15], addr ) ); - m_pendingAbtP = true; + 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: - if (no_exception) - return false; - - // Unmapped, generate a translation fault - if (flags & ARM7_TLB_ABORT_D) - { - uint8_t domain = (desc_lvl1 >> 5) & 0xF; - LOG( ( "ARM7: Translation fault on unmapped virtual address, 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) - { - LOG( ( "ARM7: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", addr, m_r[eR15] ) ); - m_pendingAbtP = true; - update_irq_state(); - } - 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 ); - } - else if (no_exception) - { - return false; - } - 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 - LOG( ( "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(); - LOG( ( "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) - { - LOG( ( "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", addr, m_r[eR15] ) ); - m_pendingAbtP = true; - update_irq_state(); - } - return false; - } - } - break; - case COPRO_TLB_TINY_PAGE: - // Tiny page descriptor - if( ( desc_lvl1 & 3 ) == 1 ) - { - LOG( ( "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; - } + if (m_tlb_log) + LOGMASKED(LOG_MMU, "No TLB entry for %08x yet, running page_table_translate\n", vaddr); + return page_table_translate(vaddr, flags); } +} - return true; +void arm7_cpu_device::translate_insn_command(const std::vector<std::string_view> ¶ms) +{ + translate_command(params, TR_FETCH); +} + +void arm7_cpu_device::translate_data_command(const std::vector<std::string_view> ¶ms) +{ + translate_command(params, TR_READ); } +void arm7_cpu_device::translate_command(const std::vector<std::string_view> ¶ms, int intention) +{ + uint64_t vaddr; + + if (!machine().debugger().console().validate_number_parameter(params[0], vaddr)) return; + + vaddr &= 0xffffffff; -bool arm7_cpu_device::memory_translate(int spacenum, int intention, offs_t &address) + offs_t paddr = (offs_t)vaddr; + address_space *space = nullptr; + bool can_translate = memory_translate(AS_PROGRAM, intention, paddr, space); + if (can_translate) + machine().debugger().console().printf("%s vaddr %08x => phys %08x\n", intention == TR_FETCH ? "instruction" : "data", (uint32_t)vaddr, paddr); + else + machine().debugger().console().printf("%s vaddr %08x => unmapped\n", intention == TR_FETCH ? "instruction" : "data"); +} + +bool arm7_cpu_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { + target_space = &space(spacenum); /* 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 ) ) + if (spacenum == AS_PROGRAM && (m_control & COPRO_CTRL_MMU_EN)) { - return arm7_tlb_translate(address, 0); + const int flags = intention == TR_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; } @@ -598,16 +960,18 @@ void arm7_cpu_device::postload() void arm7_cpu_device::device_start() { + init_ce_kernel_addrs(); + m_program = &space(AS_PROGRAM); if(m_program->endianness() == ENDIANNESS_LITTLE) { - auto cache = m_program->cache<2, 0, ENDIANNESS_LITTLE>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + m_program->cache(m_cachele); + m_pr32 = [this](offs_t address) -> u32 { return m_cachele.read_dword(address); }; + m_prptr = [this](offs_t address) -> const void * { return m_cachele.read_ptr(address); }; } else { - auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + m_program->cache(m_cachebe); + m_pr32 = [this](offs_t address) -> u32 { return m_cachebe.read_dword(address); }; + m_prptr = [this](offs_t address) -> const void * { return m_cachebe.read_ptr(address); }; } save_item(NAME(m_insn_prefetch_depth)); @@ -615,6 +979,9 @@ void arm7_cpu_device::device_start() save_item(NAME(m_insn_prefetch_index)); 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)); @@ -632,6 +999,20 @@ 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)); set_icountptr(m_icount); @@ -683,8 +1064,16 @@ 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(); + + if (debugger_enabled()) + { + using namespace std::placeholders; + machine().debugger().console().register_command("translate_insn", CMDFLAG_NONE, 1, 1, std::bind(&arm7_cpu_device::translate_insn_command, this, _1)); + machine().debugger().console().register_command("translate_data", CMDFLAG_NONE, 1, 1, std::bind(&arm7_cpu_device::translate_data_command, this, _1)); + } } @@ -705,7 +1094,6 @@ void arm946es_cpu_device::device_start() save_item(NAME(DTCM)); } - void arm7_cpu_device::state_export(const device_state_entry &entry) { switch (entry.index()) @@ -739,7 +1127,7 @@ void arm7_cpu_device::state_string_export(const device_state_entry &entry, std:: void arm7_cpu_device::device_reset() { - memset(m_r, 0, sizeof(m_r)); + std::fill(std::begin(m_r), std::end(m_r), 0); m_pendingIrq = false; m_pendingFiq = false; m_pendingAbtD = false; @@ -756,7 +1144,7 @@ void arm7_cpu_device::device_reset() m_fcsePID = 0; m_pid_offset = 0; m_domainAccessControl = 0; - memset(m_decoded_access_control, 0, sizeof(uint8_t) * 16); + std::fill_n(&m_decoded_access_control[0], 16, 0); /* start up in SVC mode with interrupts disabled. */ m_r[eCPSR] = I_MASK | F_MASK | 0x10; @@ -764,38 +1152,71 @@ void arm7_cpu_device::device_reset() m_r[eR15] = 0 | m_vectorbase; m_impstate.cache_dirty = true; -} + for (auto &entry : m_dtlb_entries) + { + entry.valid = false; + entry.domain = 0; + entry.access = 0; + entry.table_bits = 0; + entry.base_addr = 0; + entry.type = 0; + } + for (auto &entry : m_itlb_entries) + { + entry.valid = false; + entry.domain = 0; + entry.access = 0; + entry.table_bits = 0; + entry.base_addr = 0; + entry.type = 0; + } + std::fill(std::begin(m_dtlb_entry_index), std::end(m_dtlb_entry_index), 0); + std::fill(std::begin(m_itlb_entry_index), std::end(m_itlb_entry_index), 0); +} -#define UNEXECUTED() \ - m_r[eR15] += 4; \ - m_icount +=2; /* Any unexecuted instruction only takes 1 cycle (page 193) */ +void arm1176jzf_s_cpu_device::device_reset() +{ + arm7_cpu_device::device_reset(); + m_control = 0x00050078; +} void arm7_cpu_device::update_insn_prefetch(uint32_t curr_pc) { curr_pc &= ~3; if (m_insn_prefetch_address[m_insn_prefetch_index] != curr_pc) { + LOGMASKED(LOG_PREFETCH, "Prefetch addr %08x doesn't match curr_pc %08x, flushing prefetch buffer\n", m_insn_prefetch_address[m_insn_prefetch_index], curr_pc); m_insn_prefetch_count = 0; m_insn_prefetch_index = 0; } if (m_insn_prefetch_count == m_insn_prefetch_depth) + { + LOGMASKED(LOG_PREFETCH, "We have prefetched up to the max depth, bailing\n"); return; + } const uint32_t to_fetch = m_insn_prefetch_depth - m_insn_prefetch_count; const uint32_t start_index = (m_insn_prefetch_depth + (m_insn_prefetch_index - to_fetch)) % m_insn_prefetch_depth; //printf("need to prefetch %d instructions starting at index %d\n", to_fetch, start_index); + LOGMASKED(LOG_PREFETCH, "Need to fetch %d entries starting from index %d\n", to_fetch, start_index); uint32_t pc = curr_pc + m_insn_prefetch_count * 4; for (uint32_t i = 0; i < to_fetch; i++) { uint32_t index = (i + start_index) % m_insn_prefetch_depth; - if ((m_control & COPRO_CTRL_MMU_EN) && !arm7_tlb_translate(pc, ARM7_TLB_ABORT_P | ARM7_TLB_READ, true)) + LOGMASKED(LOG_PREFETCH, "About to get prefetch index %d from addr %08x\n", index, pc); + m_insn_prefetch_valid[index] = true; + offs_t physical_pc = pc; + if ((m_control & COPRO_CTRL_MMU_EN) && !translate_vaddr_to_paddr(physical_pc, ARM7_TLB_ABORT_P | ARM7_TLB_READ)) { + LOGMASKED(LOG_PREFETCH, "Unable to fetch, bailing\n"); + m_insn_prefetch_valid[index] = false; break; } - uint32_t op = m_pr32(pc); + uint32_t op = m_pr32(physical_pc); + LOGMASKED(LOG_PREFETCH, "Got op %08x\n", op); //printf("ipb[%d] <- %08x(%08x)\n", index, op, pc); m_insn_prefetch_buffer[index] = op; m_insn_prefetch_address[index] = pc; @@ -804,102 +1225,284 @@ void arm7_cpu_device::update_insn_prefetch(uint32_t curr_pc) } } -uint16_t arm7_cpu_device::insn_fetch_thumb(uint32_t pc) +bool arm7_cpu_device::insn_fetch_thumb(uint32_t pc, uint32_t &out_insn) { if (pc & 2) { - uint16_t insn = (uint16_t)(m_insn_prefetch_buffer[m_insn_prefetch_index] >> m_prefetch_word1_shift); - m_insn_prefetch_index = (m_insn_prefetch_index + 1) % m_insn_prefetch_count; + out_insn = (uint16_t)(m_insn_prefetch_buffer[m_insn_prefetch_index] >> m_prefetch_word1_shift); + bool valid = m_insn_prefetch_valid[m_insn_prefetch_index]; + m_insn_prefetch_index = (m_insn_prefetch_index + 1) % m_insn_prefetch_depth; m_insn_prefetch_count--; - return insn; + return valid; } - return (uint16_t)(m_insn_prefetch_buffer[m_insn_prefetch_index] >> m_prefetch_word0_shift); + out_insn = (uint16_t)(m_insn_prefetch_buffer[m_insn_prefetch_index] >> m_prefetch_word0_shift); + return m_insn_prefetch_valid[m_insn_prefetch_index]; } -uint32_t arm7_cpu_device::insn_fetch_arm(uint32_t pc) +bool arm7_cpu_device::insn_fetch_arm(uint32_t pc, uint32_t &out_insn) { //printf("ipb[%d] = %08x\n", m_insn_prefetch_index, m_insn_prefetch_buffer[m_insn_prefetch_index]); - uint32_t insn = m_insn_prefetch_buffer[m_insn_prefetch_index]; - m_insn_prefetch_index = (m_insn_prefetch_index + 1) % m_insn_prefetch_count; + out_insn = m_insn_prefetch_buffer[m_insn_prefetch_index]; + bool valid = m_insn_prefetch_valid[m_insn_prefetch_index]; + LOGMASKED(LOG_PREFETCH, "Fetched op %08x for PC %08x with %s entry from %08x\n", out_insn, pc, valid ? "valid" : "invalid", m_insn_prefetch_address[m_insn_prefetch_index]); + m_insn_prefetch_index = (m_insn_prefetch_index + 1) % m_insn_prefetch_depth; m_insn_prefetch_count--; - return insn; + return valid; } -int arm7_cpu_device::get_insn_prefetch_index(uint32_t address) +void arm7_cpu_device::add_ce_kernel_addr(offs_t addr, std::string value) { - address &= ~3; - for (uint32_t i = 0; i < m_insn_prefetch_depth; i++) - { - if (m_insn_prefetch_address[i] == address) - { - return (int)i; - } - } - return -1; + m_ce_kernel_addrs[addr - 0xf0000000] = value; + m_ce_kernel_addr_present[addr - 0xf0000000] = true; } +#include "cecalls.hxx" + void arm7_cpu_device::execute_run() { + auto const UNEXECUTED = [this] { m_r[eR15] += 4; m_icount += 2; }; // Any unexecuted instruction only takes 1 cycle (page 193) + + m_tlb_log = m_actual_log; + uint32_t insn; do { uint32_t pc = GET_PC; +#if PRINT_HAPYFSH2 + if (pc == 0xC0047374) + { + char substr_buf[4096]; + uint16_t substr_idx = 0; + bool zero_prepend = false; + uint8_t digit_count = 0; + uint32_t string_addr = (m_r[eR0] & 0x0fffffff) | 0x30000000; + uint8_t charval = 0; + uint32_t reg_idx = eR1; + do + { + charval = m_program->read_byte(string_addr); + string_addr++; + if (charval >= 0x20 && charval < 0x7f) + { + if (charval == '%') + { + bool still_processing = true; + uint8_t nextval = m_program->read_byte(string_addr); + string_addr++; + switch (nextval) + { + case 0: + printf("%%"); + charval = 0; + still_processing = false; + break; + case '%': + printf("%%"); + still_processing = false; + break; + case '0': + zero_prepend = true; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + digit_count = nextval - '0'; + break; + case 'd': + printf("%d", (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]); + still_processing = false; + reg_idx++; + break; + case 'l': + case 'u': + printf("%u", (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]); + still_processing = false; + reg_idx++; + break; + case 'x': + case 'p': + printf("%x", (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]); + still_processing = false; + reg_idx++; + break; + case 'o': + printf("%o", (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]); + still_processing = false; + reg_idx++; + break; + case 's': + { + uint32_t val = (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]; + uint32_t substring_addr = (val & 0x0fffffff) | 0x30000000; + reg_idx++; + bool end_found = false; + while (!end_found) + { + substr_buf[substr_idx] = m_program->read_byte(substring_addr); + if (substr_buf[substr_idx] == 0) + { + end_found = true; + } + substring_addr++; + substr_idx++; + } + substr_idx = 0; + printf("%s", substr_buf); + still_processing = false; + break; + } + } + while (still_processing) + { + uint8_t nextval2 = m_program->read_byte(string_addr); + string_addr++; + if (nextval2 == 0) + { + printf("%c%c", (char)charval, (char)nextval); + charval = 0; + break; + } + else if (nextval2 >= '1' && nextval2 <= '9') + { + digit_count = nextval2 - '0'; + } + else if (nextval2 == 'd') + { + uint32_t val = (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]; + switch (digit_count) + { + case 1: if (zero_prepend) { printf("%01d", val); } else { printf("%1d", val); } break; + case 2: if (zero_prepend) { printf("%02d", val); } else { printf("%2d", val); } break; + case 3: if (zero_prepend) { printf("%03d", val); } else { printf("%3d", val); } break; + case 4: if (zero_prepend) { printf("%04d", val); } else { printf("%4d", val); } break; + case 5: if (zero_prepend) { printf("%05d", val); } else { printf("%5d", val); } break; + case 6: if (zero_prepend) { printf("%06d", val); } else { printf("%6d", val); } break; + case 7: if (zero_prepend) { printf("%07d", val); } else { printf("%7d", val); } break; + case 8: if (zero_prepend) { printf("%08d", val); } else { printf("%8d", val); } break; + case 9: if (zero_prepend) { printf("%09d", val); } else { printf("%9d", val); } break; + } + reg_idx++; + still_processing = false; + } + else if (nextval2 == 'u' || nextval2 == 'l') + { + uint32_t val = (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]; + switch (digit_count) + { + case 1: if (zero_prepend) { printf("%01u", val); } else { printf("%1u", val); } break; + case 2: if (zero_prepend) { printf("%02u", val); } else { printf("%2u", val); } break; + case 3: if (zero_prepend) { printf("%03u", val); } else { printf("%3u", val); } break; + case 4: if (zero_prepend) { printf("%04u", val); } else { printf("%4u", val); } break; + case 5: if (zero_prepend) { printf("%05u", val); } else { printf("%5u", val); } break; + case 6: if (zero_prepend) { printf("%06u", val); } else { printf("%6u", val); } break; + case 7: if (zero_prepend) { printf("%07u", val); } else { printf("%7u", val); } break; + case 8: if (zero_prepend) { printf("%08u", val); } else { printf("%8u", val); } break; + case 9: if (zero_prepend) { printf("%09u", val); } else { printf("%9u", val); } break; + } + reg_idx++; + still_processing = false; + } + else if (nextval2 == 'x') + { + uint32_t val = (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]; + switch (digit_count) + { + case 1: if (zero_prepend) { printf("%01x", val); } else { printf("%1x", val); } break; + case 2: if (zero_prepend) { printf("%02x", val); } else { printf("%2x", val); } break; + case 3: if (zero_prepend) { printf("%03x", val); } else { printf("%3x", val); } break; + case 4: if (zero_prepend) { printf("%04x", val); } else { printf("%4x", val); } break; + case 5: if (zero_prepend) { printf("%05x", val); } else { printf("%5x", val); } break; + case 6: if (zero_prepend) { printf("%06x", val); } else { printf("%6x", val); } break; + case 7: if (zero_prepend) { printf("%07x", val); } else { printf("%7x", val); } break; + case 8: if (zero_prepend) { printf("%08x", val); } else { printf("%8x", val); } break; + case 9: if (zero_prepend) { printf("%09x", val); } else { printf("%9x", val); } break; + } + reg_idx++; + still_processing = false; + } + else if (nextval2 == 'o') + { + uint32_t val = (reg_idx >= eR4) ? m_program->read_dword(((m_r[eR13_SVC] & 0x0fffffff) | 0x30000000) + (reg_idx - eR4)) : m_r[reg_idx]; + switch (digit_count) + { + case 1: if (zero_prepend) { printf("%01o", val); } else { printf("%1o", val); } break; + case 2: if (zero_prepend) { printf("%02o", val); } else { printf("%2o", val); } break; + case 3: if (zero_prepend) { printf("%03o", val); } else { printf("%3o", val); } break; + case 4: if (zero_prepend) { printf("%04o", val); } else { printf("%4o", val); } break; + case 5: if (zero_prepend) { printf("%05o", val); } else { printf("%5o", val); } break; + case 6: if (zero_prepend) { printf("%06o", val); } else { printf("%6o", val); } break; + case 7: if (zero_prepend) { printf("%07o", val); } else { printf("%7o", val); } break; + case 8: if (zero_prepend) { printf("%08o", val); } else { printf("%8o", val); } break; + case 9: if (zero_prepend) { printf("%09o", val); } else { printf("%9o", val); } break; + } + reg_idx++; + still_processing = false; + } + else + { + printf("%c%c", (char)charval, (char)nextval); + still_processing = false; + } + } + } + else + { + printf("%c", (char)charval); + } + } + } while (charval != 0); + printf("\n"); + } +#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])) { - offs_t raddr; - pc = m_r[eR15]; // "In Thumb state, bit [0] is undefined and must be ignored. Bits [31:1] contain the PC." - raddr = pc & (~1); + offs_t const raddr = pc & ~uint32_t(1); - if ( m_control & COPRO_CTRL_MMU_EN ) + if (!insn_fetch_thumb(raddr, insn)) { - if (!arm7_tlb_translate(raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ)) - { - goto skip_exec; - } + m_pendingAbtP = true; + update_irq_state(); + goto skip_exec; } - - insn = insn_fetch_thumb(raddr); (this->*thumb_handler[(insn & 0xffc0) >> 6])(pc, insn); - } else { - offs_t raddr; - /* load 32 bit instruction */ // "In ARM state, bits [1:0] of r15 are undefined and must be ignored. Bits [31:2] contain the PC." - raddr = pc & (~3); + offs_t const raddr = pc & ~uint32_t(3); - if ( m_control & COPRO_CTRL_MMU_EN ) + if (!insn_fetch_arm(raddr, insn)) { - if (!arm7_tlb_translate(raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ)) +#if PRINT_CE_KERNEL + if (raddr >= 0xf0000000) { - goto skip_exec; + print_ce_kernel_address(raddr - 0xf0000000); } - } - -#if 0 - if (MODE26) - { - uint32_t 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)\n", pc, temp1, temp2); - } #endif - - insn = insn_fetch_arm(raddr); + m_pendingAbtP = true; + update_irq_state(); + goto skip_exec; + } int op_offset = 0; /* process condition codes for this instruction */ @@ -984,29 +1587,32 @@ 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; } void arm7_cpu_device::execute_set_input(int irqline, int state) { - switch (irqline) { - case ARM7_IRQ_LINE: /* IRQ */ - m_pendingIrq = state ? true : false; + switch (irqline) + { + case ARM7_IRQ_LINE: // IRQ + m_pendingIrq = state != 0; break; - case ARM7_FIRQ_LINE: /* FIRQ */ - m_pendingFiq = state ? true : false; + case ARM7_FIRQ_LINE: // FIQ + m_pendingFiq = state != 0; break; case ARM7_ABORT_EXCEPTION: - m_pendingAbtD = state ? true : false; + m_pendingAbtD = state != 0; break; case ARM7_ABORT_PREFETCH_EXCEPTION: - m_pendingAbtP = state ? true : false; + m_pendingAbtP = state != 0; break; case ARM7_UNDEFINE_EXCEPTION: - m_pendingUnd = state ? true : false; + m_pendingUnd = state != 0; break; } @@ -1015,6 +1621,24 @@ void arm7_cpu_device::execute_set_input(int irqline, int state) } +void arm7_cpu_device::set_irq(int state) +{ + assert((machine().scheduler().currently_executing() == static_cast<device_execute_interface *>(this)) || !machine().scheduler().currently_executing()); + m_pendingIrq = state != 0; + update_irq_state(); + arm7_check_irq_state(); +} + + +void arm7_cpu_device::set_fiq(int state) +{ + assert((machine().scheduler().currently_executing() == static_cast<device_execute_interface *>(this)) || !machine().scheduler().currently_executing()); + m_pendingFiq = state != 0; + update_irq_state(); + arm7_check_irq_state(); +} + + std::unique_ptr<util::disasm_interface> arm7_cpu_device::create_disassembler() { return std::make_unique<arm7_disassembler>(this); @@ -1028,13 +1652,13 @@ bool arm7_cpu_device::get_t_flag() const /* ARM system coprocessor support */ -WRITE32_MEMBER( arm7_cpu_device::arm7_do_callback ) +void arm7_cpu_device::arm7_do_callback(uint32_t data) { m_pendingUnd = true; update_irq_state(); } -READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) +uint32_t arm7_cpu_device::arm7_rt_r_callback(offs_t offset) { uint32_t opcode = offset; uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; @@ -1072,7 +1696,7 @@ READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) } else { - LOG( ("ARM7: Unhandled coprocessor %d (archFlags %x)\n", cpnum, m_archFlags) ); + LOGMASKED(LOG_COPRO_UNKNOWN, "ARM7: Unhandled coprocessor %d (archFlags %x)\n", cpnum, m_archFlags); m_pendingUnd = true; update_irq_state(); return 0; @@ -1089,7 +1713,7 @@ READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) case 11: case 12: // RESERVED - LOG( ( "arm7_rt_r_callback CR%d, RESERVED\n", cReg ) ); + LOGMASKED(LOG_COPRO_RESERVED, "arm7_rt_r_callback CR%d, RESERVED\n", cReg); break; case 0: // ID switch(op2) @@ -1111,20 +1735,21 @@ READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) data = 0; break; } - LOG( ( "arm7_rt_r_callback, ID %02x (%02x) -> %08x (PC=%08x)\n",op2,m_archRev,data,GET_PC ) ); + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, ID %02x (%02x) -> %08x (PC=%08x)\n",op2,m_archRev,data,GET_PC); break; case 1: // Control data = COPRO_CTRL | 0x70; // bits 4-6 always read back as "1" (bit 3 too in XScale) break; case 2: // Translation Table Base + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, TLB Base, PC = %08x\n", m_r[eR15]); data = COPRO_TLB_BASE; break; case 3: // Domain Access Control - LOG( ( "arm7_rt_r_callback, Domain Access Control\n" ) ); + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Domain Access Control, PC = %08x\n", m_r[eR15]); data = COPRO_DOMAIN_ACCESS_CONTROL; break; case 5: // Fault Status - LOG( ( "arm7_rt_r_callback, Fault Status\n" ) ); + 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; @@ -1132,25 +1757,25 @@ READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) } break; case 6: // Fault Address - LOG( ( "arm7_rt_r_callback, Fault Address\n" ) ); + 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) - LOG( ( "arm7_rt_r_callback, Read PID\n" ) ); + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Read PID, PC = %08x\n", m_r[eR15]); data = COPRO_FCSE_PID; break; case 14: // Read Breakpoint - LOG( ( "arm7_rt_r_callback, Read Breakpoint\n" ) ); + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Read Breakpoint\n"); break; case 15: // Test, Clock, Idle - LOG( ( "arm7_rt_r_callback, Test / Clock / Idle \n" ) ); + LOGMASKED(LOG_COPRO_READS, "arm7_rt_r_callback, Test / Clock / Idle \n"); break; } return data; } -WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) +void arm7_cpu_device::arm7_rt_w_callback(offs_t offset, uint32_t data) { uint32_t opcode = offset; uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; @@ -1163,19 +1788,19 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) { if (cpnum == 14) { - LOG( ("arm7_rt_w_callback: write %x to XScale CP14 reg %d\n", data, cReg) ); + LOGMASKED(LOG_COPRO_UNKNOWN, "arm7_rt_w_callback: write %x to XScale CP14 reg %d\n", data, cReg); return; } else { - LOG( ("ARM7: Unhandled coprocessor %d\n", cpnum) ); + LOGMASKED(LOG_COPRO_UNKNOWN, "ARM7: Unhandled coprocessor %d\n", cpnum); m_pendingUnd = true; update_irq_state(); return; } } - switch( cReg ) + switch (cReg) { case 0: case 4: @@ -1183,28 +1808,28 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) case 11: case 12: // RESERVED - LOG( ( "arm7_rt_w_callback CR%d, RESERVED = %08x\n", cReg, data) ); + LOGMASKED(LOG_COPRO_RESERVED, "arm7_rt_w_callback CR%d, RESERVED = %08x\n", cReg, data); break; case 1: // Control - LOG( ( "arm7_rt_w_callback Control = %08x (%d) (%d)\n", data, op2, op3 ) ); - LOG( ( " MMU:%d, Address Fault:%d, Data Cache:%d, Write Buffer:%d\n", + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Control = %08x (%d) (%d)\n", data, op2, op3); + LOGMASKED(LOG_COPRO_WRITES, " MMU:%d, Address Fault:%d, Data Cache:%d, Write Buffer:%d\n", data & COPRO_CTRL_MMU_EN, ( data & COPRO_CTRL_ADDRFAULT_EN ) >> COPRO_CTRL_ADDRFAULT_EN_SHIFT, ( data & COPRO_CTRL_DCACHE_EN ) >> COPRO_CTRL_DCACHE_EN_SHIFT, - ( data & COPRO_CTRL_WRITEBUF_EN ) >> COPRO_CTRL_WRITEBUF_EN_SHIFT ) ); - LOG( ( " Endianness:%d, System:%d, ROM:%d, Instruction Cache:%d\n", + ( data & COPRO_CTRL_WRITEBUF_EN ) >> COPRO_CTRL_WRITEBUF_EN_SHIFT); + LOGMASKED(LOG_COPRO_WRITES, " Endianness:%d, System:%d, ROM:%d, Instruction Cache:%d\n", ( data & COPRO_CTRL_ENDIAN ) >> COPRO_CTRL_ENDIAN_SHIFT, ( data & COPRO_CTRL_SYSTEM ) >> COPRO_CTRL_SYSTEM_SHIFT, ( 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 ) ); + ( data & COPRO_CTRL_ICACHE_EN ) >> COPRO_CTRL_ICACHE_EN_SHIFT); + LOGMASKED(LOG_COPRO_WRITES, " 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)) { - >m_mmu_enable_addr = R15; + m_mmu_enable_addr = R15; } 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"); } @@ -1213,12 +1838,12 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) COPRO_CTRL = data & COPRO_CTRL_MASK; break; case 2: // Translation Table Base - LOG( ( "arm7_rt_w_callback TLB Base = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Base = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); COPRO_TLB_BASE = data; m_tlb_base_mask = data & COPRO_TLB_BASE_MASK; break; case 3: // Domain Access Control - LOG( ( "arm7_rt_w_callback Domain Access Control = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Domain Access Control = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); COPRO_DOMAIN_ACCESS_CONTROL = data; for (int i = 0; i < 32; i += 2) { @@ -1226,7 +1851,7 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) } break; case 5: // Fault Status - LOG( ( "arm7_rt_w_callback Fault Status = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Fault Status = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); switch (op3) { case 0: COPRO_FAULT_STATUS_D = data; break; @@ -1234,33 +1859,114 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) } break; case 6: // Fault Address - LOG( ( "arm7_rt_w_callback Fault Address = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Fault Address = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); COPRO_FAULT_ADDRESS = data; break; case 7: // Cache Operations -// LOG( ( "arm7_rt_w_callback Cache Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); +// LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Cache Ops = %08x (%d) (%d)\n", data, op2, op3); break; case 8: // TLB Operations - LOG( ( "arm7_rt_w_callback TLB Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "%s: arm7_rt_w_callback TLB Ops = %08x (%d) (%d), PC = %08x\n", machine().describe_context(), data, op2, op3, m_r[eR15]); + switch (op2) + { + case 0: + switch (op3) + { + case 5: + // Flush I + for (uint32_t i = 0; i < std::size(m_itlb_entries); i++) + { + m_itlb_entries[i].valid = false; + } + break; + case 6: + // Flush D + for (uint32_t i = 0; i < std::size(m_dtlb_entries); i++) + { + m_dtlb_entries[i].valid = false; + } + break; + case 7: + // Flush I+D + for (uint32_t i = 0; i < std::size(m_dtlb_entries); 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: + switch (op3) + { + case 5: + { + // Flush I single entry + tlb_entry *entry = tlb_probe(data, ARM7_TLB_ABORT_P); + if (entry) + { + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Ops: Successfully flushed I entry for %08x\n", data); + entry->valid = false; + } + break; + } + + case 6: + { + // Flush D single entry + tlb_entry *entry = tlb_probe(data, ARM7_TLB_ABORT_D); + if (entry) + { + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Ops: Successfully flushed D entry for %08x\n", data); + entry->valid = false; + } + break; + } + case 7: + { + // Flush unified single entry + tlb_entry *entry = tlb_probe(data, ARM7_TLB_ABORT_D); + if (entry) + { + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Ops: Successfully flushed D entry for %08x\n", data); + entry->valid = false; + } + entry = tlb_probe(data, ARM7_TLB_ABORT_P); + if (entry) + { + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback TLB Ops: Successfully flushed I entry for %08x\n", data); + entry->valid = false; + } + break; + } + default: + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Unsupported TLB Op\n"); + break; + } + break; + } break; case 9: // Read Buffer Operations - LOG( ( "arm7_rt_w_callback Read Buffer Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Read Buffer Ops = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); break; case 13: // Write Process ID (PID) - LOG( ( "arm7_rt_w_callback Write PID = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Write PID = %08x (%d) (%d), PC = %08x\n", data, op2, op3, m_r[eR15]); COPRO_FCSE_PID = data; m_pid_offset = (((COPRO_FCSE_PID >> 25) & 0x7F)) * 0x2000000; break; case 14: // Write Breakpoint - LOG( ( "arm7_rt_w_callback Write Breakpoint = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Write Breakpoint = %08x (%d) (%d)\n", data, op2, op3); break; case 15: // Test, Clock, Idle - LOG( ( "arm7_rt_w_callback Test / Clock / Idle = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback Test / Clock / Idle = %08x (%d) (%d)\n", data, op2, op3); break; } } -READ32_MEMBER( arm946es_cpu_device::arm7_rt_r_callback ) +uint32_t arm946es_cpu_device::arm7_rt_r_callback(offs_t offset) { uint32_t opcode = offset; uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; @@ -1314,7 +2020,7 @@ READ32_MEMBER( arm946es_cpu_device::arm7_rt_r_callback ) return data; } -WRITE32_MEMBER( arm946es_cpu_device::arm7_rt_w_callback ) +void arm946es_cpu_device::arm7_rt_w_callback(offs_t offset, uint32_t data) { uint32_t opcode = offset; uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; @@ -1465,8 +2171,7 @@ uint32_t arm946es_cpu_device::arm7_cpu_read32(uint32_t addr) if (addr & 3) { uint32_t *wp = (uint32_t *)&ITCM[(addr & ~3)&0x7fff]; - result = *wp; - result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + result = rotr_32(*wp, 8 * (addr & 3)); } else { @@ -1479,8 +2184,7 @@ uint32_t arm946es_cpu_device::arm7_cpu_read32(uint32_t addr) if (addr & 3) { uint32_t *wp = (uint32_t *)&DTCM[(addr & ~3)&0x3fff]; - result = *wp; - result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + result = rotr_32(*wp, 8 * (addr & 3)); } else { @@ -1492,8 +2196,7 @@ uint32_t arm946es_cpu_device::arm7_cpu_read32(uint32_t addr) { if (addr & 3) { - result = m_program->read_dword(addr & ~3); - result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + result = rotr_32(m_program->read_dword(addr & ~3), 8 * (addr & 3)); } else { @@ -1541,7 +2244,7 @@ void arm7_cpu_device::arm7_dt_r_callback(uint32_t insn, uint32_t *prn) uint8_t cpn = (insn >> 8) & 0xF; if ((m_archFlags & ARCHFLAG_XSCALE) && (cpn == 0)) { - LOG( ( "arm7_dt_r_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC ) ); + LOGMASKED(LOG_DSP, "arm7_dt_r_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC); } else { @@ -1556,7 +2259,7 @@ void arm7_cpu_device::arm7_dt_w_callback(uint32_t insn, uint32_t *prn) uint8_t cpn = (insn >> 8) & 0xF; if ((m_archFlags & ARCHFLAG_XSCALE) && (cpn == 0)) { - LOG( ( "arm7_dt_w_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC ) ); + LOGMASKED(LOG_DSP, "arm7_dt_w_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC); } else { @@ -1565,6 +2268,44 @@ void arm7_cpu_device::arm7_dt_w_callback(uint32_t insn, uint32_t *prn) } } +uint32_t arm1176jzf_s_cpu_device::arm7_rt_r_callback(offs_t offset) +{ + uint32_t opcode = offset; + uint8_t crn = (opcode & INSN_COPRO_CREG) >> INSN_COPRO_CREG_SHIFT; + uint8_t op1 = (opcode & INSN_COPRO_OP1) >> INSN_COPRO_OP1_SHIFT; + uint8_t op2 = (opcode & INSN_COPRO_OP2) >> INSN_COPRO_OP2_SHIFT; + uint8_t crm = opcode & INSN_COPRO_OP3; + uint8_t cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT; + uint32_t data = 0; + +// printf("arm7946: copro %d write %x to cReg %d op2 %d op3 %d (mask %08x)\n", cpnum, data, cReg, op2, op3, mem_mask); + + if (cpnum == 15) + { + if(crn == 0 && op1 == 0 && crm == 0 && op2 == 0) data = 0x410FB767; //ARM1176JZF-S Main ID. + if(crn == 1 && op1 == 0 && crm == 0 && op2 == 0) data = m_control; + } + + return data; +} + +void arm1176jzf_s_cpu_device::arm7_rt_w_callback(offs_t offset, uint32_t data) +{ + uint32_t opcode = offset; + uint8_t crn = (opcode & INSN_COPRO_CREG) >> INSN_COPRO_CREG_SHIFT; + uint8_t op1 = (opcode & INSN_COPRO_OP1) >> INSN_COPRO_OP1_SHIFT; + uint8_t op2 = (opcode & INSN_COPRO_OP2) >> INSN_COPRO_OP2_SHIFT; + uint8_t crm = opcode & INSN_COPRO_OP3; + uint8_t cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT; + +// printf("arm7946: copro %d write %x to cReg %d op2 %d op3 %d (mask %08x)\n", cpnum, data, cReg, op2, op3, mem_mask); + + if (cpnum == 15) + { + LOGMASKED(LOG_COPRO_WRITES, "arm7_rt_w_callback: CP15 CRn %02x Op1 %02x CRm %02x Op2 %02x data %08x\n", crn, op1, crm, op2, data); + if(crn == 1 && op1 == 0 && crm == 0 && op2 == 0) m_control = data; + } +} /*************************************************************************** * Default Memory Handlers @@ -1573,7 +2314,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; } @@ -1588,7 +2329,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; } @@ -1602,7 +2343,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; } @@ -1617,7 +2358,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; } @@ -1625,8 +2366,7 @@ uint32_t arm7_cpu_device::arm7_cpu_read32(uint32_t addr) if (addr & 3) { - result = m_program->read_dword(addr & ~3); - result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + result = rotr_32(m_program->read_dword(addr & ~3), 8 * (addr & 3)); } else { @@ -1642,7 +2382,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; } @@ -1662,7 +2402,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; } |