-r4000: Added basic R5000 support. [Ryan Holtz]

This commit is contained in:
MooglyGuy 2020-03-04 14:25:55 +01:00
parent edc2024fc0
commit c0d388dc09
3 changed files with 232 additions and 15 deletions

View File

@ -84,6 +84,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")
DEFINE_DEVICE_TYPE(R5000, r5000_device, "r5000", "MIPS R5000")
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)
@ -609,10 +610,7 @@ void r4000_base_device::cpu_execute(u32 const op)
break;
default:
// * Operation codes marked with an asterisk cause reserved
// instruction exceptions in all current implementations and are
// reserved for future versions of the architecture.
cpu_exception(EXCEPTION_RI);
handle_reserved_instruction(op);
break;
}
break;
@ -816,7 +814,9 @@ void r4000_base_device::cpu_execute(u32 const op)
case 0x12: // COP2
cp2_execute(op);
break;
//case 0x13: // *
case 0x13: // COP1X
cp1x_execute(op);
break;
case 0x14: // BEQL
if (m_r[RSREG] == m_r[RTREG])
{
@ -1044,7 +1044,7 @@ void r4000_base_device::cpu_execute(u32 const op)
case 0x32: // LWC2
cp2_execute(op);
break;
//case 0x33: // *
// case 0x33: *
case 0x34: // LLD
load_linked<u64>(ADDR(m_r[RSREG], s16(op)),
[this, op](u64 address, u64 data)
@ -1119,6 +1119,33 @@ void r4000_base_device::cpu_execute(u32 const op)
}
}
void r4000_base_device::handle_reserved_instruction(u32 const op)
{
// Unahdnled operation codes cause reserved instruction
// exceptions in all current implementations and are
// reserved for future versions of the architecture.
cpu_exception(EXCEPTION_RI);
}
void r5000_device::handle_reserved_instruction(u32 const op)
{
switch (op & 0x3f)
{
case 0x33: // PREF (effective no-op)
break;
default:
switch (op >> 26)
{
case 0x0a: // MOVN
if (m_r[RTREG] == 0) { if (RDREG) m_r[RDREG] = m_r[RSREG]; }
break;
case 0x0b: // MOVZ
if (m_r[RTREG] != 0) { if (RDREG) m_r[RDREG] = m_r[RSREG]; }
break;
}
}
}
void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
{
if (exception != EXCEPTION_INT)
@ -2601,6 +2628,186 @@ void r4000_base_device::cp1_execute(u32 const op)
}
}
void r4000_base_device::cp1x_execute(u32 const op)
{
if (!(SR & SR_CU1))
{
cpu_exception(EXCEPTION_CP1);
return;
}
logerror("cp1x not supported < R5000 (%s)\n", machine().describe_context());
}
void r5000_device::cp1x_execute(u32 const op)
{
if (!(SR & SR_CU1))
{
cpu_exception(EXCEPTION_CP1);
return;
}
switch (op & 0x3f)
{
case 0x00: // LWXC1
load<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))),
[this, op](u32 data)
{
if (SR & SR_FR)
m_f[RTREG] = (m_f[RTREG] & ~0xffffffffULL) | data;
else
if (RTREG & 1)
// load the high half of the even floating point register
m_f[RTREG & ~1] = (u64(data) << 32) | u32(m_f[RTREG & ~1]);
else
// load the low half of the even floating point register
m_f[RTREG & ~1] = (m_f[RTREG & ~1] & ~0xffffffffULL) | data;
});
break;
case 0x01: // LDXC1
load<u64>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))),
[this, op](u64 data)
{
if ((SR & SR_FR) || !(RTREG & 1))
m_f[RTREG] = data;
});
break;
case 0x08: // SWXC1
if (SR & SR_FR)
store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG]));
else
if (RTREG & 1)
// store the high half of the even floating point register
store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG & ~1] >> 32));
else
// store the low half of the even floating point register
store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG & ~1]));
break;
case 0x09: // SDXC1
if ((SR & SR_FR) || !(RTREG & 1))
store<u64>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), m_f[RTREG]);
break;
case 0x0f: // PREFX
// Do nothing for now (implementations are permitted to do this)
break;
case 0x20: // MADD.S
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float32_t const fr = float32_t{ u32(m_f[FRREG]) };
float32_t const fs = float32_t{ u32(m_f[FSREG]) };
float32_t const ft = float32_t{ u32(m_f[FTREG]) };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f32_add(f32_mul(fs, ft), fr).v);
}
break;
case 0x21: // MADD.D
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float64_t const fr = float64_t{ m_f[FRREG] };
float64_t const fs = float64_t{ m_f[FSREG] };
float64_t const ft = float64_t{ m_f[FTREG] };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f64_add(f64_mul(fs, ft), fr).v);
}
break;
case 0x28: // MSUB.S
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float32_t const fr = float32_t{ u32(m_f[FRREG]) };
float32_t const fs = float32_t{ u32(m_f[FSREG]) };
float32_t const ft = float32_t{ u32(m_f[FTREG]) };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f32_sub(f32_mul(fs, ft), fr).v);
}
break;
case 0x29: // MSUB.D
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float64_t const fr = float64_t{ m_f[FRREG] };
float64_t const fs = float64_t{ m_f[FSREG] };
float64_t const ft = float64_t{ m_f[FTREG] };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f64_sub(f64_mul(fs, ft), fr).v);
}
break;
case 0x30: // NMADD.S
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float32_t const fr = float32_t{ u32(m_f[FRREG]) };
float32_t const fs = float32_t{ u32(m_f[FSREG]) };
float32_t const ft = float32_t{ u32(m_f[FTREG]) };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f32_mul(f32_add(f32_mul(fs, ft), fr), i32_to_f32(-1)).v);
}
break;
case 0x31: // NMADD.D
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float64_t const fr = float64_t{ m_f[FRREG] };
float64_t const fs = float64_t{ m_f[FSREG] };
float64_t const ft = float64_t{ m_f[FTREG] };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f64_mul(f64_add(f64_mul(fs, ft), fr), i32_to_f64(-1)).v);
}
break;
case 0x38: // NMSUB.S
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float32_t const fr = float32_t{ u32(m_f[FRREG]) };
float32_t const fs = float32_t{ u32(m_f[FSREG]) };
float32_t const ft = float32_t{ u32(m_f[FTREG]) };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f32_mul(f32_sub(f32_mul(fs, ft), fr), i32_to_f32(-1)).v);
}
break;
case 0x39: // NMSUB.D
if ((SR & SR_FR) || !(op & ODD_REGS))
{
float64_t const fr = float64_t{ m_f[FRREG] };
float64_t const fs = float64_t{ m_f[FSREG] };
float64_t const ft = float64_t{ m_f[FTREG] };
if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
cp1_set(FDREG, f64_mul(f64_sub(f64_mul(fs, ft), fr), i32_to_f64(-1)).v);
}
break;
case 0x24: /* MADD.W */
logerror("cp1x unsupported op (%s): MADD.W\n", machine().describe_context());
break;
case 0x25: /* MADD.L */
logerror("cp1x unsupported op (%s): MADD.L\n", machine().describe_context());
break;
case 0x2c: /* MSUB.W */
logerror("cp1x unsupported op (%s): MSUB.W\n", machine().describe_context());
break;
case 0x2d: /* MSUB.L */
logerror("cp1x unsupported op (%s): MSUB.L\n", machine().describe_context());
break;
case 0x34: /* NMADD.W */
logerror("cp1x unsupported op (%s): NMADD.W\n", machine().describe_context());
break;
case 0x35: /* NMADD.L */
logerror("cp1x unsupported op (%s): NMADD.L\n", machine().describe_context());
break;
case 0x3c: /* NMSUB.W */
logerror("cp1x unsupported op (%s): NMSUB.W\n", machine().describe_context());
break;
case 0x3d: /* NMSUB.L */
logerror("cp1x unsupported op (%s): NMSUB.L\n", machine().describe_context());
break;
default:
logerror("cp1x unsupported op (%s): [unknown]\n", machine().describe_context());
break;
}
}
template <typename T> void r4000_base_device::cp1_set(unsigned const reg, T const data)
{
// translate softfloat exception flags to cause register

View File

@ -9,6 +9,7 @@
DECLARE_DEVICE_TYPE(R4000, r4000_device)
DECLARE_DEVICE_TYPE(R4400, r4400_device)
DECLARE_DEVICE_TYPE(R4600, r4600_device)
DECLARE_DEVICE_TYPE(R5000, r5000_device)
class r4000_base_device : public cpu_device
{
@ -326,6 +327,7 @@ protected:
virtual void execute_set_input(int inputnum, int state) override;
// cpu implementation
virtual void handle_reserved_instruction(u32 const op);
void cpu_execute(u32 const op);
void cpu_exception(u32 exception, u16 const vector = 0x180);
void cpu_lwl(u32 const op);
@ -355,6 +357,7 @@ protected:
void cp1_unimplemented();
template <typename T> bool cp1_op(T op);
void cp1_execute(u32 const op);
virtual void cp1x_execute(u32 const op);
template <typename T> void cp1_set(unsigned const reg, T const data);
// cp2 implementation
@ -470,4 +473,19 @@ public:
m_cp0[CP0_Config] |= CONFIG_SC;
}
};
class r5000_device : public r4000_base_device
{
public:
r5000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: r4000_base_device(mconfig, R5000, tag, owner, clock, 0x2320, 0x2320, CACHE_32K, CACHE_32K)
{
// no secondary cache
m_cp0[CP0_Config] |= CONFIG_SC;
}
private:
virtual void handle_reserved_instruction(u32 const op) override;
virtual void cp1x_execute(u32 const op) override;
};
#endif // MAME_CPU_MIPS_R4000_H

View File

@ -413,9 +413,7 @@ void ip24_state::indy_5015(machine_config &config)
{
ip24(config);
R4000(config, m_maincpu, 50000000*3);
//m_maincpu->set_icache_size(32768);
//m_maincpu->set_dcache_size(32768);
R5000(config, m_maincpu, 50000000*3);
m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map);
}
@ -424,8 +422,6 @@ void ip24_state::indy_4613(machine_config &config)
ip24(config);
R4600(config, m_maincpu, 33333333*4);
//m_maincpu->set_icache_size(16384);
//m_maincpu->set_dcache_size(16384);
m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map);
}
@ -434,8 +430,6 @@ void ip24_state::indy_4610(machine_config &config)
ip24(config);
R4600(config, m_maincpu, 33333333*3);
//m_maincpu->set_icache_size(16384);
//m_maincpu->set_dcache_size(16384);
m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map);
}
@ -449,8 +443,6 @@ void ip22_state::wd33c93_2(device_t *device)
void ip22_state::indigo2_4415(machine_config &config)
{
R4400(config, m_maincpu, 50000000*3);
//m_maincpu->set_icache_size(32768);
//m_maincpu->set_dcache_size(32768);
m_maincpu->set_addrmap(AS_PROGRAM, &ip22_state::ip22_map);
ip24_base(config);