From c4b79a2a089935081ec39f5e26bdbf7a0b68bf79 Mon Sep 17 00:00:00 2001 From: arbee Date: Sun, 19 Nov 2017 17:39:24 -0500 Subject: [PATCH] arm7: Flesh out ARM946ES, add movable DTCM and ITCM support. [R. Belmont] --- src/devices/cpu/arm7/arm7.cpp | 298 +++++++++++++++++++++++++++++++++- src/devices/cpu/arm7/arm7.h | 33 +++- 2 files changed, 323 insertions(+), 8 deletions(-) diff --git a/src/devices/cpu/arm7/arm7.cpp b/src/devices/cpu/arm7/arm7.cpp index 6c745cec5f9..2f547d3eb7c 100644 --- a/src/devices/cpu/arm7/arm7.cpp +++ b/src/devices/cpu/arm7/arm7.cpp @@ -149,12 +149,23 @@ 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; } pxa255_cpu_device::pxa255_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) @@ -1231,6 +1242,291 @@ 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); diff --git a/src/devices/cpu/arm7/arm7.h b/src/devices/cpu/arm7/arm7.h index 38b7d185b63..8a72a8bb1a8 100644 --- a/src/devices/cpu/arm7/arm7.h +++ b/src/devices/cpu/arm7/arm7.h @@ -231,16 +231,16 @@ protected: 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 ); + 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); @@ -613,6 +613,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(); };