mirror of
https://github.com/holub/mame
synced 2025-10-05 16:50:57 +03:00
mips: preserve upper 32 bits for single-precision fp operations (nw)
While this behaviour is undefined according to the MIPS R4000 Microprocessor User's Manual, various factors point toward it most likely being correct, including: 1. The fact MIPS-I exposes 16x64-bit floating-point registers, but internally implements them as pairs of 32-bit registers (with only the even-numbered pairs being valid for arithmetic operations), making it somewhat likely MOV.S, like LWC1 and SWC1, can access either half. 2. Explicit mention in IDT documentation and "See MIPS Run", i.e. "The odd-numbered registers can be accessed by move and load/store instructions", and other commentary. 3. The presence of paired-single operations in later MIPS32/64 specifications, which operate on independent single-precision values stored in each of the lower and upper halves of a single floating-point register.
This commit is contained in:
parent
db980f2b42
commit
eff5477f0f
@ -1408,10 +1408,23 @@ void mips1_device_base::handle_cop1(u32 const op)
|
||||
if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ 0 }))
|
||||
set_cop1_reg(FDREG >> 1, f32_mul(float32_t{ u32(m_f[FSREG >> 1]) }, i32_to_f32(-1)).v);
|
||||
else
|
||||
set_cop1_reg(FDREG >> 1, m_f[FSREG >> 1]);
|
||||
set_cop1_reg(FDREG >> 1, u32(m_f[FSREG >> 1]));
|
||||
break;
|
||||
case 0x06: // MOV.S
|
||||
m_f[FDREG >> 1] = m_f[FSREG >> 1];
|
||||
if (FDREG & 1)
|
||||
if (FSREG & 1)
|
||||
// move high half to high half
|
||||
m_f[FDREG >> 1] = (m_f[FSREG >> 1] & ~0xffffffffULL) | u32(m_f[FDREG >> 1]);
|
||||
else
|
||||
// move low half to high half
|
||||
m_f[FDREG >> 1] = (m_f[FSREG >> 1] << 32) | u32(m_f[FDREG >> 1]);
|
||||
else
|
||||
if (FSREG & 1)
|
||||
// move high half to low half
|
||||
m_f[FDREG >> 1] = (m_f[FDREG >> 1] & ~0xffffffffULL) | (m_f[FSREG >> 1] >> 32);
|
||||
else
|
||||
// move low half to low half
|
||||
m_f[FDREG >> 1] = (m_f[FDREG >> 1] & ~0xffffffffULL) | u32(m_f[FSREG >> 1]);
|
||||
break;
|
||||
case 0x07: // NEG.S
|
||||
set_cop1_reg(FDREG >> 1, f32_mul(float32_t{ u32(m_f[FSREG >> 1]) }, i32_to_f32(-1)).v);
|
||||
@ -1802,7 +1815,7 @@ void mips1_device_base::handle_cop1(u32 const op)
|
||||
}
|
||||
}
|
||||
|
||||
void mips1_device_base::set_cop1_reg(unsigned const reg, u64 const data)
|
||||
template <typename T> void mips1_device_base::set_cop1_reg(unsigned const reg, T const data)
|
||||
{
|
||||
// translate softfloat exception flags to cause register
|
||||
if (softfloat_exceptionFlags)
|
||||
@ -1829,6 +1842,9 @@ void mips1_device_base::set_cop1_reg(unsigned const reg, u64 const data)
|
||||
m_fcr31 |= ((m_fcr31 & FCR31_CM) >> 10);
|
||||
}
|
||||
|
||||
if (sizeof(T) == 4)
|
||||
m_f[reg] = (m_f[reg] & ~0xffffffffULL) | data;
|
||||
else
|
||||
m_f[reg] = data;
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ protected:
|
||||
virtual u32 get_cop0_reg(unsigned const reg) override;
|
||||
|
||||
virtual void handle_cop1(u32 const op) override;
|
||||
virtual void set_cop1_reg(unsigned const reg, u64 const data);
|
||||
template <typename T> void set_cop1_reg(unsigned const reg, T const data);
|
||||
|
||||
private:
|
||||
u64 m_reset_time;
|
||||
|
@ -1642,7 +1642,7 @@ void r4000_base_device::cp1_execute(u32 const op)
|
||||
break;
|
||||
case 0x04: // MTC1
|
||||
if (SR & SR_FR)
|
||||
m_f[RDREG] = u32(m_r[RTREG]);
|
||||
m_f[RDREG] = (m_f[RDREG] & ~0xffffffffULL) | u32(m_r[RTREG]);
|
||||
else
|
||||
if (RDREG & 1)
|
||||
// load the high half of the even floating point register
|
||||
@ -1761,12 +1761,27 @@ void r4000_base_device::cp1_execute(u32 const op)
|
||||
if (f32_lt(float32_t{ u32(m_f[FSREG]) }, float32_t{ 0 }))
|
||||
cp1_set(FDREG, f32_mul(float32_t{ u32(m_f[FSREG]) }, i32_to_f32(-1)).v);
|
||||
else
|
||||
cp1_set(FDREG, m_f[FSREG]);
|
||||
cp1_set(FDREG, u32(m_f[FSREG]));
|
||||
}
|
||||
break;
|
||||
case 0x06: // MOV.S
|
||||
if ((SR & SR_FR) || !(op & ODD_REGS))
|
||||
m_f[FDREG] = m_f[FSREG];
|
||||
if (SR & SR_FR)
|
||||
m_f[FDREG] = (m_f[FDREG] & ~0xffffffffULL) | u32(m_f[FSREG]);
|
||||
else
|
||||
if (FDREG & 1)
|
||||
if (FSREG & 1)
|
||||
// move high half to high half
|
||||
m_f[FDREG & ~1] = (m_f[FSREG & ~1] & ~0xffffffffULL) | u32(m_f[FDREG & ~1]);
|
||||
else
|
||||
// move low half to high half
|
||||
m_f[FDREG & ~1] = (m_f[FSREG & ~1] << 32) | u32(m_f[FDREG & ~1]);
|
||||
else
|
||||
if (FSREG & 1)
|
||||
// move high half to low half
|
||||
m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | (m_f[FSREG & ~1] >> 32);
|
||||
else
|
||||
// move low half to low half
|
||||
m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | u32(m_f[FSREG & ~1]);
|
||||
break;
|
||||
case 0x07: // NEG.S
|
||||
if ((SR & SR_FR) || !(op & ODD_REGS))
|
||||
@ -2358,7 +2373,7 @@ void r4000_base_device::cp1_execute(u32 const op)
|
||||
[this, op](u32 data)
|
||||
{
|
||||
if (SR & SR_FR)
|
||||
m_f[RTREG] = data;
|
||||
m_f[RTREG] = (m_f[RTREG] & ~0xffffffffULL) | data;
|
||||
else
|
||||
if (RTREG & 1)
|
||||
// load the high half of the even floating point register
|
||||
@ -2397,7 +2412,7 @@ void r4000_base_device::cp1_execute(u32 const op)
|
||||
}
|
||||
}
|
||||
|
||||
void r4000_base_device::cp1_set(unsigned const reg, u64 const data)
|
||||
template <typename T> void r4000_base_device::cp1_set(unsigned const reg, T const data)
|
||||
{
|
||||
// translate softfloat exception flags to cause register
|
||||
if (softfloat_exceptionFlags)
|
||||
@ -2424,6 +2439,9 @@ void r4000_base_device::cp1_set(unsigned const reg, u64 const data)
|
||||
m_fcr31 |= ((m_fcr31 & FCR31_CM) >> 10);
|
||||
}
|
||||
|
||||
if (sizeof(T) == 4)
|
||||
m_f[reg] = (m_f[reg] & ~0xffffffffULL) | data;
|
||||
else
|
||||
m_f[reg] = data;
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ protected:
|
||||
|
||||
// cp1 implementation
|
||||
void cp1_execute(u32 const op);
|
||||
void cp1_set(unsigned const reg, u64 const data);
|
||||
template <typename T> void cp1_set(unsigned const reg, T const data);
|
||||
|
||||
// cp2 implementation
|
||||
void cp2_execute(u32 const op);
|
||||
|
Loading…
Reference in New Issue
Block a user