diff options
Diffstat (limited to 'src/devices/cpu/mips/mips1.cpp')
-rw-r--r-- | src/devices/cpu/mips/mips1.cpp | 112 |
1 files changed, 80 insertions, 32 deletions
diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index c2a34e47e73..26260b836b4 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -54,9 +54,9 @@ DEFINE_DEVICE_TYPE(R3071, r3071_device, "r3071", "IDT R3071") DEFINE_DEVICE_TYPE(R3081, r3081_device, "r3081", "IDT R3081") DEFINE_DEVICE_TYPE(SONYPS2_IOP, iop_device, "sonyiop", "Sony Playstation 2 IOP") -ALLOW_SAVE_TYPE(mips1core_device_base::branch_state_t); +ALLOW_SAVE_TYPE(mips1core_device_base::branch_state); -mips1core_device_base::mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size) +mips1core_device_base::mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size) : cpu_device(mconfig, type, tag, owner, clock) , m_program_config_be("program", ENDIANNESS_BIG, 32, 32) , m_program_config_le("program", ENDIANNESS_LITTLE, 32, 32) @@ -71,64 +71,64 @@ mips1core_device_base::mips1core_device_base(const machine_config &mconfig, devi { } -mips1_device_base::mips1_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size) +mips1_device_base::mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size) : mips1core_device_base(mconfig, type, tag, owner, clock, cpurev, icache_size, dcache_size) , m_fcr0(0) { } -r2000_device::r2000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r2000_device::r2000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R2000, tag, owner, clock, 0x0100, icache_size, dcache_size) { } -r2000a_device::r2000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r2000a_device::r2000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R2000A, tag, owner, clock, 0x0210, icache_size, dcache_size) { } -r3000_device::r3000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r3000_device::r3000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R3000, tag, owner, clock, 0x0220, icache_size, dcache_size) { } -r3000a_device::r3000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r3000a_device::r3000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R3000A, tag, owner, clock, 0x0230, icache_size, dcache_size) { } -r3041_device::r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +r3041_device::r3041_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : mips1core_device_base(mconfig, R3041, tag, owner, clock, 0x0700, 2048, 512) { } -r3051_device::r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +r3051_device::r3051_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : mips1core_device_base(mconfig, R3051, tag, owner, clock, 0x0200, 4096, 2048) { } -r3052_device::r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +r3052_device::r3052_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : mips1core_device_base(mconfig, R3052, tag, owner, clock, 0x0200, 8192, 2048) { } -r3052e_device::r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +r3052e_device::r3052e_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : mips1_device_base(mconfig, R3052E, tag, owner, clock, 0x0200, 8192, 2048) { } -r3071_device::r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r3071_device::r3071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R3071, tag, owner, clock, 0x0200, icache_size, dcache_size) { } -r3081_device::r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) +r3081_device::r3081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size) : mips1_device_base(mconfig, R3081, tag, owner, clock, 0x0200, icache_size, dcache_size) { set_fpu(0x0300); } -iop_device::iop_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +iop_device::iop_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : mips1core_device_base(mconfig, SONYPS2_IOP, tag, owner, clock, 0x001f, 4096, 1024) { m_endianness = ENDIANNESS_LITTLE; @@ -184,6 +184,8 @@ void mips1core_device_base::device_start() // initialise cpu id register m_cop0[COP0_PRId] = m_cpurev; + m_cop0[COP0_Cause] = 0; + m_r[0] = 0; } @@ -197,6 +199,10 @@ void r3041_device::device_start() state_add(MIPS1_COP0 + COP0_Count, "Count", m_cop0[COP0_Count]); state_add(MIPS1_COP0 + COP0_PortSize, "PortSize", m_cop0[COP0_PortSize]); state_add(MIPS1_COP0 + COP0_Compare, "Compare", m_cop0[COP0_Compare]); + + m_cop0[COP0_BusCtrl] = 0x20130b00U; + m_cop0[COP0_Config] = 0x40000000U; + m_cop0[COP0_PortSize] = 0; } void mips1core_device_base::device_reset() @@ -212,6 +218,14 @@ void mips1core_device_base::device_reset() m_bus_error = false; } +void r3041_device::device_reset() +{ + mips1core_device_base::device_reset(); + + m_cop0[COP0_Count] = 0; + m_cop0[COP0_Compare] = 0x00ffffffU; +} + void mips1core_device_base::execute_run() { // core execution loop @@ -649,13 +663,8 @@ bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t } else if (SR & SR_KUc) { - if (!machine().side_effects_disabled()) - { - // exception - m_cop0[COP0_BadVAddr] = address; + address_error(intention, address); - generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); - } return false; } } @@ -861,6 +870,21 @@ void mips1core_device_base::generate_exception(u32 exception, bool refill) debugger_privilege_hook(); } +void mips1core_device_base::address_error(int intention, u32 const address) +{ + if (!machine().side_effects_disabled() && !(intention & TRANSLATE_DEBUG_MASK)) + { + logerror("address_error 0x%08x (%s)\n", address, machine().describe_context()); + + m_cop0[COP0_BadVAddr] = address; + + generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); + + // address errors shouldn't typically occur, so a breakpoint is handy + machine().debug_break(); + } +} + void mips1core_device_base::handle_cop0(u32 const op) { switch (RSREG) @@ -1032,7 +1056,7 @@ void mips1core_device_base::handle_cop3(u32 const op) void mips1core_device_base::lwl(u32 const op) { offs_t const offset = SIMMVAL + m_r[RSREG]; - load<u32>(offset & ~3, [this, op, offset](u32 temp) + load<u32, false>(offset, [this, op, offset](u32 temp) { unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3; @@ -1043,7 +1067,7 @@ void mips1core_device_base::lwl(u32 const op) void mips1core_device_base::lwr(u32 const op) { offs_t const offset = SIMMVAL + m_r[RSREG]; - load<u32>(offset & ~3, [this, op, offset](u32 temp) + load<u32, false>(offset, [this, op, offset](u32 temp) { unsigned const shift = ((offset & 0x3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3; @@ -1056,7 +1080,7 @@ void mips1core_device_base::swl(u32 const op) offs_t const offset = SIMMVAL + m_r[RSREG]; unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3; - store<u32>(offset & ~3, m_r[RTREG] >> shift, 0xffffffffU >> shift); + store<u32, false>(offset, m_r[RTREG] >> shift, 0xffffffffU >> shift); } void mips1core_device_base::swr(u32 const op) @@ -1064,13 +1088,24 @@ void mips1core_device_base::swr(u32 const op) offs_t const offset = SIMMVAL + m_r[RSREG]; unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3; - store<u32>(offset & ~3, m_r[RTREG] << shift, 0xffffffffU << shift); + store<u32, false>(offset, m_r[RTREG] << shift, 0xffffffffU << shift); } -template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply) +template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply) { + // alignment error + if (Aligned && (address & (sizeof(T) - 1))) + { + address_error(TRANSLATE_READ, address); + return; + } + if (memory_translate(m_data_spacenum, TRANSLATE_READ, address)) { + // align address for ld[lr] instructions + if (!Aligned) + address &= ~(sizeof(T) - 1); + T const data = (sizeof(T) == 1) ? space(m_data_spacenum).read_byte(address) : (sizeof(T) == 2) ? space(m_data_spacenum).read_word(address) @@ -1086,10 +1121,21 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f } } -template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> mips1core_device_base::store(u32 address, U data, T mem_mask) +template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> mips1core_device_base::store(u32 address, U data, T mem_mask) { + // alignment error + if (Aligned && (address & (sizeof(T) - 1))) + { + address_error(TRANSLATE_WRITE, address); + return; + } + if (memory_translate(m_data_spacenum, TRANSLATE_WRITE, address)) { + // align address for sd[lr] instructions + if (!Aligned) + address &= ~(sizeof(T) - 1); + switch (sizeof(T)) { case 1: space(m_data_spacenum).write_byte(address, T(data)); break; @@ -1101,6 +1147,13 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::va bool mips1core_device_base::fetch(u32 address, std::function<void(u32)> &&apply) { + // alignment error + if (address & 3) + { + address_error(TRANSLATE_FETCH, address); + return false; + } + if (memory_translate(0, TRANSLATE_FETCH, address)) { u32 const data = space(0).read_dword(address); @@ -1913,13 +1966,8 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad } else if (SR & SR_KUc) { - if (!machine().side_effects_disabled()) - { - // exception - m_cop0[COP0_BadVAddr] = address; + address_error(intention, address); - generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); - } return false; } } |