diff options
Diffstat (limited to 'src/devices/cpu/arm7/arm7.cpp')
-rw-r--r-- | src/devices/cpu/arm7/arm7.cpp | 442 |
1 files changed, 417 insertions, 25 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) { |