summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/arm7/arm7.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/arm7/arm7.cpp')
-rw-r--r--src/devices/cpu/arm7/arm7.cpp442
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)
{