diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index 1ed202c0d63..a5f99fcc993 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -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 void mips1_device_base::set_cop1_reg(unsigned const reg, T const data) { // translate softfloat exception flags to cause register if (softfloat_exceptionFlags) @@ -1829,7 +1842,10 @@ void mips1_device_base::set_cop1_reg(unsigned const reg, u64 const data) m_fcr31 |= ((m_fcr31 & FCR31_CM) >> 10); } - m_f[reg] = data; + if (sizeof(T) == 4) + m_f[reg] = (m_f[reg] & ~0xffffffffULL) | data; + else + m_f[reg] = data; } bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &address) diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h index 3ae34e4b69f..3a442fa914c 100644 --- a/src/devices/cpu/mips/mips1.h +++ b/src/devices/cpu/mips/mips1.h @@ -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 void set_cop1_reg(unsigned const reg, T const data); private: u64 m_reset_time; diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp index ca95b107c65..28adcda0e15 100644 --- a/src/devices/cpu/mips/r4000.cpp +++ b/src/devices/cpu/mips/r4000.cpp @@ -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 void r4000_base_device::cp1_set(unsigned const reg, T const data) { // translate softfloat exception flags to cause register if (softfloat_exceptionFlags) @@ -2424,7 +2439,10 @@ void r4000_base_device::cp1_set(unsigned const reg, u64 const data) m_fcr31 |= ((m_fcr31 & FCR31_CM) >> 10); } - m_f[reg] = data; + if (sizeof(T) == 4) + m_f[reg] = (m_f[reg] & ~0xffffffffULL) | data; + else + m_f[reg] = data; } void r4000_base_device::cp2_execute(u32 const op) diff --git a/src/devices/cpu/mips/r4000.h b/src/devices/cpu/mips/r4000.h index 8c3a1760ba3..57e37b6dfe1 100644 --- a/src/devices/cpu/mips/r4000.h +++ b/src/devices/cpu/mips/r4000.h @@ -347,7 +347,7 @@ protected: // cp1 implementation void cp1_execute(u32 const op); - void cp1_set(unsigned const reg, u64 const data); + template void cp1_set(unsigned const reg, T const data); // cp2 implementation void cp2_execute(u32 const op);