summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/arm7
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/arm7')
-rw-r--r--src/devices/cpu/arm7/arm7.cpp442
-rw-r--r--src/devices/cpu/arm7/arm7.h82
-rw-r--r--src/devices/cpu/arm7/arm7core.h2
-rw-r--r--src/devices/cpu/arm7/arm7core.hxx7
-rw-r--r--src/devices/cpu/arm7/arm7dasm.cpp72
-rw-r--r--src/devices/cpu/arm7/arm7dasm.h51
-rw-r--r--src/devices/cpu/arm7/arm7ops.cpp78
-rw-r--r--src/devices/cpu/arm7/arm7thmb.cpp9
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 &params)
{
- 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 &params) 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);