summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mips/r4000.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mips/r4000.cpp')
-rw-r--r--src/devices/cpu/mips/r4000.cpp74
1 files changed, 44 insertions, 30 deletions
diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp
index 7b26493f61c..13f75f47ed5 100644
--- a/src/devices/cpu/mips/r4000.cpp
+++ b/src/devices/cpu/mips/r4000.cpp
@@ -85,7 +85,7 @@ DEFINE_DEVICE_TYPE(R4000, r4000_device, "r4000", "MIPS R4000")
DEFINE_DEVICE_TYPE(R4400, r4400_device, "r4400", "MIPS R4400")
DEFINE_DEVICE_TYPE(R4600, r4600_device, "r4600", "QED R4600")
-r4000_base_device::r4000_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size_t icache_size, cache_size_t dcache_size)
+r4000_base_device::r4000_base_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size icache_size, cache_size dcache_size)
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config_le("program", ENDIANNESS_LITTLE, 64, 32)
, m_program_config_be("program", ENDIANNESS_BIG, 64, 32)
@@ -189,14 +189,20 @@ void r4000_base_device::device_reset()
{
m_branch_state = NONE;
m_pc = s64(s32(0xbfc00000));
+ m_r[0] = 0;
+
+ if (m_hard_reset)
+ m_cp0[CP0_Status] = SR_BEV | SR_ERL;
+ else
+ m_cp0[CP0_Status] = SR_BEV | SR_ERL | SR_SR;
- m_cp0[CP0_Status] = SR_BEV | SR_ERL;
m_cp0[CP0_Wired] = 0;
m_cp0[CP0_Compare] = 0;
m_cp0[CP0_Count] = 0;
m_cp0_timer_zero = total_cycles();
+ m_hard_reset = false;
m_ll_active = false;
m_bus_error = false;
@@ -240,7 +246,7 @@ bool r4000_base_device::memory_translate(int spacenum, int intention, offs_t &ad
// FIXME: address truncation
u64 placeholder = s32(address);
- translate_t const t = translate(intention, placeholder);
+ translate_result const t = translate(intention, placeholder);
if (t == ERROR || t == MISS)
return false;
@@ -1146,7 +1152,7 @@ void r4000_base_device::cpu_lwl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(3, 0)) << 3;
- load<u32>(offset & ~3,
+ load<u32, false>(offset,
[this, op, shift](u32 const data)
{
m_r[RTREG] = s32((m_r[RTREG] & ~u32(~u32(0) << shift)) | (data << shift));
@@ -1158,7 +1164,7 @@ void r4000_base_device::cpu_lwr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 0x3) ^ R4000_ENDIAN_LE_BE(0, 3)) << 3;
- load<u32>(offset & ~3,
+ load<u32, false>(offset,
[this, op, shift](u32 const data)
{
m_r[RTREG] = s32((m_r[RTREG] & ~u32(~u32(0) >> shift)) | (data >> shift));
@@ -1170,7 +1176,7 @@ void r4000_base_device::cpu_swl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(3, 0)) << 3;
- store<u32>(offset & ~3, u32(m_r[RTREG]) >> shift, ~u32(0) >> shift);
+ store<u32, false>(offset, u32(m_r[RTREG]) >> shift, ~u32(0) >> shift);
}
void r4000_base_device::cpu_swr(u32 const op)
@@ -1178,7 +1184,7 @@ void r4000_base_device::cpu_swr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(0, 3)) << 3;
- store<u32>(offset & ~3, u32(m_r[RTREG]) << shift, ~u32(0) << shift);
+ store<u32, false>(offset, u32(m_r[RTREG]) << shift, ~u32(0) << shift);
}
void r4000_base_device::cpu_ldl(u32 const op)
@@ -1186,7 +1192,7 @@ void r4000_base_device::cpu_ldl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(7, 0)) << 3;
- load<u64>(offset & ~7,
+ load<u64, false>(offset,
[this, op, shift](u64 const data)
{
m_r[RTREG] = (m_r[RTREG] & ~u64(~u64(0) << shift)) | (data << shift);
@@ -1198,7 +1204,7 @@ void r4000_base_device::cpu_ldr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(0, 7)) << 3;
- load<u64>(offset & ~7,
+ load<u64, false>(offset,
[this, op, shift](u64 const data)
{
m_r[RTREG] = (m_r[RTREG] & ~u64(~u64(0) >> shift)) | (data >> shift);
@@ -1210,7 +1216,7 @@ void r4000_base_device::cpu_sdl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(7, 0)) << 3;
- store<u64>(offset & ~7, m_r[RTREG] >> shift, ~u64(0) >> shift);
+ store<u64, false>(offset, m_r[RTREG] >> shift, ~u64(0) >> shift);
}
void r4000_base_device::cpu_sdr(u32 const op)
@@ -1218,7 +1224,7 @@ void r4000_base_device::cpu_sdr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(0, 7)) << 3;
- store<u64>(offset & ~7, m_r[RTREG] << shift, ~u64(0) << shift);
+ store<u64, false>(offset, m_r[RTREG] << shift, ~u64(0) << shift);
}
void r4000_base_device::cp0_execute(u32 const op)
@@ -1469,7 +1475,7 @@ void r4000_base_device::cp0_tlbr()
if (index < ARRAY_LENGTH(m_tlb))
{
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
m_cp0[CP0_PageMask] = entry.mask;
m_cp0[CP0_EntryHi] = entry.vpn;
@@ -1482,7 +1488,7 @@ void r4000_base_device::cp0_tlbwi(u8 const index)
{
if (index < ARRAY_LENGTH(m_tlb))
{
- tlb_entry_t &entry = m_tlb[index];
+ tlb_entry &entry = m_tlb[index];
entry.mask = m_cp0[CP0_PageMask];
entry.vpn = m_cp0[CP0_EntryHi] & EH_WM;
@@ -1517,7 +1523,7 @@ void r4000_base_device::cp0_tlbp()
m_cp0[CP0_Index] = 0x80000000;
for (u8 index = 0; index < ARRAY_LENGTH(m_tlb); index++)
{
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
u64 const mask = (cp0_64() ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
| ((entry.vpn & EH_G) ? 0 : EH_ASID);
@@ -1530,9 +1536,9 @@ void r4000_base_device::cp0_tlbp()
}
if (m_cp0[CP0_Index] == 0x80000000)
- LOGMASKED(LOG_TLB, "tlbp miss 0x%08x\n", m_cp0[CP0_EntryHi]);
+ LOGMASKED(LOG_TLB, "tlbp miss 0x%08x (%s)\n", m_cp0[CP0_EntryHi], machine().describe_context());
else
- LOGMASKED(LOG_TLB, "tlbp hit 0x%08x index %02d\n", m_cp0[CP0_EntryHi], m_cp0[CP0_Index]);
+ LOGMASKED(LOG_TLB, "tlbp hit 0x%08x index %02d (%s)\n", m_cp0[CP0_EntryHi], m_cp0[CP0_Index], machine().describe_context());
}
void r4000_base_device::cp0_update_timer(bool start)
@@ -2727,7 +2733,7 @@ void r4000_base_device::cp2_execute(u32 const op)
}
}
-r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &address)
+r4000_base_device::translate_result r4000_base_device::translate(int intention, u64 &address)
{
/*
* Decode the program address into one of the following ranges depending on
@@ -2890,7 +2896,7 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++)
{
unsigned const index = mru[i];
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
// test vpn and asid
u64 const mask = (extended ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
@@ -2934,13 +2940,13 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
{
if (VERBOSE & LOG_TLB)
{
- char const mode[] = { 'r', 'w', 'x' };
+ static char const mode[] = { 'r', 'w', 'x' };
if (modify)
- LOGMASKED(LOG_TLB, "tlb modify asid %d address 0x%016x (%s)\n",
- m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
+ LOGMASKED(LOG_TLB, "tlb modify asid 0x%02x address 0x%016x (%s)\n",
+ m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
else
- LOGMASKED(LOG_TLB, "tlb miss %c asid %d address 0x%016x (%s)\n",
+ LOGMASKED(LOG_TLB, "tlb miss %c asid 0x%02x address 0x%016x (%s)\n",
mode[intention & TRANSLATE_TYPE_MASK], m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
}
@@ -2976,16 +2982,16 @@ void r4000_base_device::address_error(int intention, u64 const address)
}
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> r4000_base_device::load(u64 address, U &&apply)
+template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> r4000_base_device::load(u64 address, U &&apply)
{
// alignment error
- if (address & (sizeof(T) - 1))
+ if (Aligned && (address & (sizeof(T) - 1)))
{
address_error(TRANSLATE_READ, address);
return false;
}
- translate_t const t = translate(TRANSLATE_READ, address);
+ translate_result const t = translate(TRANSLATE_READ, address);
// address error
if (t == ERROR)
@@ -3011,6 +3017,10 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
}
}
+ // align address for l[dw][lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
// TODO: cache lookup
T value = 0;
@@ -3044,7 +3054,7 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
return false;
}
- translate_t const t = translate(TRANSLATE_READ, address);
+ translate_result const t = translate(TRANSLATE_READ, address);
// address error
if (t == ERROR)
@@ -3080,16 +3090,16 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
return true;
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> r4000_base_device::store(u64 address, U data, T mem_mask)
+template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> r4000_base_device::store(u64 address, U data, T mem_mask)
{
// alignment error
- if (address & (sizeof(T) - 1))
+ if (Aligned && (address & (sizeof(T) - 1)))
{
address_error(TRANSLATE_WRITE, address);
return false;
}
- translate_t const t = translate(TRANSLATE_WRITE, address);
+ translate_result const t = translate(TRANSLATE_WRITE, address);
// address error
if (t == ERROR)
@@ -3114,6 +3124,10 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::va
}
}
+ // align address for s[dw][lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
// TODO: cache lookup
switch (sizeof(T))
@@ -3139,7 +3153,7 @@ bool r4000_base_device::fetch(u64 address, std::function<void(u32)> &&apply)
return false;
}
- translate_t const t = translate(TRANSLATE_FETCH, address);
+ translate_result const t = translate(TRANSLATE_FETCH, address);
// address error
if (t == ERROR)