diff options
author | 2020-01-24 15:21:47 +0700 | |
---|---|---|
committer | 2020-01-24 15:21:47 +0700 | |
commit | 76ec1f95916cb6a43e2c1ac95276826d9bfeb3f7 (patch) | |
tree | 701d97e3056b927b25cbc7aea137eaf93a2a78e8 | |
parent | 06a2d7e3b80c5047b66d0d649c4dc5b38ffaf221 (diff) |
mips1: alignment checking/exceptions (nw)
-rw-r--r-- | src/devices/cpu/mips/mips1.cpp | 96 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips1.h | 43 |
2 files changed, 87 insertions, 52 deletions
diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index bad20d2f857..26260b836b4 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -56,7 +56,7 @@ DEFINE_DEVICE_TYPE(SONYPS2_IOP, iop_device, "sonyiop", "Sony Playstation 2 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; @@ -663,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; } } @@ -875,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) @@ -1046,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; @@ -1057,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; @@ -1070,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) @@ -1078,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) @@ -1100,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; @@ -1115,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); @@ -1927,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; } } diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h index 2e9243c18a2..1abff01bc86 100644 --- a/src/devices/cpu/mips/mips1.h +++ b/src/devices/cpu/mips/mips1.h @@ -17,7 +17,7 @@ public: void berr_w(int state) { m_bus_error = bool(state); } protected: - 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(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); enum registers : unsigned { @@ -172,8 +172,9 @@ protected: void icache_map(address_map &map); void dcache_map(address_map &map); - // interrupts + // exceptions void generate_exception(u32 exception, bool refill = false); + void address_error(int intention, u32 const address); // cop0 virtual void handle_cop0(u32 const op); @@ -192,8 +193,8 @@ protected: void swr(u32 const op); // memory accessors - template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply); - template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 address, U data, T mem_mask = ~T(0)); + template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply); + template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 address, U data, T mem_mask = ~T(0)); bool fetch(u32 address, std::function<void(u32)> &&apply); // debug helpers @@ -201,10 +202,10 @@ protected: std::string debug_string_array(u32 array_pointer); // address spaces - const address_space_config m_program_config_be; - const address_space_config m_program_config_le; - const address_space_config m_icache_config; - const address_space_config m_dcache_config; + address_space_config const m_program_config_be; + address_space_config const m_program_config_le; + address_space_config const m_icache_config; + address_space_config const m_dcache_config; int m_data_spacenum; @@ -246,7 +247,7 @@ class mips1_device_base : public mips1core_device_base { public: // floating point coprocessor revision numbers recognised by RISC/os 4.52 and IRIX - enum fpu_rev_t : u32 + enum fpu_rev : u32 { MIPS_R2360 = 0x0100, // MIPS R2360 Floating Point Board MIPS_R2010 = 0x0200, // MIPS R2010 VLSI Floating Point Chip @@ -260,7 +261,7 @@ public: void set_fpu(u32 revision, unsigned interrupt = 3) { m_fcr0 = revision; m_fpu_irq = interrupt; } protected: - 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(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); enum cp1_fcr31_mask : u32 { @@ -323,31 +324,31 @@ private: class r2000_device : public mips1_device_base { public: - r2000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); + r2000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); }; class r2000a_device : public mips1_device_base { public: - r2000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); + r2000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); }; class r3000_device : public mips1_device_base { public: - r3000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); + r3000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); }; class r3000a_device : public mips1_device_base { public: - r3000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); + r3000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0); }; class r3041_device : public mips1core_device_base { public: - r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + r3041_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; @@ -357,37 +358,37 @@ protected: class r3051_device : public mips1core_device_base { public: - r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + r3051_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); }; class r3052_device : public mips1core_device_base { public: - r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + r3052_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); }; class r3052e_device : public mips1_device_base { public: - r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + r3052e_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); }; class r3071_device : public mips1_device_base { public: - r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096); + r3071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096); }; class r3081_device : public mips1_device_base { public: - r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096); + r3081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096); }; class iop_device : public mips1core_device_base { public: - iop_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + iop_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); }; DECLARE_DEVICE_TYPE(R2000, r2000_device) |