diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp index d88210c9d79..059dfb47540 100644 --- a/src/devices/cpu/mips/r4000.cpp +++ b/src/devices/cpu/mips/r4000.cpp @@ -90,10 +90,11 @@ DEFINE_DEVICE_TYPE(R5000, r5000_device, "r5000", "MIPS R5000") u32 const r5000_device::s_fcc_masks[8] = { (1U << 23), (1U << 25), (1U << 26), (1U << 27), (1U << 28), (1U << 29), (1U << 30), (1U << 31) }; u32 const r5000_device::s_fcc_shifts[8] = { 23, 25, 26, 27, 28, 29, 30, 31 }; -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) +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, unsigned m32, unsigned m64, unsigned d32, unsigned d64) : 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) + , m_hilo_cycles{ m32, m64, d32, d64 } , m_r{} , m_cp0{} , m_f{} @@ -193,6 +194,8 @@ void r4000_base_device::device_start() m_icache_mask_hi = (0x1000U << config_ic) - 1; m_icache_tag = std::make_unique(0x100U << config_ic); m_icache_data = std::make_unique((0x1000U << config_ic) >> 2); + + R4000_ENDIAN_LE_BE(accessors(m_le), accessors(m_be)); } void r4000_base_device::device_reset() @@ -205,6 +208,7 @@ void r4000_base_device::device_reset() else m_cp0[CP0_Status] = SR_BEV | SR_ERL; + m_hilo_delay = 0; m_branch_state = NONE; m_pc = s64(s32(0xbfc00000)); m_r[0] = 0; @@ -294,6 +298,9 @@ void r4000_base_device::execute_run() m_r[0] = 0; }); + if (m_hilo_delay) + m_hilo_delay--; + // update pc and branch state switch (m_branch_state) { @@ -428,12 +435,22 @@ void r4000_base_device::cpu_execute(u32 const op) break; case 0x10: // MFHI m_r[RDREG] = m_hi; + if (m_hilo_delay) + { + m_icount -= m_hilo_delay; + m_hilo_delay = 0; + } break; case 0x11: // MTHI m_hi = m_r[RSREG]; break; case 0x12: // MFLO m_r[RDREG] = m_lo; + if (m_hilo_delay) + { + m_icount -= m_hilo_delay; + m_hilo_delay = 0; + } break; case 0x13: // MTLO m_lo = m_r[RSREG]; @@ -454,6 +471,7 @@ void r4000_base_device::cpu_execute(u32 const op) m_lo = s64(s32(product)); m_hi = s64(s32(product >> 32)); + m_hilo_delay = m_hilo_cycles[0]; } break; case 0x19: // MULTU @@ -462,6 +480,7 @@ void r4000_base_device::cpu_execute(u32 const op) m_lo = s64(s32(product)); m_hi = s64(s32(product >> 32)); + m_hilo_delay = m_hilo_cycles[0]; } break; case 0x1a: // DIV @@ -469,6 +488,7 @@ void r4000_base_device::cpu_execute(u32 const op) { m_lo = s64(s32(m_r[RSREG]) / s32(m_r[RTREG])); m_hi = s64(s32(m_r[RSREG]) % s32(m_r[RTREG])); + m_hilo_delay = m_hilo_cycles[2]; } break; case 0x1b: // DIVU @@ -476,19 +496,23 @@ void r4000_base_device::cpu_execute(u32 const op) { 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_hilo_delay = m_hilo_cycles[2]; } break; case 0x1c: // DMULT m_lo = mul_64x64(m_r[RSREG], m_r[RTREG], *reinterpret_cast(&m_hi)); + m_hilo_delay = m_hilo_cycles[1]; break; case 0x1d: // DMULTU m_lo = mulu_64x64(m_r[RSREG], m_r[RTREG], m_hi); + m_hilo_delay = m_hilo_cycles[1]; break; case 0x1e: // DDIV if (m_r[RTREG]) { m_lo = s64(m_r[RSREG]) / s64(m_r[RTREG]); m_hi = s64(m_r[RSREG]) % s64(m_r[RTREG]); + m_hilo_delay = m_hilo_cycles[3]; } break; case 0x1f: // DDIVU @@ -496,6 +520,7 @@ void r4000_base_device::cpu_execute(u32 const op) { m_lo = m_r[RSREG] / m_r[RTREG]; m_hi = m_r[RSREG] % m_r[RTREG]; + m_hilo_delay = m_hilo_cycles[3]; } break; case 0x20: // ADD @@ -3704,6 +3729,21 @@ void r4000_base_device::address_error(int intention, u64 const address) } } +template void r4000_base_device::accessors(T &m) +{ + space(AS_PROGRAM).cache(m); + + read_byte = [&m](offs_t offset) { return m.read_byte(offset); }; + read_word = [&m](offs_t offset) { return m.read_word(offset); }; + read_dword = [&m](offs_t offset) { return m.read_dword(offset); }; + read_qword = [&m](offs_t offset) { return m.read_qword(offset); }; + + write_byte = [&m](offs_t offset, u8 data) { m.write_byte(offset, data); }; + write_word = [&m](offs_t offset, u16 data, u16 mem_mask) { m.write_word(offset, data, mem_mask); }; + write_dword = [&m](offs_t offset, u32 data, u32 mem_mask) { m.write_dword(offset, data, mem_mask); }; + write_qword = [&m](offs_t offset, u64 data, u64 mem_mask) { m.write_qword(offset, data, mem_mask); }; +} + template std::enable_if_t>::value, bool> r4000_base_device::load(u64 address, U &&apply) { // alignment error @@ -3748,10 +3788,10 @@ template std::enable_if_t std::enable_if_t std::enable_if_t &&apply) { if (t == UNCACHED) { - const u32 insn = space(0).read_dword(address); + const u32 insn = read_dword(address); if (m_bus_error) { @@ -3922,7 +3962,7 @@ bool r4000_base_device::fetch(u64 address, std::function &&apply) tag = ICACHE_V | (address >> 12); for (unsigned i = 0; i < m_icache_line_size; i += 8) { - u64 const data = space(0).read_qword((address & m_icache_mask_lo) | i); + u64 const data = read_qword((address & m_icache_mask_lo) | i); m_icache_data[(((cache_address & m_icache_mask_lo) | i) >> 2) + 0] = u32(data); m_icache_data[(((cache_address & m_icache_mask_lo) | i) >> 2) + 1] = data >> 32; @@ -3936,7 +3976,7 @@ bool r4000_base_device::fetch(u64 address, std::function &&apply) } else { - const u32 insn = space(0).read_dword(address); + const u32 insn = read_dword(address); if (m_bus_error) { diff --git a/src/devices/cpu/mips/r4000.h b/src/devices/cpu/mips/r4000.h index 2e4c0e177a7..a2dad69ba6a 100644 --- a/src/devices/cpu/mips/r4000.h +++ b/src/devices/cpu/mips/r4000.h @@ -57,7 +57,7 @@ protected: CACHE_256K = 6, CACHE_512K = 7, }; - 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); + 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, unsigned m32, unsigned m64, unsigned d32, unsigned d64); enum cp0_reg : int { @@ -320,8 +320,10 @@ protected: virtual std::unique_ptr create_disassembler() override; // device_execute_interface overrides + virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks * 2); } + virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles + 1) / 2; } virtual u32 execute_min_cycles() const noexcept override { return 1; } - virtual u32 execute_max_cycles() const noexcept override { return 40; } + virtual u32 execute_max_cycles() const noexcept override { return *std::max_element(std::begin(m_hilo_cycles), std::end(m_hilo_cycles)); } virtual u32 execute_input_lines() const noexcept override { return 6; } virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; @@ -370,6 +372,7 @@ protected: translate_result translate(int intention, u64 &address); void address_error(int intention, u64 const address); + template void accessors(T &m); template std::enable_if_t>::value, bool> load(u64 program_address, U &&apply); template std::enable_if_t>::value, bool> load_linked(u64 program_address, U &&apply); template std::enable_if_t::value, bool> store(u64 program_address, U data, T mem_mask = ~T(0)); @@ -384,9 +387,26 @@ protected: address_space_config m_program_config_le; address_space_config m_program_config_be; + // memory access helpers + memory_access<64, 3, 0, ENDIANNESS_LITTLE>::cache m_le; + memory_access<64, 3, 0, ENDIANNESS_BIG>::cache m_be; + + std::function read_byte; + std::function read_word; + std::function read_dword; + std::function read_qword; + std::function write_byte; + std::function write_word; + std::function write_dword; + std::function write_qword; + // runtime state int m_icount; + // integer multiple/divide state + unsigned const m_hilo_cycles[4]; + unsigned m_hilo_delay; + // cpu state u64 m_pc; u64 m_r[32]; @@ -447,7 +467,7 @@ class r4000_device : public r4000_base_device public: // NOTE: R4000 chips prior to 3.0 have an xtlb bug r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K) + : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K, 10, 20, 69, 133) { // no secondary cache m_cp0[CP0_Config] |= CONFIG_SC; @@ -458,7 +478,7 @@ class r4400_device : public r4000_base_device { public: r4400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K) + : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K, 10, 20, 69, 133) { // no secondary cache m_cp0[CP0_Config] |= CONFIG_SC; @@ -469,7 +489,7 @@ class r4600_device : public r4000_base_device { public: r4600_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K) + : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K, 10, 12, 42, 74) { // no secondary cache m_cp0[CP0_Config] |= CONFIG_SC; @@ -480,7 +500,7 @@ 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) + : r4000_base_device(mconfig, R5000, tag, owner, clock, 0x2320, 0x2320, CACHE_32K, CACHE_32K, 5, 9, 36, 68) { // no secondary cache m_cp0[CP0_Config] |= CONFIG_SC; diff --git a/src/mame/drivers/indigo.cpp b/src/mame/drivers/indigo.cpp index b2553e33f7d..ede8813bb55 100644 --- a/src/mame/drivers/indigo.cpp +++ b/src/mame/drivers/indigo.cpp @@ -214,7 +214,7 @@ void indigo4k_state::indigo4k(machine_config &config) { indigo_base(config); - R4000(config, m_maincpu, 50000000*2); + R4000(config, m_maincpu, 50000000); //m_maincpu->set_icache_size(32768); //m_maincpu->set_dcache_size(32768); m_maincpu->set_addrmap(AS_PROGRAM, &indigo4k_state::mem_map); diff --git a/src/mame/drivers/indy_indigo2.cpp b/src/mame/drivers/indy_indigo2.cpp index 207f2214230..8a6a202f548 100644 --- a/src/mame/drivers/indy_indigo2.cpp +++ b/src/mame/drivers/indy_indigo2.cpp @@ -407,7 +407,7 @@ void ip24_state::indy_5015(machine_config &config) { ip24(config); - R5000(config, m_maincpu, 50000000*3); + R5000(config, m_maincpu, 75'000'000); m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map); } @@ -415,7 +415,7 @@ void ip24_state::indy_4613(machine_config &config) { ip24(config); - R4600(config, m_maincpu, 33333333*4); + R4600(config, m_maincpu, 66'666'666); m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map); } @@ -423,7 +423,7 @@ void ip24_state::indy_4610(machine_config &config) { ip24(config); - R4600(config, m_maincpu, 33333333*3); + R4600(config, m_maincpu, 50'000'000); m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip24_map); } @@ -436,7 +436,7 @@ void ip22_state::wd33c93_2(device_t *device) void ip22_state::indigo2_4415(machine_config &config) { - R4400(config, m_maincpu, 50000000*3); + R4400(config, m_maincpu, 75'000'000); m_maincpu->set_addrmap(AS_PROGRAM, &ip22_state::ip22_map); ip24_base(config);