summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2020-01-24 15:21:47 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2020-01-24 15:21:47 +0700
commit76ec1f95916cb6a43e2c1ac95276826d9bfeb3f7 (patch)
tree701d97e3056b927b25cbc7aea137eaf93a2a78e8
parent06a2d7e3b80c5047b66d0d649c4dc5b38ffaf221 (diff)
mips1: alignment checking/exceptions (nw)
-rw-r--r--src/devices/cpu/mips/mips1.cpp96
-rw-r--r--src/devices/cpu/mips/mips1.h43
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)