diff options
Diffstat (limited to 'src/devices/cpu/arm7')
-rw-r--r-- | src/devices/cpu/arm7/arm7.cpp | 442 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7.h | 82 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7core.h | 2 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7core.hxx | 7 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7dasm.cpp | 72 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7dasm.h | 51 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7ops.cpp | 78 | ||||
-rw-r--r-- | src/devices/cpu/arm7/arm7thmb.cpp | 9 |
8 files changed, 638 insertions, 105 deletions
diff --git a/src/devices/cpu/arm7/arm7.cpp b/src/devices/cpu/arm7/arm7.cpp index 551f940f692..6538e573935 100644 --- a/src/devices/cpu/arm7/arm7.cpp +++ b/src/devices/cpu/arm7/arm7.cpp @@ -53,6 +53,7 @@ DEFINE_DEVICE_TYPE(ARM920T, arm920t_cpu_device, "arm920t", "ARM920T") DEFINE_DEVICE_TYPE(ARM946ES, arm946es_cpu_device, "arm946es", "ARM946ES") DEFINE_DEVICE_TYPE(PXA255, pxa255_cpu_device, "pxa255", "Intel XScale PXA255") DEFINE_DEVICE_TYPE(SA1110, sa1110_cpu_device, "sa1110", "Intel StrongARM SA-1110") +DEFINE_DEVICE_TYPE(IGS036, igs036_cpu_device, "igs036", "IGS036") arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : arm7_cpu_device(mconfig, ARM7, tag, owner, clock, 4, ARCHFLAG_T, ENDIANNESS_LITTLE) @@ -62,9 +63,12 @@ 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, uint8_t archFlags, endianness_t endianness) : cpu_device(mconfig, type, tag, owner, clock) , m_program_config("program", endianness, 32, 32, 0) + , m_prefetch_word0_shift(endianness == ENDIANNESS_LITTLE ? 0 : 16) + , m_prefetch_word1_shift(endianness == ENDIANNESS_LITTLE ? 16 : 0) , m_endian(endianness) , m_archRev(archRev) , m_archFlags(archFlags) + , m_vectorbase(0) , m_pc(0) { memset(m_r, 0x00, sizeof(m_r)); @@ -73,6 +77,14 @@ arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type arch = ARM9_COPRO_ID_ARCH_V4T; m_copro_id = ARM9_COPRO_ID_MFR_ARM | arch | ARM9_COPRO_ID_PART_GENERICARM7; + + // 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); + m_insn_prefetch_count = 0; + m_insn_prefetch_index = 0; } @@ -137,12 +149,24 @@ arm920t_cpu_device::arm920t_cpu_device(const machine_config &mconfig, const char arm946es_cpu_device::arm946es_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : arm9_cpu_device(mconfig, ARM946ES, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E, ENDIANNESS_LITTLE) + : arm9_cpu_device(mconfig, ARM946ES, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E, ENDIANNESS_LITTLE), + cp15_control(0x78) { m_copro_id = ARM9_COPRO_ID_MFR_ARM | ARM9_COPRO_ID_ARCH_V5TE | ARM9_COPRO_ID_PART_ARM946 | ARM9_COPRO_ID_STEP_ARM946_A0; + + memset(ITCM, 0, 0x8000); + memset(DTCM, 0, 0x4000); + + cp15_itcm_base = 0xffffffff; + cp15_itcm_size = 0; + cp15_itcm_end = 0; + cp15_dtcm_base = 0xffffffff; + cp15_dtcm_size = 0; + cp15_dtcm_end = 0; + cp15_itcm_reg = cp15_dtcm_reg = 0; } pxa255_cpu_device::pxa255_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) @@ -165,6 +189,13 @@ sa1110_cpu_device::sa1110_cpu_device(const machine_config &mconfig, const char * | ARM9_COPRO_ID_STEP_SA1110_A0; } +// unknown configuration +igs036_cpu_device::igs036_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : arm9_cpu_device(mconfig, IGS036, tag, owner, clock, 5, ARCHFLAG_T | ARCHFLAG_E, ENDIANNESS_LITTLE) +{ +} + + device_memory_interface::space_config_vector arm7_cpu_device::memory_space_config() const { return space_config_vector { @@ -334,7 +365,7 @@ int arm7_cpu_device::detect_fault(int desc_lvl1, int ap, int flags) } -bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) +bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags, bool no_exception) { if (addr < 0x2000000) { @@ -366,6 +397,9 @@ bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) } else { + if (no_exception) + return false; + if (flags & ARM7_TLB_ABORT_D) { uint8_t domain = (desc_lvl1 >> 5) & 0xF; @@ -389,6 +423,9 @@ bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) } else if (tlb_type == COPRO_TLB_UNMAPPED) { + if (no_exception) + return false; + // Unmapped, generate a translation fault if (flags & ARM7_TLB_ABORT_D) { @@ -420,6 +457,9 @@ bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) switch( desc_lvl2 & 3 ) { case COPRO_TLB_UNMAPPED: + if (no_exception) + return false; + // Unmapped, generate a translation fault if (flags & ARM7_TLB_ABORT_D) { @@ -450,6 +490,10 @@ bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) { 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) @@ -511,7 +555,7 @@ bool arm7_cpu_device::memory_translate(int spacenum, int intention, offs_t &addr void arm7_cpu_device::device_start() { m_program = &space(AS_PROGRAM); - m_direct = &m_program->direct(); + m_direct = m_program->direct<0>(); save_item(NAME(m_r)); save_item(NAME(m_pendingIrq)); @@ -631,7 +675,7 @@ void arm7_cpu_device::device_reset() /* start up in SVC mode with interrupts disabled. */ m_r[eCPSR] = I_MASK | F_MASK | 0x10; SwitchMode(eARM7_MODE_SVC); - m_r[eR15] = 0; + m_r[eR15] = 0 | m_vectorbase; m_impstate.cache_dirty = true; } @@ -641,6 +685,73 @@ void arm7_cpu_device::device_reset() m_r[eR15] += 4; \ m_icount +=2; /* Any unexecuted instruction only takes 1 cycle (page 193) */ +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) + { + m_insn_prefetch_count = 0; + m_insn_prefetch_index = 0; + } + + if (m_insn_prefetch_count == m_insn_prefetch_depth) + 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); + + 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)) + { + break; + } + uint32_t op = m_direct->read_dword(pc); + //printf("ipb[%d] <- %08x(%08x)\n", index, op, pc); + m_insn_prefetch_buffer[index] = op; + m_insn_prefetch_address[index] = pc; + m_insn_prefetch_count++; + pc += 4; + } +} + +uint16_t arm7_cpu_device::insn_fetch_thumb(uint32_t pc) +{ + 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; + m_insn_prefetch_count--; + return insn; + } + return (uint16_t)(m_insn_prefetch_buffer[m_insn_prefetch_index] >> m_prefetch_word0_shift); +} + +uint32_t arm7_cpu_device::insn_fetch_arm(uint32_t pc) +{ + //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; + m_insn_prefetch_count--; + return insn; +} + +int arm7_cpu_device::get_insn_prefetch_index(uint32_t address) +{ + 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; +} + void arm7_cpu_device::execute_run() { uint32_t insn; @@ -649,6 +760,8 @@ void arm7_cpu_device::execute_run() { uint32_t pc = GET_PC; + update_insn_prefetch(pc); + debugger_instruction_hook(this, pc); /* handle Thumb instructions if active */ @@ -669,7 +782,7 @@ void arm7_cpu_device::execute_run() } } - insn = m_direct->read_word(raddr); + insn = insn_fetch_thumb(raddr); (this->*thumb_handler[(insn & 0xffc0) >> 6])(pc, insn); } @@ -700,7 +813,7 @@ void arm7_cpu_device::execute_run() } #endif - insn = m_direct->read_dword(raddr); + insn = insn_fetch_arm(raddr); int op_offset = 0; /* process condition codes for this instruction */ @@ -816,27 +929,14 @@ void arm7_cpu_device::execute_set_input(int irqline, int state) } -offs_t arm7_cpu_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) +util::disasm_interface *arm7_cpu_device::create_disassembler() { - extern CPU_DISASSEMBLE( arm7arm ); - extern CPU_DISASSEMBLE( arm7thumb ); - extern CPU_DISASSEMBLE( arm7arm_be ); - extern CPU_DISASSEMBLE( arm7thumb_be ); + return new arm7_disassembler(this); +} - if (T_IS_SET(m_r[eCPSR])) - { - if ( m_endian == ENDIANNESS_BIG ) - return CPU_DISASSEMBLE_NAME(arm7thumb_be)(this, stream, pc, oprom, opram, options); - else - return CPU_DISASSEMBLE_NAME(arm7thumb)(this, stream, pc, oprom, opram, options); - } - else - { - if ( m_endian == ENDIANNESS_BIG ) - return CPU_DISASSEMBLE_NAME(arm7arm_be)(this, stream, pc, oprom, opram, options); - else - return CPU_DISASSEMBLE_NAME(arm7arm)(this, stream, pc, oprom, opram, options); - } +bool arm7_cpu_device::get_t_flag() const +{ + return T_IS_SET(m_r[eCPSR]); } @@ -1074,6 +1174,298 @@ WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) } } +READ32_MEMBER( arm946es_cpu_device::arm7_rt_r_callback ) +{ + uint32_t opcode = offset; + uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; + uint8_t op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT; + uint8_t op3 = opcode & INSN_COPRO_OP3; + uint8_t cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT; + uint32_t data = 0; + + //printf("arm7946: read cpnum %d cReg %d op2 %d op3 %d (%x)\n", cpnum, cReg, op2, op3, opcode); + if (cpnum == 15) + { + switch( cReg ) + { + case 0: + switch (op2) + { + case 0: // chip ID + data = 0x41059461; + break; + + case 1: // cache ID + data = 0x0f0d2112; + break; + + case 2: // TCM size + data = (6 << 6) | (5 << 18); + break; + } + break; + + case 1: + return cp15_control; + break; + + case 9: + if (op3 == 1) + { + if (op2 == 0) + { + return cp15_dtcm_reg; + } + else + { + return cp15_itcm_reg; + } + } + break; + } + } + + return data; +} + +WRITE32_MEMBER( arm946es_cpu_device::arm7_rt_w_callback ) +{ + uint32_t opcode = offset; + uint8_t cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; + uint8_t op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT; + uint8_t op3 = 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) + { + switch (cReg) + { + case 1: // control + cp15_control = data; + RefreshDTCM(); + RefreshITCM(); + break; + + case 2: // Protection Unit cacheability bits + break; + + case 3: // write bufferability bits for PU + break; + + case 5: // protection unit region controls + break; + + case 6: // protection unit region controls 2 + break; + + case 7: // cache commands + break; + + case 9: // cache lockdown & TCM controls + if (op3 == 1) + { + if (op2 == 0) + { + cp15_dtcm_reg = data; + RefreshDTCM(); + } + else if (op2 == 1) + { + cp15_itcm_reg = data; + RefreshITCM(); + } + } + break; + } + } +} + +void arm946es_cpu_device::RefreshDTCM() +{ + if (cp15_control & (1<<16)) + { + cp15_dtcm_base = (cp15_dtcm_reg & ~0xfff); + cp15_dtcm_size = 512 << ((cp15_dtcm_reg & 0x3f) >> 1); + cp15_dtcm_end = cp15_dtcm_base + cp15_dtcm_size; + //printf("DTCM enabled: base %08x size %x\n", cp15_dtcm_base, cp15_dtcm_size); + } + else + { + cp15_dtcm_base = 0xffffffff; + cp15_dtcm_size = cp15_dtcm_end = 0; + } +} + +void arm946es_cpu_device::RefreshITCM() +{ + if (cp15_control & (1<<18)) + { + cp15_itcm_base = 0; //(cp15_itcm_reg & ~0xfff); + cp15_itcm_size = 512 << ((cp15_itcm_reg & 0x3f) >> 1); + cp15_itcm_end = cp15_itcm_base + cp15_itcm_size; + //printf("ITCM enabled: base %08x size %x\n", cp15_dtcm_base, cp15_dtcm_size); + } + else + { + cp15_itcm_base = 0xffffffff; + cp15_itcm_size = cp15_itcm_end = 0; + } +} + +void arm946es_cpu_device::arm7_cpu_write32(uint32_t addr, uint32_t data) +{ + addr &= ~3; + + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + uint32_t *wp = (uint32_t *)&ITCM[addr&0x7fff]; + *wp = data; + return; + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + uint32_t *wp = (uint32_t *)&DTCM[addr&0x3fff]; + *wp = data; + return; + } + + m_program->write_dword(addr, data); +} + + +void arm946es_cpu_device::arm7_cpu_write16(uint32_t addr, uint16_t data) +{ + addr &= ~1; + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + uint16_t *wp = (uint16_t *)&ITCM[addr&0x7fff]; + *wp = data; + return; + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + uint16_t *wp = (uint16_t *)&DTCM[addr&0x3fff]; + *wp = data; + return; + } + + m_program->write_word(addr, data); +} + +void arm946es_cpu_device::arm7_cpu_write8(uint32_t addr, uint8_t data) +{ + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + ITCM[addr&0x7fff] = data; + return; + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + DTCM[addr&0x3fff] = data; + return; + } + + m_program->write_byte(addr, data); +} + +uint32_t arm946es_cpu_device::arm7_cpu_read32(uint32_t addr) +{ + uint32_t result; + + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + if (addr & 3) + { + uint32_t *wp = (uint32_t *)&ITCM[(addr & ~3)&0x7fff]; + result = *wp; + result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + } + else + { + uint32_t *wp = (uint32_t *)&ITCM[addr&0x7fff]; + result = *wp; + } + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + if (addr & 3) + { + uint32_t *wp = (uint32_t *)&DTCM[(addr & ~3)&0x3fff]; + result = *wp; + result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + } + else + { + uint32_t *wp = (uint32_t *)&DTCM[addr&0x3fff]; + result = *wp; + } + } + else + { + if (addr & 3) + { + result = m_program->read_dword(addr & ~3); + result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + } + else + { + result = m_program->read_dword(addr); + } + } + return result; +} + +uint16_t arm946es_cpu_device::arm7_cpu_read16(uint32_t addr) +{ + uint16_t result; + + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + uint16_t *wp = (uint16_t *)&ITCM[(addr & ~1)&0x7fff]; + result = *wp; + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + uint16_t *wp = (uint16_t *)&DTCM[(addr & ~1)&0x3fff]; + result = *wp; + } + else + { + result = m_program->read_word(addr & ~1); + } + + if (addr & 1) + { + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); + } + + return result; +} + +uint8_t arm946es_cpu_device::arm7_cpu_read8(uint32_t addr) +{ + if ((addr >= cp15_itcm_base) && (addr <= cp15_itcm_end)) + { + return ITCM[addr & 0x7fff]; + } + else if ((addr >= cp15_dtcm_base) && (addr <= cp15_dtcm_end)) + { + return DTCM[addr & 0x3fff]; + } + + // Handle through normal 8 bit handler (for 32 bit cpu) + return m_program->read_byte(addr); +} + +WRITE32_MEMBER(igs036_cpu_device::arm7_rt_w_callback) +{ + arm7_cpu_device::arm7_rt_w_callback(space, offset, data, mem_mask); + /* disable the MMU for now, it doesn't seem to set up valid mappings + so could be entirely different here */ + COPRO_CTRL &= ~COPRO_CTRL_MMU_EN; +} void arm7_cpu_device::arm7_dt_r_callback(uint32_t insn, uint32_t *prn) { diff --git a/src/devices/cpu/arm7/arm7.h b/src/devices/cpu/arm7/arm7.h index 3f7f82fed8a..2fde4b1805a 100644 --- a/src/devices/cpu/arm7/arm7.h +++ b/src/devices/cpu/arm7/arm7.h @@ -23,6 +23,8 @@ #pragma once +#include "arm7dasm.h" + #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" @@ -31,6 +33,9 @@ #define ARM7_MAX_FASTRAM 4 #define ARM7_MAX_HOTSPOTS 16 +#define MCFG_ARM_HIGH_VECTORS() \ + arm7_cpu_device::set_high_vectors(*device); + /*************************************************************************** COMPILER-SPECIFIC OPTIONS @@ -46,12 +51,18 @@ * PUBLIC FUNCTIONS ***************************************************************************************************/ -class arm7_cpu_device : public cpu_device +class arm7_cpu_device : public cpu_device, public arm7_disassembler::config { public: // construction/destruction arm7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + static void set_high_vectors(device_t &device) + { + arm7_cpu_device &dev = downcast<arm7_cpu_device &>(device); + dev.m_vectorbase = 0xffff0000; + } + protected: enum { @@ -121,13 +132,26 @@ protected: virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; // device_disasm_interface overrides - virtual uint32_t disasm_min_opcode_bytes() const override { return 2; } - virtual uint32_t disasm_max_opcode_bytes() const override { return 4; } - virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override; + virtual util::disasm_interface *create_disassembler() override; + virtual bool get_t_flag() const override; address_space_config m_program_config; uint32_t m_r[/*NUM_REGS*/37]; + + void update_insn_prefetch(uint32_t curr_pc); + virtual uint16_t insn_fetch_thumb(uint32_t pc); + uint32_t insn_fetch_arm(uint32_t pc); + int get_insn_prefetch_index(uint32_t address); + + uint32_t m_insn_prefetch_depth; + uint32_t m_insn_prefetch_count; + uint32_t m_insn_prefetch_index; + uint32_t m_insn_prefetch_buffer[3]; + uint32_t m_insn_prefetch_address[3]; + const uint32_t m_prefetch_word0_shift; + const uint32_t m_prefetch_word1_shift; + bool m_pendingIrq; bool m_pendingFiq; bool m_pendingAbtD; @@ -138,7 +162,7 @@ protected: int m_icount; endianness_t m_endian; address_space *m_program; - direct_read_data *m_direct; + direct_read_data<0> *m_direct; /* Coprocessor Registers */ uint32_t m_control; @@ -154,6 +178,8 @@ protected: uint8_t m_archRev; // ARM architecture revision (3, 4, and 5 are valid) uint8_t m_archFlags; // architecture flags + uint32_t m_vectorbase; + //#if ARM7_MMU_ENABLE_HACK // uint32_t mmu_enable_addr; // workaround for "MMU is enabled when PA != VA" problem //#endif @@ -201,22 +227,22 @@ protected: void arm9ops_e(uint32_t insn); void set_cpsr(uint32_t val); - bool arm7_tlb_translate(offs_t &addr, int flags); + bool arm7_tlb_translate(offs_t &addr, int flags, bool no_exception = false); uint32_t arm7_tlb_get_second_level_descriptor( 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(); - void arm7_cpu_write32(uint32_t addr, uint32_t data); - void arm7_cpu_write16(uint32_t addr, uint16_t data); - void arm7_cpu_write8(uint32_t addr, uint8_t data); - uint32_t arm7_cpu_read32(uint32_t addr); - uint16_t arm7_cpu_read16(uint32_t addr); - uint8_t arm7_cpu_read8(uint32_t addr); + virtual void arm7_cpu_write32(uint32_t addr, uint32_t data); + virtual void arm7_cpu_write16(uint32_t addr, uint16_t data); + virtual void arm7_cpu_write8(uint32_t addr, uint8_t data); + virtual uint32_t arm7_cpu_read32(uint32_t addr); + virtual uint16_t arm7_cpu_read16(uint32_t addr); + virtual uint8_t arm7_cpu_read8(uint32_t addr); // Coprocessor support DECLARE_WRITE32_MEMBER( arm7_do_callback ); - DECLARE_READ32_MEMBER( arm7_rt_r_callback ); - DECLARE_WRITE32_MEMBER( arm7_rt_w_callback ); + virtual DECLARE_READ32_MEMBER( arm7_rt_r_callback ); + virtual DECLARE_WRITE32_MEMBER( arm7_rt_w_callback ); void arm7_dt_r_callback(uint32_t insn, uint32_t *prn); void arm7_dt_w_callback(uint32_t insn, uint32_t *prn); @@ -588,6 +614,25 @@ class arm946es_cpu_device : public arm9_cpu_device public: // construction/destruction arm946es_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // 946E-S has Protection Unit instead of ARM MMU so CP15 is quite different + virtual DECLARE_READ32_MEMBER( arm7_rt_r_callback ) override; + virtual DECLARE_WRITE32_MEMBER( arm7_rt_w_callback ) override; + + virtual void arm7_cpu_write32(uint32_t addr, uint32_t data) override; + virtual void arm7_cpu_write16(uint32_t addr, uint16_t data) override; + virtual void arm7_cpu_write8(uint32_t addr, uint8_t data) override; + virtual uint32_t arm7_cpu_read32(uint32_t addr) override; + virtual uint16_t arm7_cpu_read16(uint32_t addr) override; + virtual uint8_t arm7_cpu_read8(uint32_t addr) override; + +private: + uint32_t cp15_control, cp15_itcm_base, cp15_dtcm_base, cp15_itcm_size, cp15_dtcm_size; + uint32_t cp15_itcm_end, cp15_dtcm_end, cp15_itcm_reg, cp15_dtcm_reg; + uint8_t ITCM[0x8000], DTCM[0x4000]; + + void RefreshITCM(); + void RefreshDTCM(); }; @@ -606,6 +651,14 @@ public: sa1110_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class igs036_cpu_device : public arm9_cpu_device +{ +public: + // construction/destruction + igs036_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual DECLARE_WRITE32_MEMBER( arm7_rt_w_callback ) override; +}; + DECLARE_DEVICE_TYPE(ARM7, arm7_cpu_device) DECLARE_DEVICE_TYPE(ARM7_BE, arm7_be_cpu_device) @@ -615,5 +668,6 @@ DECLARE_DEVICE_TYPE(ARM920T, arm920t_cpu_device) DECLARE_DEVICE_TYPE(ARM946ES, arm946es_cpu_device) DECLARE_DEVICE_TYPE(PXA255, pxa255_cpu_device) DECLARE_DEVICE_TYPE(SA1110, sa1110_cpu_device) +DECLARE_DEVICE_TYPE(IGS036, igs036_cpu_device) #endif // MAME_CPU_ARM7_ARM7_H diff --git a/src/devices/cpu/arm7/arm7core.h b/src/devices/cpu/arm7/arm7core.h index 14d6f6267e8..9ae499ae109 100644 --- a/src/devices/cpu/arm7/arm7core.h +++ b/src/devices/cpu/arm7/arm7core.h @@ -163,7 +163,7 @@ struct arm_state int m_icount; endianness_t m_endian; address_space *m_program; - direct_read_data *m_direct; + direct_read_data<0> *m_direct; /* Coprocessor Registers */ uint32_t m_control; diff --git a/src/devices/cpu/arm7/arm7core.hxx b/src/devices/cpu/arm7/arm7core.hxx index 0e418209e73..0fbe5f00868 100644 --- a/src/devices/cpu/arm7/arm7core.hxx +++ b/src/devices/cpu/arm7/arm7core.hxx @@ -136,6 +136,7 @@ void arm7_cpu_device::arm7_check_irq_state() set_cpsr(GET_CPSR | I_MASK | F_MASK); /* Mask both IRQ & FIQ */ set_cpsr(GET_CPSR & ~T_MASK); R15 = 0x1c; /* IRQ Vector address */ + R15 |= m_vectorbase; if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; return; } @@ -159,6 +160,7 @@ void arm7_cpu_device::arm7_check_irq_state() temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; set_cpsr(temp); /* Mask IRQ */ } + R15 |= m_vectorbase; if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; return; } @@ -172,7 +174,7 @@ void arm7_cpu_device::arm7_check_irq_state() SetRegister(SPSR, cpsr); /* Save current CPSR */ set_cpsr(GET_CPSR | I_MASK); /* Mask IRQ */ set_cpsr(GET_CPSR & ~T_MASK); - R15 = 0x0c; /* IRQ Vector address */ + R15 = 0x0c | m_vectorbase; /* IRQ Vector address */ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; m_pendingAbtP = false; update_irq_state(); @@ -196,7 +198,7 @@ void arm7_cpu_device::arm7_check_irq_state() SetRegister(SPSR, cpsr); /* Save current CPSR */ set_cpsr(GET_CPSR | I_MASK); /* Mask IRQ */ set_cpsr(GET_CPSR & ~T_MASK); - R15 = 0x04; /* IRQ Vector address */ + R15 = 0x04 | m_vectorbase; /* IRQ Vector address */ if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; m_pendingUnd = false; update_irq_state(); @@ -230,6 +232,7 @@ void arm7_cpu_device::arm7_check_irq_state() temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; set_cpsr(temp); /* Mask IRQ */ } + R15 |= m_vectorbase; if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; m_pendingSwi = false; update_irq_state(); diff --git a/src/devices/cpu/arm7/arm7dasm.cpp b/src/devices/cpu/arm7/arm7dasm.cpp index 3d38ea29872..efe3459898c 100644 --- a/src/devices/cpu/arm7/arm7dasm.cpp +++ b/src/devices/cpu/arm7/arm7dasm.cpp @@ -23,16 +23,17 @@ ******************************************************************************/ #include "emu.h" +#include "arm7dasm.h" #include "arm7core.h" -static void WritePadding(std::ostream &stream, std::streampos start_position) +void arm7_disassembler::WritePadding(std::ostream &stream, std::streampos start_position) { std::streamoff difference = stream.tellp() - start_position; for (std::streamoff i = difference; i < 8; i++) stream << ' '; } -static void DasmCoProc_RT(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) +void arm7_disassembler::DasmCoProc_RT(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) { /* co processor register transfer */ /* xxxx 1110 oooL nnnn dddd cccc ppp1 mmmm */ @@ -51,7 +52,7 @@ static void DasmCoProc_RT(std::ostream &stream, uint32_t opcode, const char *pCo if((opcode>>5)&7) util::stream_format( stream, ", %d",(opcode>>5)&7); } -static void DasmCoProc_DT(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) +void arm7_disassembler::DasmCoProc_DT(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) { /* co processor data transfer */ /* xxxx 111P UNWL nnnn dddd pppp oooooooo */ @@ -75,7 +76,7 @@ static void DasmCoProc_DT(std::ostream &stream, uint32_t opcode, const char *pCo util::stream_format(stream, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":""); } -static void DasmCoProc_DO(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) +void arm7_disassembler::DasmCoProc_DO(std::ostream &stream, uint32_t opcode, const char *pConditionCode, std::streampos start_position) { /* co processor data operation */ /* xxxx 1110 oooo nnnn dddd cccc ppp0 mmmm */ @@ -88,7 +89,7 @@ static void DasmCoProc_DO(std::ostream &stream, uint32_t opcode, const char *pCo if((opcode>>5)&7) util::stream_format(stream, ", %d",(opcode>>5)&7); } -static void WriteImmediateOperand( std::ostream &stream, uint32_t opcode ) +void arm7_disassembler::WriteImmediateOperand( std::ostream &stream, uint32_t opcode ) { /* rrrrbbbbbbbb */ uint32_t imm; @@ -100,7 +101,7 @@ static void WriteImmediateOperand( std::ostream &stream, uint32_t opcode ) util::stream_format( stream, ", #$%x", imm ); } -static void WriteDataProcessingOperand( std::ostream &stream, uint32_t opcode, int printOp0, int printOp1, int printOp2 ) +void arm7_disassembler::WriteDataProcessingOperand( std::ostream &stream, uint32_t opcode, int printOp0, int printOp1, int printOp2 ) { /* ccccctttmmmm */ static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; @@ -142,7 +143,7 @@ static void WriteDataProcessingOperand( std::ostream &stream, uint32_t opcode, i } } -static void WriteRegisterOperand1( std::ostream &stream, uint32_t opcode ) +void arm7_disassembler::WriteRegisterOperand1( std::ostream &stream, uint32_t opcode ) { /* ccccctttmmmm */ static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; @@ -172,7 +173,7 @@ static void WriteRegisterOperand1( std::ostream &stream, uint32_t opcode ) } /* WriteRegisterOperand */ -static void WriteBranchAddress( std::ostream &stream, uint32_t pc, uint32_t opcode, bool h_bit ) +void arm7_disassembler::WriteBranchAddress( std::ostream &stream, uint32_t pc, uint32_t opcode, bool h_bit ) { opcode <<= 2; if (h_bit && (opcode & 0x04000000)) @@ -188,7 +189,7 @@ static void WriteBranchAddress( std::ostream &stream, uint32_t pc, uint32_t opco util::stream_format( stream, "$%x", pc ); } /* WriteBranchAddress */ -static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode ) +u32 arm7_disassembler::arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode ) { static const char *const pConditionCodeTable[16] = { @@ -212,14 +213,22 @@ static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode if( (opcode&0xfe000000)==0xfa000000 ) //bits 31-25 == 1111 101 (BLX - v5) { - /* BLX */ + /* BLX(1) */ util::stream_format( stream, "BLX" ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; WritePadding(stream, start_position); WriteBranchAddress( stream, pc, opcode, true ); } + else if( (opcode&0x0ff000f0)==0x01200030 ) // (BLX - v5) + { + /* BLX(2) */ + util::stream_format( stream, "BLX" ); + dasmflags = STEP_OVER; + WritePadding(stream, start_position); + util::stream_format( stream, "R%d",(opcode&0xf)); + } else if( (opcode&0x0ffffff0)==0x012fff10 ) //bits 27-4 == 000100101111111111110001 { /* Branch and Exchange (BX) */ @@ -228,7 +237,7 @@ static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode WritePadding(stream, start_position); util::stream_format( stream, "R%d",(opcode&0xf)); if ((opcode & 0x0f) == 14) - dasmflags = DASMFLAG_STEP_OUT; + dasmflags = STEP_OUT; } else if ((opcode & 0x0ff000f0) == 0x01600010) // CLZ - v5 { @@ -492,7 +501,7 @@ static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode case 0x0d: /* look for mov pc,lr */ if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) - dasmflags = DASMFLAG_STEP_OUT; + dasmflags = STEP_OUT; case 0x0f: WriteDataProcessingOperand(stream, opcode, 1, 0, 1); break; @@ -641,7 +650,7 @@ static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode if( opcode&0x01000000 ) { util::stream_format( stream, "BL" ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; } else { @@ -680,16 +689,16 @@ static uint32_t arm7_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode util::stream_format( stream, "SWI%s $%x", pConditionCode, opcode&0x00ffffff ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; } else { util::stream_format( stream, "Undefined" ); } - return dasmflags | DASMFLAG_SUPPORTED; + return 4 | dasmflags | SUPPORTED; } -static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) +u32 arm7_disassembler::thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) { std::streampos start_position = stream.tellp(); uint32_t dasmflags = 0; @@ -970,7 +979,7 @@ static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) rd = ( ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8; util::stream_format( stream, "BX R%d", rd ); if (rd == 14) - dasmflags = DASMFLAG_STEP_OUT; + dasmflags = STEP_OUT; break; case 0x2: rd = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; @@ -1279,7 +1288,7 @@ static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) { addr = ( ( opcode & THUMB_BLOP_OFFS ) << 1 ) & 0xfffc; util::stream_format( stream, "BLX (LO) %08x", addr ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; } else { @@ -1295,7 +1304,7 @@ static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) if( opcode & THUMB_BLOP_LO ) { util::stream_format( stream, "BL (LO) %08x", ( opcode & THUMB_BLOP_OFFS ) << 1 ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; } else { @@ -1305,7 +1314,7 @@ static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) addr |= 0xff800000; } util::stream_format( stream, "BL (HI) %08x", addr ); - dasmflags = DASMFLAG_STEP_OVER; + dasmflags = STEP_OVER; } break; default: @@ -1313,25 +1322,22 @@ static uint32_t thumb_disasm(std::ostream &stream, uint32_t pc, uint16_t opcode) break; } - return dasmflags | DASMFLAG_SUPPORTED; + return 2 | dasmflags | SUPPORTED; } -CPU_DISASSEMBLE( arm7arm ) +arm7_disassembler::arm7_disassembler(config *conf) : m_config(conf) { - return arm7_disasm(stream, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24)) | 4; } -CPU_DISASSEMBLE( arm7arm_be ) +u32 arm7_disassembler::opcode_alignment() const { - return arm7_disasm(stream, pc, oprom[3] | (oprom[2] << 8) | (oprom[1] << 16) | (oprom[0] << 24)) | 4; + return m_config->get_t_flag() ? 2 : 4; } -CPU_DISASSEMBLE( arm7thumb ) +offs_t arm7_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) { - return thumb_disasm(stream, pc, oprom[0] | (oprom[1] << 8)) | 2; -} - -CPU_DISASSEMBLE( arm7thumb_be ) -{ - return thumb_disasm(stream, pc, oprom[1] | (oprom[0] << 8)) | 2; + if(m_config->get_t_flag()) + return thumb_disasm(stream, pc, opcodes.r16(pc)); + else + return arm7_disasm(stream, pc, opcodes.r32(pc)); } diff --git a/src/devices/cpu/arm7/arm7dasm.h b/src/devices/cpu/arm7/arm7dasm.h new file mode 100644 index 00000000000..9f90b47308f --- /dev/null +++ b/src/devices/cpu/arm7/arm7dasm.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7dasm.c + * Portable ARM7TDMI Core Emulator - Disassembler + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + *****************************************************************************/ + +#ifndef MAME_CPU_ARM7_ARM7DASM_H +#define MAME_CPU_ARM7_ARM7DASM_H + +#pragma once + +class arm7_disassembler : public util::disasm_interface +{ +public: + class config { + public: + virtual ~config() = default; + virtual bool get_t_flag() const = 0; + }; + + arm7_disassembler(config *conf); + + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + config *m_config; + + void WritePadding(std::ostream &stream, std::streampos start_position); + void DasmCoProc_RT(std::ostream &stream, u32 opcode, const char *pConditionCode, std::streampos start_position); + void DasmCoProc_DT(std::ostream &stream, u32 opcode, const char *pConditionCode, std::streampos start_position); + void DasmCoProc_DO(std::ostream &stream, u32 opcode, const char *pConditionCode, std::streampos start_position); + void WriteImmediateOperand( std::ostream &stream, u32 opcode ); + void WriteDataProcessingOperand( std::ostream &stream, u32 opcode, int printOp0, int printOp1, int printOp2 ); + void WriteRegisterOperand1( std::ostream &stream, u32 opcode ); + void WriteBranchAddress( std::ostream &stream, u32 pc, u32 opcode, bool h_bit ); + u32 arm7_disasm( std::ostream &stream, u32 pc, u32 opcode ); + u32 thumb_disasm(std::ostream &stream, u32 pc, u16 opcode); +}; + + +#endif diff --git a/src/devices/cpu/arm7/arm7ops.cpp b/src/devices/cpu/arm7/arm7ops.cpp index ea10a36be4d..084634a77c0 100644 --- a/src/devices/cpu/arm7/arm7ops.cpp +++ b/src/devices/cpu/arm7/arm7ops.cpp @@ -66,18 +66,12 @@ uint32_t arm7_cpu_device::decodeShift(uint32_t insn, uint32_t *pCarry) if ((insn & 0x80) == 0x80) LOG(("%08x: RegShift ERROR (p36)\n", R15)); #endif - - // see p35 for check on this - //k = GetRegister(k >> 1) & 0x1f; - // Keep only the bottom 8 bits for a Register Shift k = GetRegister(k >> 1) & 0xff; if (k == 0) /* Register shift by 0 is a no-op */ { // LOG(("%08x: NO-OP Regshift\n", R15)); - /* TODO this is wrong for at least ROR by reg with lower - * 5 bits 0 but lower 8 bits non zero */ if (pCarry) *pCarry = GET_CPSR & C_MASK; return rm; @@ -145,11 +139,19 @@ uint32_t arm7_cpu_device::decodeShift(uint32_t insn, uint32_t *pCarry) case 3: /* ROR and RRX */ if (k) { - while (k > 32) - k -= 32; - if (pCarry) - *pCarry = rm & (1 << (k - 1)); - return ROR(rm, k); + k &= 31; + if (k) + { + if (pCarry) + *pCarry = rm & (1 << (k - 1)); + return ROR(rm, k); + } + else + { + if (pCarry) + *pCarry = rm & SIGN_BIT; + return rm; + } } else { @@ -262,22 +264,13 @@ int arm7_cpu_device::storeInc(uint32_t pat, uint32_t rbv, int mode) int arm7_cpu_device::storeDec(uint32_t pat, uint32_t rbv, int mode) { - int i, result = 0, cnt; - // pre-count the # of registers being stored - for (i = 15; i >= 0; i--) - { - if ((pat >> i) & 1) - { - result++; + int const result = population_count_32(pat & 0x0000ffff); - // starting address - rbv -= 4; - } - } + // adjust starting address + rbv -= (result << 2); - cnt = 0; - for (i = 0; i <= 15; i++) + for (int i = 0; i <= 15; i++) { if ((pat >> i) & 1) { @@ -285,8 +278,8 @@ int arm7_cpu_device::storeDec(uint32_t pat, uint32_t rbv, int mode) if (i == 15) /* R15 is plus 12 from address of STM */ LOG(("%08x: StoreDec on R15\n", R15)); #endif - WRITE32(rbv + (cnt * 4), GetModeRegister(mode, i)); - cnt++; + WRITE32(rbv, GetModeRegister(mode, i)); + rbv += 4; } } return result; @@ -387,8 +380,8 @@ void arm7_cpu_device::HandleBranch(uint32_t insn, bool h_bit) off |= (insn & 0x01000000) >> 23; } - /* Save PC into LR if this is a branch with link */ - if (insn & INSN_BL) + /* Save PC into LR if this is a branch with link or a BLX */ + if ((insn & INSN_BL) || ((m_archRev >= 5) && ((insn & 0xfe000000) == 0xfa000000))) { SetRegister(14, R15 + 4); } @@ -501,6 +494,11 @@ void arm7_cpu_device::HandleMemSingle(uint32_t insn) R15 = (R15 & ~0x03FFFFFC) /* N Z C V I F M1 M0 */ | ((data - 4) & 0x03FFFFFC); // LDR, PC takes 2S + 2N + 1I (5 total cycles) ARM7_ICOUNT -= 2; + if ((data & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } } else { @@ -1380,6 +1378,12 @@ void arm7_cpu_device::HandleMemBlock(uint32_t insn) SwitchMode(temp & 3); } } + else + if ((R15 & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } // LDM PC - takes 2 extra cycles ARM7_ICOUNT -= 2; } @@ -1437,6 +1441,12 @@ void arm7_cpu_device::HandleMemBlock(uint32_t insn) SwitchMode(temp & 3); } } + else + if ((R15 & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } // LDM PC - takes 2 extra cycles ARM7_ICOUNT -= 2; } @@ -1650,6 +1660,18 @@ void arm7_cpu_device::arm7ops_0123(uint32_t insn) R15--; } } + else if ((insn & 0x0ff000f0) == 0x01200030) // BLX Rn - v5 + { + // save link address + SetRegister(14, R15 + 4); + + R15 = GetRegister(insn & 0x0f); + // If new PC address has A0 set, switch to Thumb mode + if (R15 & 1) { + set_cpsr(GET_CPSR|T_MASK); + R15--; + } + } else if ((insn & 0x0ff000f0) == 0x01600010) // CLZ - v5 { uint32_t rm = insn&0xf; diff --git a/src/devices/cpu/arm7/arm7thmb.cpp b/src/devices/cpu/arm7/arm7thmb.cpp index 251e5b16408..0d25d62fcf3 100644 --- a/src/devices/cpu/arm7/arm7thmb.cpp +++ b/src/devices/cpu/arm7/arm7thmb.cpp @@ -1557,18 +1557,21 @@ void arm7_cpu_device::tg0e_0(uint32_t pc, uint32_t op) void arm7_cpu_device::tg0e_1(uint32_t pc, uint32_t op) { + /* BLX (LO) */ + uint32_t addr = GetRegister(14); addr += (op & THUMB_BLOP_OFFS) << 1; addr &= 0xfffffffc; - SetRegister(14, (R15 + 4) | 1); + SetRegister(14, (R15 + 2) | 1); R15 = addr; set_cpsr(GET_CPSR & ~T_MASK); } - /* BL */ void arm7_cpu_device::tg0f_0(uint32_t pc, uint32_t op) { + /* BL (HI) */ + uint32_t addr = (op & THUMB_BLOP_OFFS) << 12; if (addr & (1 << 22)) { @@ -1581,6 +1584,8 @@ void arm7_cpu_device::tg0f_0(uint32_t pc, uint32_t op) void arm7_cpu_device::tg0f_1(uint32_t pc, uint32_t op) /* BL */ { + /* BL (LO) */ + uint32_t addr = GetRegister(14) & ~1; addr += (op & THUMB_BLOP_OFFS) << 1; SetRegister(14, (R15 + 2) | 1); |