mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
r4000: minor fixes (nw)
* paranoid approach for 64-bit mode check * sign extension bugs * signed multiply bug
This commit is contained in:
parent
bdbe21690a
commit
6b53ffcb5c
@ -79,7 +79,7 @@
|
||||
#define ODD_REGS 0x00010840U
|
||||
|
||||
// address computation
|
||||
#define ADDR(r, o) (m_64 ? ((r) + (o)) : s64(s32((r) + (o))))
|
||||
#define ADDR(r, o) (cp0_64() ? ((r) + (o)) : s64(s32((r) + (o))))
|
||||
|
||||
#define SR m_cp0[CP0_Status]
|
||||
#define CAUSE m_cp0[CP0_Cause]
|
||||
@ -200,7 +200,6 @@ void r4000_base_device::device_reset()
|
||||
m_cp0[CP0_Count] = 0;
|
||||
|
||||
m_cp0_timer_zero = total_cycles();
|
||||
m_64 = false;
|
||||
|
||||
if (m_ll_watch)
|
||||
{
|
||||
@ -332,7 +331,7 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
break;
|
||||
//case 0x01: // *
|
||||
case 0x02: // SRL
|
||||
m_r[RDREG] = u32(m_r[RTREG]) >> SHIFT;
|
||||
m_r[RDREG] = s64(s32(u32(m_r[RTREG]) >> SHIFT));
|
||||
break;
|
||||
case 0x03: // SRA
|
||||
m_r[RDREG] = s64(s32(m_r[RTREG]) >> SHIFT);
|
||||
@ -342,7 +341,7 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
break;
|
||||
//case 0x05: // *
|
||||
case 0x06: // SRLV
|
||||
m_r[RDREG] = u32(m_r[RTREG]) >> (m_r[RSREG] & 31);
|
||||
m_r[RDREG] = s64(s32(u32(m_r[RTREG]) >> (m_r[RSREG] & 31)));
|
||||
break;
|
||||
case 0x07: // SRAV
|
||||
m_r[RDREG] = s64(s32(m_r[RTREG]) >> (m_r[RSREG] & 31));
|
||||
@ -481,8 +480,8 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
case 0x1b: // DIVU
|
||||
if (m_r[RTREG])
|
||||
{
|
||||
m_lo = s64(u32(m_r[RSREG]) / u32(m_r[RTREG]));
|
||||
m_hi = s64(u32(m_r[RSREG]) % u32(m_r[RTREG]));
|
||||
m_lo = s64(s32(u32(m_r[RSREG]) / u32(m_r[RTREG])));
|
||||
m_hi = s64(s32(u32(m_r[RSREG]) % u32(m_r[RTREG])));
|
||||
}
|
||||
m_icount -= 35;
|
||||
break;
|
||||
@ -503,9 +502,9 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
m_hi = p4 + (p2 >> 32) + (p3 >> 32) + carry;
|
||||
|
||||
// adjust for sign
|
||||
if (m_r[RSREG] < 0)
|
||||
if (s64(m_r[RSREG]) < 0)
|
||||
m_hi -= m_r[RTREG];
|
||||
if (m_r[RTREG] < 0)
|
||||
if (s64(m_r[RTREG]) < 0)
|
||||
m_hi -= m_r[RSREG];
|
||||
|
||||
m_icount -= 7;
|
||||
@ -721,7 +720,7 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
case 0x09: // TGEIU
|
||||
if (m_r[RSREG] >= u16(op))
|
||||
if (m_r[RSREG] >= u64(s64(s16(op))))
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
case 0x0a: // TLTI
|
||||
@ -729,16 +728,16 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
case 0x0b: // TLTIU
|
||||
if (m_r[RSREG] >= u16(op))
|
||||
if (m_r[RSREG] >= u64(s64(s16(op))))
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
case 0x0c: // TEQI
|
||||
if (m_r[RSREG] == u16(op))
|
||||
if (m_r[RSREG] == u64(s64(s16(op))))
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
//case 0x0d: // *
|
||||
case 0x0e: // TNEI
|
||||
if (m_r[RSREG] != u16(op))
|
||||
if (m_r[RSREG] != u64(s64(s16(op))))
|
||||
cpu_exception(EXCEPTION_TR);
|
||||
break;
|
||||
//case 0x0f: // *
|
||||
@ -854,7 +853,7 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
m_r[RTREG] = s64(m_r[RSREG]) < s64(s16(op));
|
||||
break;
|
||||
case 0x0b: // SLTIU
|
||||
m_r[RTREG] = u64(m_r[RSREG]) < u64(s16(op));
|
||||
m_r[RTREG] = m_r[RSREG] < u64(s64(s16(op)));
|
||||
break;
|
||||
case 0x0c: // ANDI
|
||||
m_r[RTREG] = m_r[RSREG] & u16(op);
|
||||
@ -866,7 +865,7 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
m_r[RTREG] = m_r[RSREG] ^ u16(op);
|
||||
break;
|
||||
case 0x0f: // LUI
|
||||
m_r[RTREG] = s64(s32(u16(op) << 16));
|
||||
m_r[RTREG] = s64(s16(op)) << 16;
|
||||
break;
|
||||
case 0x10: // COP0
|
||||
cp0_execute(op);
|
||||
@ -929,13 +928,13 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
m_r[RTREG] = m_r[RSREG] + s64(s16(op));
|
||||
break;
|
||||
case 0x1a: // LDL
|
||||
if (m_64 || !(SR & SR_KSU) || (SR & SR_EXL) || (SR & SR_ERL))
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
cpu_ldl(op);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
break;
|
||||
case 0x1b: // LDR
|
||||
if (m_64 || !(SR & SR_KSU) || (SR & SR_EXL) || (SR & SR_ERL))
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
cpu_ldr(op);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
@ -1005,13 +1004,13 @@ void r4000_base_device::cpu_execute(u32 const op)
|
||||
store<u32>(ADDR(m_r[RSREG], s16(op)), u32(m_r[RTREG]));
|
||||
break;
|
||||
case 0x2c: // SDL
|
||||
if (m_64 || !(SR & SR_KSU) || (SR & SR_EXL) || (SR & SR_ERL))
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
cpu_sdl(op);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
break;
|
||||
case 0x2d: // SDR
|
||||
if (m_64 || !(SR & SR_KSU) || (SR & SR_EXL) || (SR & SR_ERL))
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
cpu_sdr(op);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
@ -1224,8 +1223,6 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
|
||||
}
|
||||
|
||||
SR |= SR_EXL;
|
||||
|
||||
m_64 = m_cp0[CP0_Status] & SR_KX;
|
||||
}
|
||||
else
|
||||
CAUSE = (CAUSE & (CAUSE_BD | CAUSE_IP)) | exception;
|
||||
@ -1336,7 +1333,7 @@ void r4000_base_device::cp0_execute(u32 const op)
|
||||
// 64-bit non-Kernel (User or Supervisor) mode. These instructions
|
||||
// cause a reserved instruction exception if 64-bit operation is
|
||||
// not enabled in User or Supervisor mode.
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || m_64)
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
m_r[RTREG] = cp0_get(RDREG);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
@ -1353,7 +1350,7 @@ void r4000_base_device::cp0_execute(u32 const op)
|
||||
// 64-bit non-Kernel (User or Supervisor) mode. These instructions
|
||||
// cause a reserved instruction exception if 64-bit operation is
|
||||
// not enabled in User or Supervisor mode.
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || m_64)
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
cp0_set(RDREG, m_r[RTREG]);
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
@ -1419,7 +1416,6 @@ void r4000_base_device::cp0_execute(u32 const op)
|
||||
m_pc = m_cp0[CP0_EPC];
|
||||
SR &= ~SR_EXL;
|
||||
}
|
||||
cp0_mode_check();
|
||||
|
||||
if (m_ll_watch)
|
||||
{
|
||||
@ -1492,9 +1488,6 @@ void r4000_base_device::cp0_set(unsigned const reg, u64 const data)
|
||||
case CP0_Status:
|
||||
m_cp0[CP0_Status] = u32(data);
|
||||
|
||||
// reevaluate operating mode
|
||||
cp0_mode_check();
|
||||
|
||||
// FIXME: software interrupt check
|
||||
if (CAUSE & SR & SR_IMSW)
|
||||
m_icount = 0;
|
||||
@ -1597,7 +1590,7 @@ void r4000_base_device::cp0_tlbp()
|
||||
{
|
||||
tlb_entry_t const &entry = m_tlb[index];
|
||||
|
||||
u64 const mask = (m_64 ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
|
||||
u64 const mask = (cp0_64() ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
|
||||
| ((entry.vpn & EH_G) ? 0 : EH_ASID);
|
||||
|
||||
if ((entry.vpn & mask) == (m_cp0[CP0_EntryHi] & mask))
|
||||
@ -1629,17 +1622,16 @@ TIMER_CALLBACK_MEMBER(r4000_base_device::cp0_timer_callback)
|
||||
m_cp0[CP0_Cause] |= CAUSE_IPEX5;
|
||||
}
|
||||
|
||||
void r4000_base_device::cp0_mode_check()
|
||||
bool r4000_base_device::cp0_64() const
|
||||
{
|
||||
if (!(m_cp0[CP0_Status] & (SR_EXL | SR_ERL)))
|
||||
switch (m_cp0[CP0_Status] & SR_KSU)
|
||||
{
|
||||
case SR_KSU_K: m_64 = m_cp0[CP0_Status] & SR_KX; break;
|
||||
case SR_KSU_S: m_64 = m_cp0[CP0_Status] & SR_SX; break;
|
||||
case SR_KSU_U: m_64 = m_cp0[CP0_Status] & SR_UX; break;
|
||||
}
|
||||
else
|
||||
m_64 = m_cp0[CP0_Status] & SR_KX;
|
||||
switch (SR & (SR_KSU | SR_ERL | SR_EXL))
|
||||
{
|
||||
case SR_KSU_U: return bool(SR & SR_UX);
|
||||
case SR_KSU_S: return bool(SR & SR_SX);
|
||||
|
||||
default:
|
||||
return bool(SR & SR_KX);
|
||||
}
|
||||
}
|
||||
|
||||
void r4000_base_device::cp1_execute(u32 const op)
|
||||
@ -2485,7 +2477,7 @@ void r4000_base_device::cp2_execute(u32 const op)
|
||||
// 64-bit non-Kernel (User or Supervisor) mode. These instructions
|
||||
// cause a reserved instruction exception if 64-bit operation is
|
||||
// not enabled in User or Supervisor mode.
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || m_64)
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
logerror("dmfc2 unimplemented (%s)\n", machine().describe_context());
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
@ -2503,7 +2495,7 @@ void r4000_base_device::cp2_execute(u32 const op)
|
||||
// 64-bit non-Kernel (User or Supervisor) mode. These instructions
|
||||
// cause a reserved instruction exception if 64-bit operation is
|
||||
// not enabled in User or Supervisor mode.
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || m_64)
|
||||
if (!(SR & SR_KSU) || (SR & (SR_EXL | SR_ERL)) || cp0_64())
|
||||
logerror("dmtc2 unimplemented (%s)\n", machine().describe_context());
|
||||
else
|
||||
cpu_exception(EXCEPTION_RI);
|
||||
|
@ -343,7 +343,7 @@ protected:
|
||||
// cp0 helpers
|
||||
TIMER_CALLBACK_MEMBER(cp0_timer_callback);
|
||||
void cp0_update_timer(bool start = false);
|
||||
void cp0_mode_check();
|
||||
bool cp0_64() const;
|
||||
|
||||
// cp1 implementation
|
||||
void cp1_execute(u32 const op);
|
||||
@ -405,7 +405,6 @@ protected:
|
||||
}
|
||||
m_tlb[48];
|
||||
unsigned m_tlb_mru[3][48];
|
||||
bool m_64;
|
||||
|
||||
// cp1 state
|
||||
u64 m_f[32]; // floating point registers
|
||||
|
Loading…
Reference in New Issue
Block a user