diff options
author | 2018-06-28 18:16:55 +0200 | |
---|---|---|
committer | 2018-06-28 18:24:16 +0200 | |
commit | eb5a8a3dc85b2cb3572687633b07bf93292ead62 (patch) | |
tree | c81c264a72bb19ebde9f758c406ff17b6d01905a | |
parent | 85a16dfb9d98283b6dfccb4b1b915fd19c432361 (diff) |
-ps2sony: Fleshing out the skeleton driver. [Ryan Holtz]
* Added ps2timer device to encapsulate Playstation 2 timers.
* Temporarily hacked R5900 core to always have scratchpad RAM mapped at 0x70000000.
* Added reference counting to divtlb so that it does not unmap pages that are still shared with other entries.
* Added a considerable amount of logging to ps2sony.cpp.
-mips3: Added basic Emotion Engine support. [Ryan Holtz]
* Added S bit to TLB mapping.
* Added support for VSUB, VIADD, VSQI, VISWR, VOR, LQ, SQ, MFSA, MTSA, MFHI1, MFLO1, MULT1, DIV1, DIVU1, PEXTLW, PADDUW, PMFHI,
PMFLO, PCPYLD, PCPYUD, SQC2, LQC2 opcodes. [Ryan Holtz]
-rw-r--r-- | scripts/target/mame/mess.lua | 2 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips3.cpp | 1151 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips3.h | 1383 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips3com.cpp | 6 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips3com.h | 4 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips3dsm.cpp | 6 | ||||
-rw-r--r-- | src/devices/cpu/mips/r3000.cpp | 31 | ||||
-rw-r--r-- | src/devices/cpu/mips/r3000.h | 26 | ||||
-rw-r--r-- | src/devices/machine/wd33c93.cpp | 2 | ||||
-rw-r--r-- | src/emu/divtlb.cpp | 23 | ||||
-rw-r--r-- | src/emu/divtlb.h | 1 | ||||
-rw-r--r-- | src/mame/drivers/ps2sony.cpp | 1045 | ||||
-rw-r--r-- | src/mame/machine/ps2timer.cpp | 270 | ||||
-rw-r--r-- | src/mame/machine/ps2timer.h | 118 |
14 files changed, 3337 insertions, 731 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 2e5db83356e..3009590149e 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -3061,6 +3061,8 @@ files { MAME_DIR .. "src/mame/drivers/pve500.cpp", MAME_DIR .. "src/mame/drivers/smc777.cpp", MAME_DIR .. "src/mame/drivers/ps2sony.cpp", + MAME_DIR .. "src/mame/machine/ps2timer.cpp", + MAME_DIR .. "src/mame/machine/ps2timer.h", } createMESSProjects(_target, _subtarget, "sord") diff --git a/src/devices/cpu/mips/mips3.cpp b/src/devices/cpu/mips/mips3.cpp index f48682fd20a..021b81293b8 100644 --- a/src/devices/cpu/mips/mips3.cpp +++ b/src/devices/cpu/mips/mips3.cpp @@ -123,12 +123,12 @@ DEFINE_DEVICE_TYPE(RM7000LE, rm7000le_device, "rm7000le", "MIPS RM7000 (littl // VR4300 and VR5432 have 4 fewer PFN bits, and only 32 TLB entries -mips3_device::mips3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, mips3_flavor flavor, endianness_t endianness) +mips3_device::mips3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, mips3_flavor flavor, endianness_t endianness, uint32_t data_bits) : cpu_device(mconfig, type, tag, owner, clock) , device_vtlb_interface(mconfig, *this, AS_PROGRAM) - , m_program_config("program", endianness, 32, 32, 0, 32, MIPS3_MIN_PAGE_SHIFT) - , m_flavor(flavor) , m_core(nullptr) + , m_program_config("program", endianness, data_bits, 32, 0, 32, MIPS3_MIN_PAGE_SHIFT) + , m_flavor(flavor) , m_ppc(0) , m_nextpc(0) , m_pcbase(0) @@ -146,6 +146,7 @@ mips3_device::mips3_device(const machine_config &mconfig, device_type type, cons , m_ldr(endianness == ENDIANNESS_BIG ? &mips3_device::ldr_be : &mips3_device::ldr_le) , m_sdl(endianness == ENDIANNESS_BIG ? &mips3_device::sdl_be : &mips3_device::sdl_le) , m_sdr(endianness == ENDIANNESS_BIG ? &mips3_device::sdr_be : &mips3_device::sdr_le) + , m_data_bits(data_bits) , c_system_clock(0) , m_pfnmask(flavor == MIPS3_TYPE_VR4300 ? 0x000fffff : 0x00ffffff) , m_tlbentries(flavor == MIPS3_TYPE_VR4300 ? 32 : MIPS3_MAX_TLB_ENTRIES) @@ -280,7 +281,10 @@ void mips3_device::generate_exception(int exception, int backup) { osd_printf_debug("TLB miss @ %08X\n", (uint32_t)m_core->cpr[0][COP0_BadVAddr]); } - m_core->pc += offset; + else + { + m_core->pc += offset; + } /* useful for tracking interrupts @@ -336,21 +340,41 @@ void mips3_device::device_start() /* initialize based on the config */ memset(m_core, 0, sizeof(internal_mips3_state)); m_core->vfr[0][3] = 1.0f; + m_core->vfmem = &m_core->vumem[0]; + m_core->vimem = reinterpret_cast<uint32_t*>(m_core->vfmem); m_cpu_clock = clock(); m_program = &space(AS_PROGRAM); if(m_program->endianness() == ENDIANNESS_LITTLE) { - auto cache = m_program->cache<2, 0, ENDIANNESS_LITTLE>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + if (m_data_bits == 32) + { + auto cache = m_program->cache<2, 0, ENDIANNESS_LITTLE>(); + m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + } + else + { + auto cache = m_program->cache<3, 0, ENDIANNESS_LITTLE>(); + m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + } } else { - auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; - } + if (m_data_bits == 32) + { + auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>(); + m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + } + else + { + auto cache = m_program->cache<3, 0, ENDIANNESS_BIG>(); + m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + } + } /* set up the endianness */ m_program->accessors(m_memory); @@ -360,7 +384,7 @@ void mips3_device::device_start() uint32_t flags = 0; /* initialize the UML generator */ - m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 8, 32, 2); + m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 8, m_data_bits, 2); /* add symbols for our stuff */ m_drcuml->symbol_add(&m_core->pc, sizeof(m_core->pc), "pc"); @@ -652,6 +676,77 @@ void mips3_device::device_start() set_icountptr(m_core->icount); } +void r5900le_device::device_start() +{ + mips3_device::device_start(); +#if USE_ABI_REG_NAMES + state_add( MIPS3_R0H, "zeroh", m_core->rh[0]).callimport().formatstr("%016X"); // Can't change R0 + state_add( MIPS3_R1H, "ath", m_core->rh[1]).formatstr("%016X"); + state_add( MIPS3_R2H, "v0h", m_core->rh[2]).formatstr("%016X"); + state_add( MIPS3_R3H, "v1h", m_core->rh[3]).formatstr("%016X"); + state_add( MIPS3_R4H, "a0h", m_core->rh[4]).formatstr("%016X"); + state_add( MIPS3_R5H, "a1h", m_core->rh[5]).formatstr("%016X"); + state_add( MIPS3_R6H, "a2h", m_core->rh[6]).formatstr("%016X"); + state_add( MIPS3_R7H, "a3h", m_core->rh[7]).formatstr("%016X"); + state_add( MIPS3_R8H, "t0h", m_core->rh[8]).formatstr("%016X"); + state_add( MIPS3_R9H, "t1h", m_core->rh[9]).formatstr("%016X"); + state_add( MIPS3_R10H, "t2h", m_core->rh[10]).formatstr("%016X"); + state_add( MIPS3_R11H, "t3h", m_core->rh[11]).formatstr("%016X"); + state_add( MIPS3_R12H, "t4h", m_core->rh[12]).formatstr("%016X"); + state_add( MIPS3_R13H, "t5h", m_core->rh[13]).formatstr("%016X"); + state_add( MIPS3_R14H, "t6h", m_core->rh[14]).formatstr("%016X"); + state_add( MIPS3_R15H, "t7h", m_core->rh[15]).formatstr("%016X"); + state_add( MIPS3_R16H, "s0h", m_core->rh[16]).formatstr("%016X"); + state_add( MIPS3_R17H, "s1h", m_core->rh[17]).formatstr("%016X"); + state_add( MIPS3_R18H, "s2h", m_core->rh[18]).formatstr("%016X"); + state_add( MIPS3_R19H, "s3h", m_core->rh[19]).formatstr("%016X"); + state_add( MIPS3_R20H, "s4h", m_core->rh[20]).formatstr("%016X"); + state_add( MIPS3_R21H, "s5h", m_core->rh[21]).formatstr("%016X"); + state_add( MIPS3_R22H, "s6h", m_core->rh[22]).formatstr("%016X"); + state_add( MIPS3_R23H, "s7h", m_core->rh[23]).formatstr("%016X"); + state_add( MIPS3_R24H, "t8h", m_core->rh[24]).formatstr("%016X"); + state_add( MIPS3_R25H, "t9h", m_core->rh[25]).formatstr("%016X"); + state_add( MIPS3_R26H, "k0h", m_core->rh[26]).formatstr("%016X"); + state_add( MIPS3_R27H, "k1h", m_core->rh[27]).formatstr("%016X"); + state_add( MIPS3_R28H, "gph", m_core->rh[28]).formatstr("%016X"); + state_add( MIPS3_R29H, "sph", m_core->rh[29]).formatstr("%016X"); + state_add( MIPS3_R30H, "fph", m_core->rh[30]).formatstr("%016X"); + state_add( MIPS3_R31H, "rah", m_core->rh[31]).formatstr("%016X"); +#else + state_add( MIPS3_R0H, "R0H", m_core->rh[0]).callimport().formatstr("%016X"); // Can't change R0 + state_add( MIPS3_R1H, "R1H", m_core->rh[1]).formatstr("%016X"); + state_add( MIPS3_R2H, "R2H", m_core->rh[2]).formatstr("%016X"); + state_add( MIPS3_R3H, "R3H", m_core->rh[3]).formatstr("%016X"); + state_add( MIPS3_R4H, "R4H", m_core->rh[4]).formatstr("%016X"); + state_add( MIPS3_R5H, "R5H", m_core->rh[5]).formatstr("%016X"); + state_add( MIPS3_R6H, "R6H", m_core->rh[6]).formatstr("%016X"); + state_add( MIPS3_R7H, "R7H", m_core->rh[7]).formatstr("%016X"); + state_add( MIPS3_R8H, "R8H", m_core->rh[8]).formatstr("%016X"); + state_add( MIPS3_R9H, "R9H", m_core->rh[9]).formatstr("%016X"); + state_add( MIPS3_R10H, "R10H", m_core->rh[10]).formatstr("%016X"); + state_add( MIPS3_R11H, "R11H", m_core->rh[11]).formatstr("%016X"); + state_add( MIPS3_R12H, "R12H", m_core->rh[12]).formatstr("%016X"); + state_add( MIPS3_R13H, "R13H", m_core->rh[13]).formatstr("%016X"); + state_add( MIPS3_R14H, "R14H", m_core->rh[14]).formatstr("%016X"); + state_add( MIPS3_R15H, "R15H", m_core->rh[15]).formatstr("%016X"); + state_add( MIPS3_R16H, "R16H", m_core->rh[16]).formatstr("%016X"); + state_add( MIPS3_R17H, "R17H", m_core->rh[17]).formatstr("%016X"); + state_add( MIPS3_R18H, "R18H", m_core->rh[18]).formatstr("%016X"); + state_add( MIPS3_R19H, "R19H", m_core->rh[19]).formatstr("%016X"); + state_add( MIPS3_R20H, "R20H", m_core->rh[20]).formatstr("%016X"); + state_add( MIPS3_R21H, "R21H", m_core->rh[21]).formatstr("%016X"); + state_add( MIPS3_R22H, "R22H", m_core->rh[22]).formatstr("%016X"); + state_add( MIPS3_R23H, "R23H", m_core->rh[23]).formatstr("%016X"); + state_add( MIPS3_R24H, "R24H", m_core->rh[24]).formatstr("%016X"); + state_add( MIPS3_R25H, "R25H", m_core->rh[25]).formatstr("%016X"); + state_add( MIPS3_R26H, "R26H", m_core->rh[26]).formatstr("%016X"); + state_add( MIPS3_R27H, "R27H", m_core->rh[27]).formatstr("%016X"); + state_add( MIPS3_R28H, "R28H", m_core->rh[28]).formatstr("%016X"); + state_add( MIPS3_R29H, "R29H", m_core->rh[29]).formatstr("%016X"); + state_add( MIPS3_R30H, "R30H", m_core->rh[30]).formatstr("%016X"); + state_add( MIPS3_R31H, "R31H", m_core->rh[31]).formatstr("%016X"); +#endif +} void mips3_device::state_export(const device_state_entry &entry) { @@ -1346,6 +1441,163 @@ inline void mips3_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t } } +inline void r5900le_device::WBYTE(offs_t address, uint8_t data) +{ + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_byte)(*m_program, address, data); + else mips3_device::WBYTE(address, data); +} + +inline void r5900le_device::WHALF(offs_t address, uint16_t data) +{ + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_word)(*m_program, address, data); + else mips3_device::WHALF(address, data); +} + +inline void r5900le_device::WWORD(offs_t address, uint32_t data) +{ + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_dword)(*m_program, address, data); + else mips3_device::WWORD(address, data); +} + +inline void r5900le_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask) +{ + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_dword_masked)(*m_program, address, data, mem_mask); + else mips3_device::WWORD_MASKED(address, data, mem_mask); +} + +inline void r5900le_device::WDOUBLE(offs_t address, uint64_t data) { + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_qword)(*m_program, address, data); + else mips3_device::WDOUBLE(address, data); +} + +inline void r5900le_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) +{ + if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_qword_masked)(*m_program, address, data, mem_mask); + else mips3_device::WDOUBLE_MASKED(address, data, mem_mask); +} + +inline void r5900le_device::WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + (*m_memory.write_qword)(*m_program, address, data_hi); + (*m_memory.write_qword)(*m_program, address + 8, data_lo); + return; + } + + const uint32_t tlbval = vtlb_table()[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data_hi); + (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | ((address + 8) & 0xfff), data_lo); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline bool r5900le_device::RBYTE(offs_t address, uint32_t *result) { + if (address >= 0x70000000 && address < 0x70004000) { + *result = (*m_memory.read_byte)(*m_program, address); + return true; + } + return mips3_device::RBYTE(address, result); +} + +inline bool r5900le_device::RHALF(offs_t address, uint32_t *result) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result = (*m_memory.read_word)(*m_program, address); + return true; + } + return mips3_device::RHALF(address, result); +} + +inline bool r5900le_device::RWORD(offs_t address, uint32_t *result) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result = (*m_memory.read_dword)(*m_program, address); + return true; + } + return mips3_device::RWORD(address, result); +} + +inline bool r5900le_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result = (*m_memory.read_dword_masked)(*m_program, address, mem_mask); + return true; + } + return mips3_device::RWORD_MASKED(address, result, mem_mask); +} + +inline bool r5900le_device::RDOUBLE(offs_t address, uint64_t *result) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result = (*m_memory.read_qword)(*m_program, address); + return true; + } + return mips3_device::RDOUBLE(address, result); +} + +inline bool r5900le_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result = (*m_memory.read_qword_masked)(*m_program, address, mem_mask); + return true; + } + return mips3_device::RDOUBLE_MASKED(address, result, mem_mask); +} + +inline bool r5900le_device::RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo) +{ + if (address >= 0x70000000 && address < 0x70004000) + { + *result_hi = (*m_memory.read_qword)(*m_program, address); + *result_lo = (*m_memory.read_qword)(*m_program, address + 8); + return true; + } + + const uint32_t tlbval = vtlb_table()[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + *result_hi = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff)); + *result_lo = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | ((address + 8) & 0xfff)); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result_hi = 0; + *result_lo = 0; + return false; + } + return true; +} + /*************************************************************************** @@ -1845,6 +2097,12 @@ void mips3_device::handle_cop1_fr0(uint32_t op) FDVALD_FR0 = 1.0 / sqrt(FSVALD_FR0); break; + case 0x18: /* R5900 */ + if (m_flavor != MIPS3_TYPE_R5900) + break; + m_core->acc = FSVALS_FR0 + FTVALS_FR0; + break; + case 0x20: if (IS_INTEGRAL(op)) { @@ -2485,6 +2743,16 @@ void mips3_device::handle_cop1x_fr1(uint32_t op) COP2 (CUSTOM) EXECUTION HANDLING ***************************************************************************/ +inline void mips3_device::handle_dmfc2(uint32_t op) +{ + if (RTREG) RTVAL64 = get_cop2_reg(RDREG); +} + +inline void mips3_device::handle_dmtc2(uint32_t op) +{ + set_cop2_reg(RDREG, RTVAL64); +} + inline uint64_t mips3_device::get_cop2_reg(int idx) { return m_core->cpr[2][idx]; @@ -2502,7 +2770,112 @@ inline uint64_t mips3_device::get_cop2_creg(int idx) inline void mips3_device::set_cop2_creg(int idx, uint64_t val) { - m_core->ccr[2][idx] = val; + m_core->vfr[idx][0] = val; +} + +inline void r5900le_device::handle_dmfc2(uint32_t op) +{ + // QMFC2 + if (!RTREG) + { + return; + } + const int rt = RTREG; + uint32_t rtval[4] = { 0 }; + uint32_t *reg = reinterpret_cast<uint32_t*>(m_core->vfr[RDREG]); + for (int i = 0; i < 4; i++) + { + rtval[i] = reg[i]; + } + m_core->r[rt] = ((uint64_t)rtval[1] << 32) | rtval[0]; + m_core->rh[rt] = ((uint64_t)rtval[3] << 32) | rtval[2]; +} + +inline void r5900le_device::handle_dmtc2(uint32_t op) +{ + // QMTC2 + uint32_t rt = RTREG; + uint32_t rtval[4] = { (uint32_t)m_core->r[rt], (uint32_t)(m_core->r[rt] >> 32), (uint32_t)m_core->rh[rt], (uint32_t)(m_core->rh[rt] >> 32) }; + uint32_t *reg = reinterpret_cast<uint32_t*>(m_core->vfr[RDREG]); + for (int i = 0; i < 4; i++) + { + reg[i] = rtval[i]; + } +} + +inline uint64_t r5900le_device::get_cop2_reg(int idx) +{ + return reinterpret_cast<uint32_t*>(m_core->vfr[idx])[0]; +} + +inline void r5900le_device::set_cop2_reg(int idx, uint64_t val) +{ + reinterpret_cast<uint32_t*>(m_core->vfr[idx])[0] = (uint32_t)val; +} + +inline uint64_t r5900le_device::get_cop2_creg(int idx) +{ + return m_core->vcr[idx]; +} + +inline void r5900le_device::set_cop2_creg(int idx, uint64_t val) +{ + if (idx < 16) + { + m_core->vcr[idx] = val & 0xffff; + } + else + { + switch (idx) + { + case 16: // Status flag + m_core->vcr[idx] = val & 0xf30; + break; + + case 17: // MAC flag + case 26: // TPC register + case 27: // CMSAR0 register + m_core->vcr[idx] = val & 0xffff; + break; + + case 18: // clipping flag + m_core->vcr[idx] = val & 0xffffff; + break; + + case 20: // R register + m_core->vcr[idx] = val & 0x7fffff; + break; + + case 21: // I register + case 22: // Q register + m_core->vcr[idx] = val; + break; + + case 28: // FBRST register + m_core->vcr[idx] = val & 0xf0f; + break; + + case 29: // VPU-STAT register + // Register is read-only + break; + + case 31: // CMSAR1 register + m_core->vcr[idx] = val & 0xffff; + // TODO: Begin execution + break; + + case 19: + case 23: + case 24: + case 25: + case 30: // reserved + break; + + default: + m_core->vcr[idx] = val; + break; + } + } } void mips3_device::handle_cop2(uint32_t op) @@ -2516,12 +2889,12 @@ void mips3_device::handle_cop2(uint32_t op) switch (RSREG) { - case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (int32_t)get_cop2_reg(RDREG); break; - case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop2_reg(RDREG); break; - case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (int32_t)get_cop2_creg(RDREG); break; - case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL32); break; - case 0x05: /* DMTCz */ set_cop2_reg(RDREG, RTVAL64); break; - case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL32); break; + case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (int32_t)get_cop2_reg(RDREG); break; + case 0x01: /* DMFCz */ handle_dmfc2(op); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (int32_t)get_cop2_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL32); break; + case 0x05: /* DMTCz */ handle_dmtc2(op); break; + case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL32); break; case 0x08: /* BC */ switch (RTREG) { @@ -2543,18 +2916,186 @@ void mips3_device::handle_extra_cop2(uint32_t op) /*************************************************************************** - VU0 (COP2) EXECUTION HANDLING (R5900) + VU0/1 (COP2) EXECUTION HANDLING (R5900) ***************************************************************************/ void r5900le_device::handle_extra_cop2(uint32_t op) { - invalid_instruction(op); + const int rd = (op >> 6) & 31; + const int rs = (op >> 11) & 31; + const int rt = (op >> 16) & 31; + const int ext = ((op >> 4) & 0x7c) | (op & 3); + + switch (op & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: + printf("Unsupported instruction: VADDbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x04: case 0x05: case 0x06: case 0x07: + printf("Unsupported instruction: VSUBbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + printf("Unsupported instruction: VMADDbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + printf("Unsupported instruction: VMSUBbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x10: case 0x11: case 0x12: case 0x13: + printf("Unsupported instruction: VMAXbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x14: case 0x15: case 0x16: case 0x17: + printf("Unsupported instruction: VMINIbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + printf("Unsupported instruction: VMULbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1c: printf("Unsupported instruction: VMULq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1d: printf("Unsupported instruction: VMAXi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1e: printf("Unsupported instruction: VMULi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1f: printf("Unsupported instruction: VMINIi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x20: printf("Unsupported instruction: VADDq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x21: printf("Unsupported instruction: VMADDq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x22: printf("Unsupported instruction: VADDi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x23: printf("Unsupported instruction: VMADDi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x24: printf("Unsupported instruction: VSUBq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x25: printf("Unsupported instruction: VMSUBq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x26: printf("Unsupported instruction: VSUBi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x27: printf("Unsupported instruction: VMSUBi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x28: printf("Unsupported instruction: VADD @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x29: printf("Unsupported instruction: VMADD @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2a: printf("Unsupported instruction: VMUL @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2b: printf("Unsupported instruction: VMAX @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2c: + { + float *fs = m_core->vfr[rs]; + float *ft = m_core->vfr[rt]; + float *fd = m_core->vfr[rt]; + for (int field = 0; field < 4; field++) + { + if (BIT(op, 24-field)) + { + fd[field] = fs[field] - ft[field]; + } + } + break; + } + case 0x2d: printf("Unsupported instruction: VMSUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2e: printf("Unsupported instruction: VOPMSUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2f: printf("Unsupported instruction: VMINI @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x30: + if (rd) + { + m_core->vcr[rd] = (m_core->vcr[rs] + m_core->vcr[rt]) & 0xffff; + } + break; + case 0x31: printf("Unsupported instruction: VISUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x32: printf("Unsupported instruction: VIADDI @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x34: printf("Unsupported instruction: VIAND @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x35: printf("Unsupported instruction: VIOR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x38: printf("Unsupported instruction: VCALLMS @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x39: printf("Unsupported instruction: VCALLMSR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + switch (ext) + { + case 0x00: case 0x01: case 0x02: case 0x03: + printf("Unsupported instruction: VADDAbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x04: case 0x05: case 0x06: case 0x07: + printf("Unsupported instruction: VSUBAbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + printf("Unsupported instruction: VMADDAbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + printf("Unsupported instruction: VMSUBAbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x10: printf("Unsupported instruction: VITOF0 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x11: printf("Unsupported instruction: VITOF4 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x12: printf("Unsupported instruction: VITOF12 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x13: printf("Unsupported instruction: VITOF15 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x14: printf("Unsupported instruction: VFTOI0 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x15: printf("Unsupported instruction: VFTOI4 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x16: printf("Unsupported instruction: VFTOI12 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x17: printf("Unsupported instruction: VFTOI15 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + printf("Unsupported instruction: VMULAbc @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1c: printf("Unsupported instruction: VMULAq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1d: printf("Unsupported instruction: VABS @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1e: printf("Unsupported instruction: VMULAi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x1f: printf("Unsupported instruction: VCLIP @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x20: printf("Unsupported instruction: VADDAq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x21: printf("Unsupported instruction: VMADDAq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x22: printf("Unsupported instruction: VADDAi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x23: printf("Unsupported instruction: VMADDAi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x24: printf("Unsupported instruction: VSUBAq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x25: printf("Unsupported instruction: VMSUBAq @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x26: printf("Unsupported instruction: VSUBAi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x27: printf("Unsupported instruction: VMSUBAi @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x28: printf("Unsupported instruction: VADDA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x29: printf("Unsupported instruction: VMADDA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2a: printf("Unsupported instruction: VMULA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + // 2b? + case 0x2c: printf("Unsupported instruction: VSUBA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2d: printf("Unsupported instruction: VMSUBA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2e: printf("Unsupported instruction: VOPMULA @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x2f: printf("Unsupported instruction: VNOP @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x30: printf("Unsupported instruction: VMOVE @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x31: printf("Unsupported instruction: VMR32 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + // 32? + // 33? + case 0x34: printf("Unsupported instruction: VLQI @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x35: + { + uint32_t *base = &m_core->vimem[m_core->vcr[rt] << 2]; + uint32_t *fs = reinterpret_cast<uint32_t*>(m_core->vfr[rs]); + for (int field = 0; field < 4; field++) + { + if (BIT(op, 24-field)) + { + base[field] = fs[field]; + } + } + if (rt) + { + m_core->vcr[rt]++; + m_core->vcr[rt] &= 0xffff; + } + break; + } + case 0x36: printf("Unsupported instruction: VLQD @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x37: printf("Unsupported instruction: VSQD @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x38: printf("Unsupported instruction: VDIV @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x39: printf("Unsupported instruction: VSQRT @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3a: printf("Unsupported instruction: VRSQRT @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3b: printf("Unsupported instruction: VWAITQ @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3c: printf("Unsupported instruction: VMTIR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3d: printf("Unsupported instruction: VMFIR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3e: printf("Unsupported instruction: VILWR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x3f: /* VISWR */ + { + const uint32_t val = m_core->vcr[rt]; + const uint32_t base = m_core->vcr[rs] << 2; + for (int field = 0; field < 4; field++) + { + if (BIT(op, 24-field)) + { + m_core->vimem[base + field] = val; + } + } + break; + } + case 0x40: printf("Unsupported instruction: VRNEXT @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x41: printf("Unsupported instruction: VRGET @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x42: printf("Unsupported instruction: VRINIT @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + case 0x43: printf("Unsupported instruction: VRXOR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported VU instruction\n"); break; + default: invalid_instruction(op); break; + } + break; + default: + invalid_instruction(op); + break; + } } /*************************************************************************** CORE EXECUTION LOOP ***************************************************************************/ +void mips3_device::handle_extra_base(uint32_t op) +{ + /* ??? */ + invalid_instruction(op); +} + void mips3_device::handle_regimm(uint32_t op) { switch (RTREG) @@ -2608,6 +3149,8 @@ void mips3_device::handle_special(uint32_t op) LOVAL64 = (int32_t)temp64; HIVAL64 = (int32_t)(temp64 >> 32); m_core->icount -= 3; + if (m_flavor == MIPS3_TYPE_R5900 && RDREG) + RDVAL64 = LOVAL64; break; } case 0x19: /* MULTU */ @@ -2616,6 +3159,8 @@ void mips3_device::handle_special(uint32_t op) LOVAL64 = (int32_t)temp64; HIVAL64 = (int32_t)(temp64 >> 32); m_core->icount -= 3; + if (m_flavor == MIPS3_TYPE_R5900 && RDREG) + RDVAL64 = LOVAL64; break; } case 0x1a: /* DIV */ @@ -2696,7 +3241,8 @@ void mips3_device::handle_special(uint32_t op) case 0x25: /* OR */ if (RDREG) RDVAL64 = RSVAL64 | RTVAL64; break; case 0x26: /* XOR */ if (RDREG) RDVAL64 = RSVAL64 ^ RTVAL64; break; case 0x27: /* NOR */ if (RDREG) RDVAL64 = ~(RSVAL64 | RTVAL64); break; - case 0x2a: /* SLT */ if (RDREG) RDVAL64 = (int64_t)RSVAL64 < (int64_t)RTVAL64; break; + case 0x28: handle_extra_special(op); break; + case 0x2a: /* SLT */ if (RDREG) RDVAL64 = (int64_t)RSVAL64 < (int64_t)RTVAL64; break; case 0x2b: /* SLTU */ if (RDREG) RDVAL64 = (uint64_t)RSVAL64 < (uint64_t)RTVAL64; break; case 0x2c: /* DADD */ if (ENABLE_OVERFLOWS && RSVAL64 > ~RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1); @@ -2729,21 +3275,11 @@ void mips3_device::handle_extra_special(uint32_t op) invalid_instruction(op); } -void r5900le_device::handle_extra_special(uint32_t op) -{ - invalid_instruction(op); -} - void mips3_device::handle_extra_regimm(uint32_t op) { invalid_instruction(op); } -void r5900le_device::handle_extra_regimm(uint32_t op) -{ - invalid_instruction(op); -} - void mips3_device::handle_idt(uint32_t op) { switch (op & 0x1f) @@ -2758,8 +3294,551 @@ void mips3_device::handle_idt(uint32_t op) } } +void r5900le_device::handle_extra_base(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rt = (op >> 16) & 31; + + switch (op >> 26) + { + case 0x1e: /* LQ */ + { + uint64_t temp64[2]; + bool success = RQUAD(SIMMVAL + m_core->r[rs], &temp64[1], &temp64[0]); + if (success && rt) + { + m_core->r[rt] = temp64[0]; + m_core->rh[rt] = temp64[1]; + } + m_core->icount--; + break; + } + case 0x1f: /* SQ */ + WQUAD(SIMMVAL + m_core->r[rs], m_core->rh[rt], m_core->r[rt]); + m_core->icount--; + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_extra_special(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rd = (op >> 11) & 31; + + switch (op & 63) + { + case 0x28: /* MFSA */ + m_core->r[rd] = m_core->sa; + break; + case 0x29: /* MTSA */ + m_core->sa = (uint32_t)m_core->r[rs]; + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_extra_regimm(uint32_t op) +{ + switch (op & 63) + { + case 0x18: /* MTSAB */ + printf("Unsupported instruction: MTSAB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x19: /* MTSAH */ + printf("Unsupported instruction: MTSAH @%08x\n", m_core->pc - 4); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + void r5900le_device::handle_idt(uint32_t op) { + //const int rs = (op >> 21) & 31; + //const int rt = (op >> 16) & 31; + const int rd = (op >> 11) & 31; + + switch (op & 0x3f) + { + case 0x00: /* MADD */ + printf("Unsupported instruction: MADD @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x01: /* MADDU */ + printf("Unsupported instruction: MADDU @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x04: /* PLZCW */ + printf("Unsupported instruction: PLZCW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x08: /* MMI0 */ + handle_mmi0(op); + break; + case 0x09: /* MMI2 */ + handle_mmi2(op); + break; + case 0x10: /* MFHI1 */ + if (rd) + m_core->r[rd] = m_core->rh[REG_HI]; + m_core->icount--; + break; + case 0x11: /* MTHI1 */ + printf("Unsupported instruction: MTHI1 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x12: /* MFLO1 */ + if (rd) + m_core->r[rd] = m_core->rh[REG_LO]; + m_core->icount--; + break; + case 0x13: /* MTLO1 */ + printf("Unsupported instruction: MTLO1 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x18: /* MULT1 */ + { + uint64_t temp64 = (int64_t)(int32_t)RSVAL32 * (int64_t)(int32_t)RTVAL32; + m_core->rh[REG_LO] = (int32_t)temp64; + m_core->rh[REG_HI] = (int32_t)(temp64 >> 32); + if (rd) + m_core->r[rd] = m_core->rh[REG_LO]; + m_core->icount -= 3; // ? + break; + } + case 0x19: /* MULTU1 */ + printf("Unsupported instruction: MULTU1 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1a: /* DIV1 */ + if (RTVAL32) + { + m_core->rh[REG_LO] = (int32_t)((int32_t)RSVAL32 / (int32_t)RTVAL32); + m_core->rh[REG_HI] = (int32_t)((int32_t)RSVAL32 % (int32_t)RTVAL32); + } + m_core->icount -= 35; // ? + break; + case 0x1b: /* DIVU1 */ + if (RTVAL32) + { + m_core->rh[REG_LO] = (int32_t)(RSVAL32 / RTVAL32); + m_core->rh[REG_HI] = (int32_t)(RSVAL32 % RTVAL32); + } + m_core->icount -= 35; // ? + break; + case 0x20: /* MADD1 */ + printf("Unsupported instruction: MADD1 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x21: /* MADDU1 */ + printf("Unsupported instruction: MADDU1 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x28: /* MMI1 */ + handle_mmi1(op); + break; + case 0x29: /* MMI3 */ + handle_mmi3(op); + break; + case 0x30: /* PMFHL */ + printf("Unsupported instruction: PMFHL @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x31: /* PMTHL */ + printf("Unsupported instruction: PMTHL @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x34: /* PSLLH */ + printf("Unsupported instruction: PSLLH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x36: /* PSRLH */ + printf("Unsupported instruction: PSRLH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x37: /* PSRAH */ + printf("Unsupported instruction: PSRAH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x3c: /* PSLLW */ + printf("Unsupported instruction: PSLLW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x3e: /* PSRLW */ + printf("Unsupported instruction: PSRLW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x3f: /* PSRAW */ + printf("Unsupported instruction: PSRAW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_mmi0(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rt = (op >> 16) & 31; + const int rd = (op >> 11) & 31; + + switch ((op >> 6) & 0x1f) + { + case 0x00: /* PADDW */ + printf("Unsupported instruction: PADDW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x01: /* PSUBW */ + printf("Unsupported instruction: PSUBW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x02: /* PCGTW */ + printf("Unsupported instruction: PCGTW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x03: /* PMAXW */ + printf("Unsupported instruction: PMAXW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x04: /* PADDH */ + printf("Unsupported instruction: PADDH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x05: /* PSUBH */ + printf("Unsupported instruction: PSUBH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x06: /* PCGTH */ + printf("Unsupported instruction: PCGTH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x07: /* PMAXH */ + printf("Unsupported instruction: PMAXH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x08: /* PADDB */ + printf("Unsupported instruction: PADDB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x09: /* PSUBB */ + printf("Unsupported instruction: PSUBB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0a: /* PCGTB */ + printf("Unsupported instruction: PCGTB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x10: /* PADDSW */ + printf("Unsupported instruction: PADDSW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x11: /* PSUBSW */ + printf("Unsupported instruction: PSUBSW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x12: /* PEXTLW */ + { + if (rd) + { + uint64_t rsval = m_core->r[rs]; + uint64_t rtval = m_core->r[rt]; + uint32_t rdval[4] = { (uint32_t)rtval, (uint32_t)rsval, (uint32_t)(rtval >> 32), (uint32_t)(rsval >> 32) }; + m_core->r[rd] = (uint64_t)rdval[1] << 32 | rdval[0]; + m_core->rh[rd] = (uint64_t)rdval[3] << 32 | rdval[2]; + } + break; + } + case 0x13: /* PPACW */ + printf("Unsupported instruction: PPACW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x14: /* PADDSH */ + printf("Unsupported instruction: PADDSH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x15: /* PSUBSH */ + printf("Unsupported instruction: PSUBSH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x16: /* PEXTLH */ + printf("Unsupported instruction: PEXTLH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x17: /* PPACH */ + printf("Unsupported instruction: PPACH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x18: /* PADDSB */ + printf("Unsupported instruction: PADDSB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x19: /* PSUBSB */ + printf("Unsupported instruction: PSUBSB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1a: /* PEXTLB */ + printf("Unsupported instruction: PEXTLB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1b: /* PPACB */ + printf("Unsupported instruction: PPACB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1e: /* PEXT5 */ + printf("Unsupported instruction: PEXT5 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1f: /* PPAC5 */ + printf("Unsupported instruction: PPAC5 @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_mmi1(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rt = (op >> 16) & 31; + const int rd = (op >> 11) & 31; + + switch ((op >> 6) & 0x1f) + { + case 0x01: /* PABSW */ + printf("Unsupported instruction: PABSW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x02: /* PCEQW */ + printf("Unsupported instruction: PCEQW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x03: /* PMINW */ + printf("Unsupported instruction: PMINW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x04: /* PADSBH */ + printf("Unsupported instruction: PADSBH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x05: /* PABSH */ + printf("Unsupported instruction: PABSH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x06: /* PCEQH */ + printf("Unsupported instruction: PCEQH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x07: /* PMINH */ + printf("Unsupported instruction: PMINH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0a: /* PCEQB */ + printf("Unsupported instruction: PCEQB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x10: /* PADDUW */ + { + if (rd == 0) break; + + uint32_t rsval[4] = { (uint32_t)m_core->r[rs], (uint32_t)(m_core->r[rs] >> 32), (uint32_t)m_core->rh[rs], (uint32_t)(m_core->rh[rs] >> 32) }; + uint32_t rtval[4] = { (uint32_t)m_core->r[rt], (uint32_t)(m_core->r[rt] >> 32), (uint32_t)m_core->rh[rt], (uint32_t)(m_core->rh[rt] >> 32) }; + uint64_t rdval[4] = { 0 }; + + for (int i = 0; i < 4; i++) + { + uint64_t sum = (uint64_t)rsval[i] + (uint64_t)rtval[i]; + rdval[i] = (sum >= 0x100000000ULL) ? 0xffffffffULL : sum; + } + m_core->r[rd] = rdval[0] | (rdval[1] << 32); + m_core->rh[rd] = rdval[2] | (rdval[3] << 32); + m_core->icount -= 1; + break; + } + case 0x11: /* PSUBUW */ + printf("Unsupported instruction: PSUBUW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x12: /* PEXTUW */ + printf("Unsupported instruction: PEXTUW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x14: /* PADDUH */ + printf("Unsupported instruction: PADDUH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x15: /* PSUBUH */ + printf("Unsupported instruction: PSUBUH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x16: /* PEXTUH */ + printf("Unsupported instruction: PEXTUH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x18: /* PADDUB */ + printf("Unsupported instruction: PADDUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x19: /* PSUBUB */ + printf("Unsupported instruction: PSUBUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1a: /* PEXTUB */ + printf("Unsupported instruction: PEXTUB @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1b: /* QFSRV */ + printf("Unsupported instruction: QFSRV @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_mmi2(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rt = (op >> 16) & 31; + const int rd = (op >> 11) & 31; + + switch ((op >> 6) & 0x1f) + { + case 0x00: /* PMADDW */ + printf("Unsupported instruction: PMADDW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x02: /* PSLLVW */ + printf("Unsupported instruction: PSLLVW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x03: /* PSRLVW */ + printf("Unsupported instruction: PSRLVW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x04: /* PMSUBW */ + printf("Unsupported instruction: PMSUBW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x08: /* PMFHI */ + if (rd) + { + m_core->r[rd] = m_core->r[REG_HI]; + m_core->rh[rd] = m_core->rh[REG_HI]; + } + m_core->icount--; + break; + case 0x09: /* PMFLO */ + if (rd) + { + m_core->r[rd] = m_core->r[REG_LO]; + m_core->rh[rd] = m_core->rh[REG_LO]; + } + m_core->icount--; + break; + case 0x0a: /* PINTH */ + printf("Unsupported instruction: PINTH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0c: /* PMULTW */ + printf("Unsupported instruction: PMULTW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0d: /* PDIVW */ + printf("Unsupported instruction: PDIVW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0e: /* PCPYLD */ + if (rd) + { + m_core->rh[rd] = m_core->r[rs]; + m_core->r[rd] = m_core->r[rt]; + } + m_core->icount--; + break; + case 0x10: /* PMADDH */ + printf("Unsupported instruction: PMADDH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x11: /* PHMADH */ + printf("Unsupported instruction: PHMADH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x12: /* PAND */ + printf("Unsupported instruction: PAND @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x13: /* PXOR */ + printf("Unsupported instruction: PXOR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x14: /* PMSUBH */ + printf("Unsupported instruction: PMSUBH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x15: /* PHMSBH */ + printf("Unsupported instruction: PHMSBH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1a: /* PEXEH */ + printf("Unsupported instruction: PEXEH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1b: /* PREVH */ + printf("Unsupported instruction: PREVH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1c: /* PMULTH */ + printf("Unsupported instruction: PMULTH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1d: /* PDIVBW */ + printf("Unsupported instruction: PDIVBW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1e: /* PEXEW */ + printf("Unsupported instruction: PEXEW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1f: /* PROT3W */ + printf("Unsupported instruction: PROT3W @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + +void r5900le_device::handle_mmi3(uint32_t op) +{ + const int rs = (op >> 21) & 31; + const int rt = (op >> 16) & 31; + const int rd = (op >> 11) & 31; + + switch ((op >> 6) & 0x1f) + { + case 0x00: /* PMADDUW */ + printf("Unsupported instruction: PMADDUW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x03: /* PSRAVW */ + printf("Unsupported instruction: PSRAVW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x08: /* PMTHI */ + printf("Unsupported instruction: PMTHI @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x09: /* PTMLO */ + printf("Unsupported instruction: PMTLO @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0a: /* PINTEH */ + printf("Unsupported instruction: PINTEH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0c: /* PMULTUW */ + printf("Unsupported instruction: PMULTUW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0d: /* PDIVUW */ + printf("Unsupported instruction: PDIVUW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x0e: /* PCPYUD */ + if (rd) + { + m_core->rh[rd] = m_core->rh[rs]; + m_core->r[rd] = m_core->rh[rt]; + } + m_core->icount--; + break; + case 0x12: /* POR */ + if (rd) + { + m_core->rh[rd] = m_core->rh[rs] | m_core->rh[rt]; + m_core->r[rd] = m_core->r[rs] | m_core->r[rt]; + } + m_core->icount--; + break; + case 0x13: /* PNOR */ + printf("Unsupported instruction: PNOR @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1a: /* PEXCH */ + printf("Unsupported instruction: PEXCH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1b: /* PCPYH */ + printf("Unsupported instruction: PCPYH @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + case 0x1e: /* PEXCW */ + printf("Unsupported instruction: PEXCW @%08x\n", m_core->pc - 4); fflush(stdout); fatalerror("Unsupported parallel instruction\n"); + break; + default: + invalid_instruction(op); + break; + } +} + +void mips3_device::handle_ldc2(uint32_t op) +{ + uint64_t temp64 = 0; + if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop2_reg(RTREG, temp64); +} + +void mips3_device::handle_sdc2(uint32_t op) +{ + WDOUBLE(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); +} + +void r5900le_device::handle_ldc2(uint32_t op) +{ + /* LQC2 */ + const uint32_t base = SIMMVAL + RSVAL32; + uint32_t *reg = reinterpret_cast<uint32_t*>(m_core->vfr[RTREG]); + for (uint32_t i = 0; i < 4; i++) + { + uint32_t temp = 0; + if (RWORD(base + (i << 2), &temp)) reg[i] = temp; + } +} + +void r5900le_device::handle_sdc2(uint32_t op) +{ + /* SQC2 */ + const uint32_t base = SIMMVAL + RSVAL32; + uint32_t *reg = reinterpret_cast<uint32_t*>(m_core->vfr[RTREG]); + for (uint32_t i = 0; i < 4; i++) + { + WWORD(base + (i << 2), reg[i]); + } } void mips3_device::burn_cycles(int32_t cycles) @@ -2941,7 +4020,7 @@ void mips3_device::execute_run() if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop1_reg64(RTREG, temp64); break; - case 0x36: /* LDC2 */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop2_reg(RTREG, temp64); break; + case 0x36: handle_ldc2(op); break; case 0x37: /* LD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; break; case 0x38: /* SC */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) { @@ -2989,9 +4068,11 @@ void mips3_device::execute_run() } WDOUBLE(SIMMVAL+RSVAL32, get_cop1_reg64(RTREG)); break; - case 0x3e: /* SDC2 */ WDOUBLE(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); break; + case 0x3e: handle_sdc2(op); break; case 0x3f: /* SD */ WDOUBLE(SIMMVAL+RSVAL32, RTVAL64); break; - default: /* ??? */ invalid_instruction(op); break; + default: + handle_extra_base(op); + break; } /* Clear this flag once instruction execution is finished, will interfere with interrupt exceptions otherwise */ m_delayslot = false; diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h index 1e55cd81478..b896235c85a 100644 --- a/src/devices/cpu/mips/mips3.h +++ b/src/devices/cpu/mips/mips3.h @@ -2,10 +2,10 @@ // copyright-holders:Aaron Giles /*************************************************************************** - mips3.h +mips3.h - Interface file for the universal machine language-based - MIPS III/IV emulator. +Interface file for the universal machine language-based +MIPS III/IV emulator. ***************************************************************************/ @@ -21,188 +21,219 @@ // NEC VR4300 series is MIPS III with 32-bit address bus and slightly custom COP0/TLB -DECLARE_DEVICE_TYPE(VR4300BE, vr4300be_device) -DECLARE_DEVICE_TYPE(VR4300LE, vr4300le_device) +DECLARE_DEVICE_TYPE(VR4300BE, vr4300be_device) +DECLARE_DEVICE_TYPE(VR4300LE, vr4300le_device) // VR4310 = VR4300 with different speed bin -DECLARE_DEVICE_TYPE(VR4310BE, vr4310be_device) -DECLARE_DEVICE_TYPE(VR4310LE, vr4310le_device) -DECLARE_DEVICE_TYPE(R4600BE, r4600be_device) -DECLARE_DEVICE_TYPE(R4600LE, r4600le_device) -DECLARE_DEVICE_TYPE(R4650BE, r4650be_device) -DECLARE_DEVICE_TYPE(R4650LE, r4650le_device) -DECLARE_DEVICE_TYPE(R4700BE, r4700be_device) -DECLARE_DEVICE_TYPE(R4700LE, r4700le_device) -DECLARE_DEVICE_TYPE(TX4925BE, tx4925be_device) -DECLARE_DEVICE_TYPE(TX4925LE, tx4925le_device) -DECLARE_DEVICE_TYPE(R5000BE, r5000be_device) -DECLARE_DEVICE_TYPE(R5000LE, r5000le_device) -DECLARE_DEVICE_TYPE(VR5500BE, vr5500be_device) -DECLARE_DEVICE_TYPE(VR5500LE, vr5500le_device) +DECLARE_DEVICE_TYPE(VR4310BE, vr4310be_device) +DECLARE_DEVICE_TYPE(VR4310LE, vr4310le_device) +DECLARE_DEVICE_TYPE(R4600BE, r4600be_device) +DECLARE_DEVICE_TYPE(R4600LE, r4600le_device) +DECLARE_DEVICE_TYPE(R4650BE, r4650be_device) +DECLARE_DEVICE_TYPE(R4650LE, r4650le_device) +DECLARE_DEVICE_TYPE(R4700BE, r4700be_device) +DECLARE_DEVICE_TYPE(R4700LE, r4700le_device) +DECLARE_DEVICE_TYPE(TX4925BE, tx4925be_device) +DECLARE_DEVICE_TYPE(TX4925LE, tx4925le_device) +DECLARE_DEVICE_TYPE(R5000BE, r5000be_device) +DECLARE_DEVICE_TYPE(R5000LE, r5000le_device) +DECLARE_DEVICE_TYPE(VR5500BE, vr5500be_device) +DECLARE_DEVICE_TYPE(VR5500LE, vr5500le_device) DECLARE_DEVICE_TYPE(QED5271BE, qed5271be_device) DECLARE_DEVICE_TYPE(QED5271LE, qed5271le_device) -DECLARE_DEVICE_TYPE(RM7000BE, rm7000be_device) -DECLARE_DEVICE_TYPE(RM7000LE, rm7000le_device) -DECLARE_DEVICE_TYPE(R5900LE, r5900le_device) +DECLARE_DEVICE_TYPE(RM7000BE, rm7000be_device) +DECLARE_DEVICE_TYPE(RM7000LE, rm7000le_device) +DECLARE_DEVICE_TYPE(R5900LE, r5900le_device) /*************************************************************************** - REGISTER ENUMERATION +REGISTER ENUMERATION ***************************************************************************/ -enum -{ - MIPS3_PC = STATE_GENPC, - MIPS3_R0 = 1, - MIPS3_R1, - MIPS3_R2, - MIPS3_R3, - MIPS3_R4, - MIPS3_R5, - MIPS3_R6, - MIPS3_R7, - MIPS3_R8, - MIPS3_R9, - MIPS3_R10, - MIPS3_R11, - MIPS3_R12, - MIPS3_R13, - MIPS3_R14, - MIPS3_R15, - MIPS3_R16, - MIPS3_R17, - MIPS3_R18, - MIPS3_R19, - MIPS3_R20, - MIPS3_R21, - MIPS3_R22, - MIPS3_R23, - MIPS3_R24, - MIPS3_R25, - MIPS3_R26, - MIPS3_R27, - MIPS3_R28, - MIPS3_R29, - MIPS3_R30, - MIPS3_R31, - MIPS3_HI, - MIPS3_LO, - MIPS3_FPR0, - MIPS3_FPS0, - MIPS3_FPD0, - MIPS3_FPR1, - MIPS3_FPS1, - MIPS3_FPD1, - MIPS3_FPR2, - MIPS3_FPS2, - MIPS3_FPD2, - MIPS3_FPR3, - MIPS3_FPS3, - MIPS3_FPD3, - MIPS3_FPR4, - MIPS3_FPS4, - MIPS3_FPD4, - MIPS3_FPR5, - MIPS3_FPS5, - MIPS3_FPD5, - MIPS3_FPR6, - MIPS3_FPS6, - MIPS3_FPD6, - MIPS3_FPR7, - MIPS3_FPS7, - MIPS3_FPD7, - MIPS3_FPR8, - MIPS3_FPS8, - MIPS3_FPD8, - MIPS3_FPR9, - MIPS3_FPS9, - MIPS3_FPD9, - MIPS3_FPR10, - MIPS3_FPS10, - MIPS3_FPD10, - MIPS3_FPR11, - MIPS3_FPS11, - MIPS3_FPD11, - MIPS3_FPR12, - MIPS3_FPS12, - MIPS3_FPD12, - MIPS3_FPR13, - MIPS3_FPS13, - MIPS3_FPD13, - MIPS3_FPR14, - MIPS3_FPS14, - MIPS3_FPD14, - MIPS3_FPR15, - MIPS3_FPS15, - MIPS3_FPD15, - MIPS3_FPR16, - MIPS3_FPS16, - MIPS3_FPD16, - MIPS3_FPR17, - MIPS3_FPS17, - MIPS3_FPD17, - MIPS3_FPR18, - MIPS3_FPS18, - MIPS3_FPD18, - MIPS3_FPR19, - MIPS3_FPS19, - MIPS3_FPD19, - MIPS3_FPR20, - MIPS3_FPS20, - MIPS3_FPD20, - MIPS3_FPR21, - MIPS3_FPS21, - MIPS3_FPD21, - MIPS3_FPR22, - MIPS3_FPS22, - MIPS3_FPD22, - MIPS3_FPR23, - MIPS3_FPS23, - MIPS3_FPD23, - MIPS3_FPR24, - MIPS3_FPS24, - MIPS3_FPD24, - MIPS3_FPR25, - MIPS3_FPS25, - MIPS3_FPD25, - MIPS3_FPR26, - MIPS3_FPS26, - MIPS3_FPD26, - MIPS3_FPR27, - MIPS3_FPS27, - MIPS3_FPD27, - MIPS3_FPR28, - MIPS3_FPS28, - MIPS3_FPD28, - MIPS3_FPR29, - MIPS3_FPS29, - MIPS3_FPD29, - MIPS3_FPR30, - MIPS3_FPS30, - MIPS3_FPD30, - MIPS3_FPR31, - MIPS3_FPS31, - MIPS3_FPD31, - MIPS3_CCR1_31, - MIPS3_SR, - MIPS3_EPC, - MIPS3_CAUSE, - MIPS3_COUNT, - MIPS3_COMPARE, - MIPS3_INDEX, - MIPS3_RANDOM, - MIPS3_ENTRYHI, - MIPS3_ENTRYLO0, - MIPS3_ENTRYLO1, - MIPS3_PAGEMASK, - MIPS3_WIRED, - MIPS3_BADVADDR +enum { + MIPS3_PC = STATE_GENPC, + MIPS3_R0 = 1, + MIPS3_R1, + MIPS3_R2, + MIPS3_R3, + MIPS3_R4, + MIPS3_R5, + MIPS3_R6, + MIPS3_R7, + MIPS3_R8, + MIPS3_R9, + MIPS3_R10, + MIPS3_R11, + MIPS3_R12, + MIPS3_R13, + MIPS3_R14, + MIPS3_R15, + MIPS3_R16, + MIPS3_R17, + MIPS3_R18, + MIPS3_R19, + MIPS3_R20, + MIPS3_R21, + MIPS3_R22, + MIPS3_R23, + MIPS3_R24, + MIPS3_R25, + MIPS3_R26, + MIPS3_R27, + MIPS3_R28, + MIPS3_R29, + MIPS3_R30, + MIPS3_R31, + MIPS3_HI, + MIPS3_LO, + MIPS3_FPR0, + MIPS3_FPS0, + MIPS3_FPD0, + MIPS3_FPR1, + MIPS3_FPS1, + MIPS3_FPD1, + MIPS3_FPR2, + MIPS3_FPS2, + MIPS3_FPD2, + MIPS3_FPR3, + MIPS3_FPS3, + MIPS3_FPD3, + MIPS3_FPR4, + MIPS3_FPS4, + MIPS3_FPD4, + MIPS3_FPR5, + MIPS3_FPS5, + MIPS3_FPD5, + MIPS3_FPR6, + MIPS3_FPS6, + MIPS3_FPD6, + MIPS3_FPR7, + MIPS3_FPS7, + MIPS3_FPD7, + MIPS3_FPR8, + MIPS3_FPS8, + MIPS3_FPD8, + MIPS3_FPR9, + MIPS3_FPS9, + MIPS3_FPD9, + MIPS3_FPR10, + MIPS3_FPS10, + MIPS3_FPD10, + MIPS3_FPR11, + MIPS3_FPS11, + MIPS3_FPD11, + MIPS3_FPR12, + MIPS3_FPS12, + MIPS3_FPD12, + MIPS3_FPR13, + MIPS3_FPS13, + MIPS3_FPD13, + MIPS3_FPR14, + MIPS3_FPS14, + MIPS3_FPD14, + MIPS3_FPR15, + MIPS3_FPS15, + MIPS3_FPD15, + MIPS3_FPR16, + MIPS3_FPS16, + MIPS3_FPD16, + MIPS3_FPR17, + MIPS3_FPS17, + MIPS3_FPD17, + MIPS3_FPR18, + MIPS3_FPS18, + MIPS3_FPD18, + MIPS3_FPR19, + MIPS3_FPS19, + MIPS3_FPD19, + MIPS3_FPR20, + MIPS3_FPS20, + MIPS3_FPD20, + MIPS3_FPR21, + MIPS3_FPS21, + MIPS3_FPD21, + MIPS3_FPR22, + MIPS3_FPS22, + MIPS3_FPD22, + MIPS3_FPR23, + MIPS3_FPS23, + MIPS3_FPD23, + MIPS3_FPR24, + MIPS3_FPS24, + MIPS3_FPD24, + MIPS3_FPR25, + MIPS3_FPS25, + MIPS3_FPD25, + MIPS3_FPR26, + MIPS3_FPS26, + MIPS3_FPD26, + MIPS3_FPR27, + MIPS3_FPS27, + MIPS3_FPD27, + MIPS3_FPR28, + MIPS3_FPS28, + MIPS3_FPD28, + MIPS3_FPR29, + MIPS3_FPS29, + MIPS3_FPD29, + MIPS3_FPR30, + MIPS3_FPS30, + MIPS3_FPD30, + MIPS3_FPR31, + MIPS3_FPS31, + MIPS3_FPD31, + MIPS3_CCR1_31, + MIPS3_SR, + MIPS3_EPC, + MIPS3_CAUSE, + MIPS3_COUNT, + MIPS3_COMPARE, + MIPS3_INDEX, + MIPS3_RANDOM, + MIPS3_ENTRYHI, + MIPS3_ENTRYLO0, + MIPS3_ENTRYLO1, + MIPS3_PAGEMASK, + MIPS3_WIRED, + MIPS3_BADVADDR, + MIPS3_R0H, + MIPS3_R1H, + MIPS3_R2H, + MIPS3_R3H, + MIPS3_R4H, + MIPS3_R5H, + MIPS3_R6H, + MIPS3_R7H, + MIPS3_R8H, + MIPS3_R9H, + MIPS3_R10H, + MIPS3_R11H, + MIPS3_R12H, + MIPS3_R13H, + MIPS3_R14H, + MIPS3_R15H, + MIPS3_R16H, + MIPS3_R17H, + MIPS3_R18H, + MIPS3_R19H, + MIPS3_R20H, + MIPS3_R21H, + MIPS3_R22H, + MIPS3_R23H, + MIPS3_R24H, + MIPS3_R25H, + MIPS3_R26H, + MIPS3_R27H, + MIPS3_R28H, + MIPS3_R29H, + MIPS3_R30H, + MIPS3_R31H, }; #define MIPS3_MAX_FASTRAM 3 #define MIPS3_MAX_HOTSPOTS 16 /*************************************************************************** - INTERRUPT CONSTANTS +INTERRUPT CONSTANTS ***************************************************************************/ #define MIPS3_IRQ0 0 /* IRQ0 */ @@ -215,15 +246,14 @@ enum /*************************************************************************** - STRUCTURES +STRUCTURES ***************************************************************************/ /* MIPS3 TLB entry */ -struct mips3_tlb_entry -{ - uint64_t page_mask; - uint64_t entry_hi; - uint64_t entry_lo[2]; +struct mips3_tlb_entry { + uint64_t page_mask; + uint64_t entry_hi; + uint64_t entry_lo[2]; }; #define MIPS3_MAX_TLB_ENTRIES 48 @@ -240,583 +270,616 @@ struct mips3_tlb_entry class mips3_frontend; -class mips3_device : public cpu_device, public device_vtlb_interface -{ - friend class mips3_frontend; +class mips3_device : public cpu_device, public device_vtlb_interface { + friend class mips3_frontend; protected: - /* MIPS flavors */ - enum mips3_flavor - { - /* MIPS III variants */ - MIPS3_TYPE_MIPS_III, - MIPS3_TYPE_VR4300, - MIPS3_TYPE_R4600, - MIPS3_TYPE_R4650, - MIPS3_TYPE_R4700, - MIPS3_TYPE_TX4925, - - /* MIPS IV variants */ - MIPS3_TYPE_MIPS_IV, - MIPS3_TYPE_R5000, - MIPS3_TYPE_VR5500, - MIPS3_TYPE_QED5271, - MIPS3_TYPE_R5900, - MIPS3_TYPE_RM7000 - }; + /* MIPS flavors */ + enum mips3_flavor { + /* MIPS III variants */ + MIPS3_TYPE_MIPS_III, + MIPS3_TYPE_VR4300, + MIPS3_TYPE_R4600, + MIPS3_TYPE_R4650, + MIPS3_TYPE_R4700, + MIPS3_TYPE_TX4925, + + /* MIPS IV variants */ + MIPS3_TYPE_MIPS_IV, + MIPS3_TYPE_R5000, + MIPS3_TYPE_VR5500, + MIPS3_TYPE_QED5271, + MIPS3_TYPE_R5900, + MIPS3_TYPE_RM7000 + }; public: - // construction/destruction - mips3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, mips3_flavor flavor, endianness_t endiannes); + // construction/destruction + mips3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, mips3_flavor flavor, endianness_t endiannes, uint32_t data_bits); - void set_icache_size(size_t icache_size) { c_icache_size = icache_size; } - void set_dcache_size(size_t dcache_size) { c_dcache_size = dcache_size; } - void set_system_clock(uint32_t system_clock) { c_system_clock = system_clock; } + void set_icache_size(size_t icache_size) { c_icache_size = icache_size; } + void set_dcache_size(size_t dcache_size) { c_dcache_size = dcache_size; } + void set_system_clock(uint32_t system_clock) { c_system_clock = system_clock; } - TIMER_CALLBACK_MEMBER(compare_int_callback); + TIMER_CALLBACK_MEMBER(compare_int_callback); - void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base); - void clear_fastram(uint32_t select_start); - void mips3drc_set_options(uint32_t options); - void mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles); - void burn_cycles(int32_t cycles); + void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base); + void clear_fastram(uint32_t select_start); + void mips3drc_set_options(uint32_t options); + void mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles); + void burn_cycles(int32_t cycles); protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_stop() override; - - // device_execute_interface overrides - virtual uint32_t execute_min_cycles() const override { return 1; } - virtual uint32_t execute_max_cycles() const override { return 40; } - virtual uint32_t execute_input_lines() const override { return 6; } - virtual void execute_run() override; - virtual void execute_set_input(int inputnum, int state) override; - virtual void execute_burn(int32_t cycles) override { m_totalcycles += cycles; } - - // device_memory_interface overrides - virtual space_config_vector memory_space_config() const override; - virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; - - // device_state_interface overrides - virtual void state_export(const device_state_entry &entry) override; - virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; - - // device_disasm_interface overrides - virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; - - void invalid_instruction(uint32_t op); - -private: - struct internal_mips3_state - { - /* core registers */ - uint32_t pc; - int icount; - uint64_t r[35]; - - /* upper 64 bits of 128-bit GPRs (R5900 only) */ - uint64_t rh[35]; - - /* COP registers */ - uint64_t cpr[3][32]; - uint64_t ccr[3][32]; - uint32_t llbit; - - /* VU0 registers (R5900 only) */ - float vfr[32][4]; - uint32_t vcr[32]; - - uint32_t mode; /* current global mode */ - - /* parameters for subroutines */ - uint64_t numcycles; /* return value from gettotalcycles */ - const char * format; /* format string for print_debug */ - uint32_t arg0; /* print_debug argument 1 */ - uint32_t arg1; /* print_debug argument 2 */ - - uint64_t count_zero_time; - uint32_t compare_armed; - uint32_t jmpdest; /* destination jump target */ - }; - - address_space_config m_program_config; - mips3_flavor m_flavor; - - /* core state */ - internal_mips3_state *m_core; - - /* internal stuff */ - uint32_t m_ppc; - uint32_t m_nextpc; - uint32_t m_pcbase; - uint8_t m_cf[4][8]; - bool m_delayslot; - int m_op; - int m_interrupt_cycles; - uint32_t m_ll_value; - uint64_t m_lld_value; - uint32_t m_badcop_value; - - /* endian-dependent load/store */ - typedef void (mips3_device::*loadstore_func)(uint32_t op); - loadstore_func m_lwl; - loadstore_func m_lwr; - loadstore_func m_swl; - loadstore_func m_swr; - loadstore_func m_ldl; - loadstore_func m_ldr; - loadstore_func m_sdl; - loadstore_func m_sdr; - - address_space * m_program; - std::function<u32 (offs_t)> m_pr32; - std::function<const void * (offs_t)> m_prptr; - uint32_t c_system_clock; - uint32_t m_cpu_clock; - emu_timer * m_compare_int_timer; - - /* derived info based on flavor */ - uint32_t m_pfnmask; - uint8_t m_tlbentries; - - /* memory accesses */ - bool m_bigendian; - uint32_t m_byte_xor; - uint32_t m_word_xor; - data_accessors m_memory; - - /* cache memory */ - size_t c_icache_size; - size_t c_dcache_size; - - /* MMU */ - mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES]; - - /* fast RAM */ - uint32_t m_fastram_select; - struct - { - offs_t start; /* start of the RAM block */ - offs_t end; /* end of the RAM block */ - bool readonly; /* true if read-only */ - void * base; /* base in memory where the RAM lives */ - uint8_t * offset_base8; /* base in memory where the RAM lives, 8-bit pointer, with the start offset pre-applied */ - uint16_t * offset_base16; /* base in memory where the RAM lives, 16-bit pointer, with the start offset pre-applied */ - uint32_t * offset_base32; /* base in memory where the RAM lives, 32-bit pointer, with the start offset pre-applied */ - } m_fastram[MIPS3_MAX_FASTRAM]; - - uint32_t m_debugger_temp; - - /* core state */ - drc_cache m_cache; /* pointer to the DRC code cache */ - std::unique_ptr<drcuml_state> m_drcuml;/* DRC UML generator state */ - std::unique_ptr<mips3_frontend> m_drcfe; /* pointer to the DRC front-end state */ - uint32_t m_drcoptions; /* configurable DRC options */ - - /* internal stuff */ - uint8_t m_cache_dirty; /* true if we need to flush the cache */ - - /* tables */ - uint8_t m_fpmode[4]; /* FPU mode table */ - - /* register mappings */ - uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ - uml::parameter m_regmaplo[34]; /* parameter to register mappings for all 32 integer registers */ - - /* subroutines */ - uml::code_handle * m_entry; /* entry point */ - uml::code_handle * m_nocode; /* nocode exception handler */ - uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ - uml::code_handle * m_tlb_mismatch; /* tlb mismatch handler */ - uml::code_handle * m_read8[3]; /* read byte */ - uml::code_handle * m_write8[3]; /* write byte */ - uml::code_handle * m_read16[3]; /* read half */ - uml::code_handle * m_write16[3]; /* write half */ - uml::code_handle * m_read32[3]; /* read word */ - uml::code_handle * m_read32mask[3]; /* read word masked */ - uml::code_handle * m_write32[3]; /* write word */ - uml::code_handle * m_write32mask[3]; /* write word masked */ - uml::code_handle * m_read64[3]; /* read double */ - uml::code_handle * m_read64mask[3]; /* read double masked */ - uml::code_handle * m_write64[3]; /* write double */ - uml::code_handle * m_write64mask[3]; /* write double masked */ - uml::code_handle * m_exception[18/*EXCEPTION_COUNT*/]; /* array of exception handlers */ - uml::code_handle * m_exception_norecover[18/*EXCEPTION_COUNT*/]; /* array of no-recover exception handlers */ - - /* hotspots */ - uint32_t m_hotspot_select; - struct - { - offs_t pc; /* PC to consider */ - uint32_t opcode; /* required opcode at that PC */ - uint32_t cycles; /* number of cycles to eat when hit */ - } m_hotspot[MIPS3_MAX_HOTSPOTS]; - bool m_isdrc; - - - void generate_exception(int exception, int backup); - void generate_tlb_exception(int exception, offs_t address); - void check_irqs(); + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_stop() override; + + // device_execute_interface overrides + virtual uint32_t execute_min_cycles() const override { return 1; } + virtual uint32_t execute_max_cycles() const override { return 40; } + virtual uint32_t execute_input_lines() const override { return 6; } + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override; + virtual void execute_burn(int32_t cycles) override { m_totalcycles += cycles; } + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; + + // device_state_interface overrides + virtual void state_export(const device_state_entry &entry) override; + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + void invalid_instruction(uint32_t op); + + virtual bool RBYTE(offs_t address, uint32_t *result); + virtual bool RHALF(offs_t address, uint32_t *result); + virtual bool RWORD(offs_t address, uint32_t *result); + virtual bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask); + virtual bool RDOUBLE(offs_t address, uint64_t *result); + virtual bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask); + virtual void WBYTE(offs_t address, uint8_t data); + virtual void WHALF(offs_t address, uint16_t data); + virtual void WWORD(offs_t address, uint32_t data); + virtual void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask); + virtual void WDOUBLE(offs_t address, uint64_t data); + virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask); + + struct internal_mips3_state { + /* core registers */ + uint32_t pc; + int icount; + uint64_t r[35]; + uint32_t sa; + + /* upper 64 bits of 128-bit GPRs (R5900 only) */ + uint64_t rh[35]; + + /* COP registers */ + uint64_t cpr[3][32]; + uint64_t ccr[3][32]; + uint32_t llbit; + float acc; + + /* VU0 registers (R5900 only) */ + float vfr[32][4]; + uint32_t vcr[32]; + float vumem[0x1000]; + float* vfmem; + uint32_t* vimem; + + uint32_t mode; /* current global mode */ + + /* parameters for subroutines */ + uint64_t numcycles; /* return value from gettotalcycles */ + const char * format; /* format string for print_debug */ + uint32_t arg0; /* print_debug argument 1 */ + uint32_t arg1; /* print_debug argument 2 */ + + uint64_t count_zero_time; + uint32_t compare_armed; + uint32_t jmpdest; /* destination jump target */ + }; + + /* core state */ + internal_mips3_state *m_core; + + address_space_config m_program_config; + mips3_flavor m_flavor; + + /* internal stuff */ + uint32_t m_ppc; + uint32_t m_nextpc; + uint32_t m_pcbase; + uint8_t m_cf[4][8]; + bool m_delayslot; + int m_op; + int m_interrupt_cycles; + uint32_t m_ll_value; + uint64_t m_lld_value; + uint32_t m_badcop_value; + + /* endian-dependent load/store */ + typedef void (mips3_device::*loadstore_func)(uint32_t op); + loadstore_func m_lwl; + loadstore_func m_lwr; + loadstore_func m_swl; + loadstore_func m_swr; + loadstore_func m_ldl; + loadstore_func m_ldr; + loadstore_func m_sdl; + loadstore_func m_sdr; + + address_space * m_program; + uint32_t m_data_bits; + std::function<u32(offs_t)> m_pr32; + std::function<const void * (offs_t)> m_prptr; + uint32_t c_system_clock; + uint32_t m_cpu_clock; + emu_timer * m_compare_int_timer; + + /* derived info based on flavor */ + uint32_t m_pfnmask; + uint8_t m_tlbentries; + + /* memory accesses */ + bool m_bigendian; + uint32_t m_byte_xor; + uint32_t m_word_xor; + data_accessors m_memory; + + /* cache memory */ + size_t c_icache_size; + size_t c_dcache_size; + + /* MMU */ + mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES]; + + /* fast RAM */ + uint32_t m_fastram_select; + struct { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + bool readonly; /* true if read-only */ + void * base; /* base in memory where the RAM lives */ + uint8_t * offset_base8; /* base in memory where the RAM lives, 8-bit pointer, with the start offset pre-applied */ + uint16_t * offset_base16; /* base in memory where the RAM lives, 16-bit pointer, with the start offset pre-applied */ + uint32_t * offset_base32; /* base in memory where the RAM lives, 32-bit pointer, with the start offset pre-applied */ + } m_fastram[MIPS3_MAX_FASTRAM]; + + uint32_t m_debugger_temp; + + /* core state */ + drc_cache m_cache; /* pointer to the DRC code cache */ + std::unique_ptr<drcuml_state> m_drcuml;/* DRC UML generator state */ + std::unique_ptr<mips3_frontend> m_drcfe; /* pointer to the DRC front-end state */ + uint32_t m_drcoptions; /* configurable DRC options */ + + /* internal stuff */ + uint8_t m_cache_dirty; /* true if we need to flush the cache */ + + /* tables */ + uint8_t m_fpmode[4]; /* FPU mode table */ + + /* register mappings */ + uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ + uml::parameter m_regmaplo[34]; /* parameter to register mappings for all 32 integer registers */ + + /* subroutines */ + uml::code_handle * m_entry; /* entry point */ + uml::code_handle * m_nocode; /* nocode exception handler */ + uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ + uml::code_handle * m_tlb_mismatch; /* tlb mismatch handler */ + uml::code_handle * m_read8[3]; /* read byte */ + uml::code_handle * m_write8[3]; /* write byte */ + uml::code_handle * m_read16[3]; /* read half */ + uml::code_handle * m_write16[3]; /* write half */ + uml::code_handle * m_read32[3]; /* read word */ + uml::code_handle * m_read32mask[3]; /* read word masked */ + uml::code_handle * m_write32[3]; /* write word */ + uml::code_handle * m_write32mask[3]; /* write word masked */ + uml::code_handle * m_read64[3]; /* read double */ + uml::code_handle * m_read64mask[3]; /* read double masked */ + uml::code_handle * m_write64[3]; /* write double */ + uml::code_handle * m_write64mask[3]; /* write double masked */ + uml::code_handle * m_exception[18/*EXCEPTION_COUNT*/]; /* array of exception handlers */ + uml::code_handle * m_exception_norecover[18/*EXCEPTION_COUNT*/]; /* array of no-recover exception handlers */ + + /* hotspots */ + uint32_t m_hotspot_select; + struct { + offs_t pc; /* PC to consider */ + uint32_t opcode; /* required opcode at that PC */ + uint32_t cycles; /* number of cycles to eat when hit */ + } m_hotspot[MIPS3_MAX_HOTSPOTS]; + bool m_isdrc; + + + void generate_exception(int exception, int backup); + void generate_tlb_exception(int exception, offs_t address); + void check_irqs(); public: - void mips3com_update_cycle_counting(); - void mips3com_asid_changed(); - void mips3com_tlbr(); - void mips3com_tlbwi(); - void mips3com_tlbwr(); - void mips3com_tlbp(); + void mips3com_update_cycle_counting(); + void mips3com_asid_changed(); + void mips3com_tlbr(); + void mips3com_tlbwi(); + void mips3com_tlbwr(); + void mips3com_tlbp(); private: - uint32_t compute_config_register(); - uint32_t compute_prid_register(); - - void tlb_map_entry(int tlbindex); - void tlb_write_common(int tlbindex); - - bool RBYTE(offs_t address, uint32_t *result); - bool RHALF(offs_t address, uint32_t *result); - bool RWORD(offs_t address, uint32_t *result); - bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask); - bool RDOUBLE(offs_t address, uint64_t *result); - bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask); - void WBYTE(offs_t address, uint8_t data); - void WHALF(offs_t address, uint16_t data); - void WWORD(offs_t address, uint32_t data); - void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask); - void WDOUBLE(offs_t address, uint64_t data); - void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask); - - uint64_t get_cop0_reg(int idx); - void set_cop0_reg(int idx, uint64_t val); - uint64_t get_cop0_creg(int idx); - void set_cop0_creg(int idx, uint64_t val); - void handle_cop0(uint32_t op); - - uint32_t get_cop1_reg32(int idx); - uint64_t get_cop1_reg64(int idx); - void set_cop1_reg32(int idx, uint32_t val); - void set_cop1_reg64(int idx, uint64_t val); - uint64_t get_cop1_creg(int idx); - void set_cop1_creg(int idx, uint64_t val); - void handle_cop1_fr0(uint32_t op); - void handle_cop1_fr1(uint32_t op); - void handle_cop1x_fr0(uint32_t op); - void handle_cop1x_fr1(uint32_t op); - - uint64_t get_cop2_reg(int idx); - void set_cop2_reg(int idx, uint64_t val); - uint64_t get_cop2_creg(int idx); - void set_cop2_creg(int idx, uint64_t val); - void handle_cop2(uint32_t op); - - void handle_special(uint32_t op); - void handle_regimm(uint32_t op); - virtual void handle_extra_special(uint32_t op); - virtual void handle_extra_regimm(uint32_t op); - virtual void handle_extra_cop2(uint32_t op); - virtual void handle_idt(uint32_t op); - - void lwl_be(uint32_t op); - void lwr_be(uint32_t op); - void ldl_be(uint32_t op); - void ldr_be(uint32_t op); - void swl_be(uint32_t op); - void swr_be(uint32_t op); - void sdl_be(uint32_t op); - void sdr_be(uint32_t op); - void lwl_le(uint32_t op); - void lwr_le(uint32_t op); - void ldl_le(uint32_t op); - void ldr_le(uint32_t op); - void swl_le(uint32_t op); - void swr_le(uint32_t op); - void sdl_le(uint32_t op); - void sdr_le(uint32_t op); - void load_fast_iregs(drcuml_block &block); - void save_fast_iregs(drcuml_block &block); - void code_flush_cache(); - void code_compile_block(uint8_t mode, offs_t pc); + uint32_t compute_config_register(); + uint32_t compute_prid_register(); + + void tlb_map_entry(int tlbindex); + void tlb_write_common(int tlbindex); + + uint64_t get_cop0_reg(int idx); + void set_cop0_reg(int idx, uint64_t val); + uint64_t get_cop0_creg(int idx); + void set_cop0_creg(int idx, uint64_t val); + void handle_cop0(uint32_t op); + + uint32_t get_cop1_reg32(int idx); + uint64_t get_cop1_reg64(int idx); + void set_cop1_reg32(int idx, uint32_t val); + void set_cop1_reg64(int idx, uint64_t val); + uint64_t get_cop1_creg(int idx); + void set_cop1_creg(int idx, uint64_t val); + void handle_cop1_fr0(uint32_t op); + void handle_cop1_fr1(uint32_t op); + void handle_cop1x_fr0(uint32_t op); + void handle_cop1x_fr1(uint32_t op); + + virtual uint64_t get_cop2_reg(int idx); + virtual void set_cop2_reg(int idx, uint64_t val); + virtual uint64_t get_cop2_creg(int idx); + virtual void set_cop2_creg(int idx, uint64_t val); + void handle_cop2(uint32_t op); + + void handle_special(uint32_t op); + void handle_regimm(uint32_t op); + virtual void handle_extra_base(uint32_t op); + virtual void handle_extra_special(uint32_t op); + virtual void handle_extra_regimm(uint32_t op); + virtual void handle_extra_cop2(uint32_t op); + virtual void handle_idt(uint32_t op); + virtual void handle_ldc2(uint32_t op); + virtual void handle_sdc2(uint32_t op); + virtual void handle_dmfc2(uint32_t op); + virtual void handle_dmtc2(uint32_t op); + + void lwl_be(uint32_t op); + void lwr_be(uint32_t op); + void ldl_be(uint32_t op); + void ldr_be(uint32_t op); + void swl_be(uint32_t op); + void swr_be(uint32_t op); + void sdl_be(uint32_t op); + void sdr_be(uint32_t op); + void lwl_le(uint32_t op); + void lwr_le(uint32_t op); + void ldl_le(uint32_t op); + void ldr_le(uint32_t op); + void swl_le(uint32_t op); + void swr_le(uint32_t op); + void sdl_le(uint32_t op); + void sdr_le(uint32_t op); + void load_fast_iregs(drcuml_block &block); + void save_fast_iregs(drcuml_block &block); + void code_flush_cache(); + void code_compile_block(uint8_t mode, offs_t pc); public: - void func_get_cycles(); - void func_printf_exception(); - void func_printf_debug(); - void func_printf_probe(); - void func_unimplemented(); + void func_get_cycles(); + void func_printf_exception(); + void func_printf_debug(); + void func_printf_probe(); + void func_unimplemented(); private: - /* internal compiler state */ - struct compiler_state - { - compiler_state &operator=(compiler_state &) = delete; - - uint32_t cycles; /* accumulated cycles */ - uint8_t checkints; /* need to check interrupts before next instruction */ - uint8_t checksoftints; /* need to check software interrupts before next instruction */ - uml::code_label labelnum; /* index for local labels */ - }; - - void static_generate_entry_point(); - void static_generate_nocode_handler(); - void static_generate_out_of_cycles(); - void static_generate_tlb_mismatch(); - void static_generate_exception(uint8_t exception, int recover, const char *name); - void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr); - - void generate_update_mode(drcuml_block &block); - void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception); - void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); - void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg); - - bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_idt(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - - bool generate_set_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg); - bool generate_get_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg); - bool generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_cop1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_cop1x(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - - void check_cop0_access(drcuml_block &block); - void check_cop1_access(drcuml_block &block); - void generate_badcop(drcuml_block &block, const int cop); - - void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op); - const char *log_desc_flags_to_string(uint32_t flags); - void log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist); - void log_opcode_desc(const opcode_desc *desclist, int indent); + /* internal compiler state */ + struct compiler_state { + compiler_state &operator=(compiler_state &) = delete; + + uint32_t cycles; /* accumulated cycles */ + uint8_t checkints; /* need to check interrupts before next instruction */ + uint8_t checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_tlb_mismatch(); + void static_generate_exception(uint8_t exception, int recover, const char *name); + void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr); + + void generate_update_mode(drcuml_block &block); + void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception); + void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg); + + bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + bool generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + bool generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + bool generate_idt(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + + bool generate_set_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg); + bool generate_get_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg); + bool generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + bool generate_cop1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + bool generate_cop1x(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); + + void check_cop0_access(drcuml_block &block); + void check_cop1_access(drcuml_block &block); + void generate_badcop(drcuml_block &block, const int cop); + + void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op); + const char *log_desc_flags_to_string(uint32_t flags); + void log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist); + void log_opcode_desc(const opcode_desc *desclist, int indent); }; -class vr4300be_device : public mips3_device -{ +class vr4300be_device : public mips3_device { public: - // construction/destruction - vr4300be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR4300BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG) - { } + // construction/destruction + vr4300be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR4300BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG, 32) // checkme + { + } }; -class vr4300le_device : public mips3_device -{ +class vr4300le_device : public mips3_device { public: - // construction/destruction - vr4300le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR4300LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE) - { } + // construction/destruction + vr4300le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR4300LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class vr4310be_device : public mips3_device -{ +class vr4310be_device : public mips3_device { public: - // construction/destruction - vr4310be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR4310BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG) - { } + // construction/destruction + vr4310be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR4310BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG, 32) // checkme + { + } }; -class vr4310le_device : public mips3_device -{ +class vr4310le_device : public mips3_device { public: - // construction/destruction - vr4310le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR4310LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE) - { } + // construction/destruction + vr4310le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR4310LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class r4600be_device : public mips3_device -{ +class r4600be_device : public mips3_device { public: - // construction/destruction - r4600be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4600BE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_BIG) - { } + // construction/destruction + r4600be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4600BE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_BIG, 32) // checkme + { + } }; -class r4600le_device : public mips3_device -{ +class r4600le_device : public mips3_device { public: - // construction/destruction - r4600le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4600LE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_LITTLE) - { } + // construction/destruction + r4600le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4600LE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class r4650be_device : public mips3_device -{ +class r4650be_device : public mips3_device { public: - // construction/destruction - r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4650BE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_BIG) - { } + // construction/destruction + r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4650BE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_BIG, 32) // checkme + { + } }; -class r4650le_device : public mips3_device -{ +class r4650le_device : public mips3_device { public: - // construction/destruction - r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4650LE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_LITTLE) - { } + // construction/destruction + r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4650LE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class r4700be_device : public mips3_device -{ +class r4700be_device : public mips3_device { public: - // construction/destruction - r4700be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4700BE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_BIG) - { } + // construction/destruction + r4700be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4700BE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_BIG, 32) // checkme + { + } }; -class r4700le_device : public mips3_device -{ +class r4700le_device : public mips3_device { public: - // construction/destruction - r4700le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R4700LE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_LITTLE) - { } + // construction/destruction + r4700le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R4700LE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class tx4925be_device : public mips3_device -{ +class tx4925be_device : public mips3_device { public: - // construction/destruction - tx4925be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, TX4925BE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_BIG) - { } + // construction/destruction + tx4925be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, TX4925BE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_BIG, 32) // checkme + { + } }; -class tx4925le_device : public mips3_device -{ +class tx4925le_device : public mips3_device { public: - // construction/destruction - tx4925le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, TX4925LE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_LITTLE) - { } + // construction/destruction + tx4925le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, TX4925LE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class r5000be_device : public mips3_device -{ +class r5000be_device : public mips3_device { public: - // construction/destruction - r5000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R5000BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG) - { } + // construction/destruction + r5000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R5000BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG, 32) // checkme + { + } }; -class r5000le_device : public mips3_device -{ +class r5000le_device : public mips3_device { public: - // construction/destruction - r5000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R5000LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE) - { } + // construction/destruction + r5000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R5000LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class vr5500be_device : public mips3_device -{ +class vr5500be_device : public mips3_device { public: - // construction/destruction - vr5500be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR5500BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG) - { } + // construction/destruction + vr5500be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR5500BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG, 32) { + } }; -class vr5500le_device : public mips3_device -{ +class vr5500le_device : public mips3_device { public: - // construction/destruction - vr5500le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, VR5500LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE) - { } + // construction/destruction + vr5500le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, VR5500LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class r5900le_device : public mips3_device -{ +class r5900le_device : public mips3_device { public: - // construction/destruction - r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, R5900LE, tag, owner, clock, MIPS3_TYPE_R5900, ENDIANNESS_LITTLE) - { } + // construction/destruction + r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, R5900LE, tag, owner, clock, MIPS3_TYPE_R5900, ENDIANNESS_LITTLE, 64) { + } protected: - // device_disasm_interface overrides - virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + virtual void device_start() override; - void handle_extra_special(uint32_t op) override; - void handle_extra_regimm(uint32_t op) override; - void handle_extra_cop2(uint32_t op) override; - void handle_idt(uint32_t op) override; + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + bool RBYTE(offs_t address, uint32_t *result) override; + bool RHALF(offs_t address, uint32_t *result) override; + bool RWORD(offs_t address, uint32_t *result) override; + bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask) override; + bool RDOUBLE(offs_t address, uint64_t *result) override; + bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask) override; + void WBYTE(offs_t address, uint8_t data) override; + void WHALF(offs_t address, uint16_t data) override; + void WWORD(offs_t address, uint32_t data) override; + void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask) override; + void WDOUBLE(offs_t address, uint64_t data) override; + void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) override; + + bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo); + void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo); + + uint64_t get_cop2_reg(int idx) override; + void set_cop2_reg(int idx, uint64_t val) override; + uint64_t get_cop2_creg(int idx) override; + void set_cop2_creg(int idx, uint64_t val) override; + + void handle_extra_base(uint32_t op) override; + void handle_extra_special(uint32_t op) override; + void handle_extra_regimm(uint32_t op) override; + void handle_extra_cop2(uint32_t op) override; + void handle_idt(uint32_t op) override; + void handle_mmi0(uint32_t op); + void handle_mmi1(uint32_t op); + void handle_mmi2(uint32_t op); + void handle_mmi3(uint32_t op); + void handle_ldc2(uint32_t op) override; + void handle_sdc2(uint32_t op) override; + void handle_dmfc2(uint32_t op) override; + void handle_dmtc2(uint32_t op) override; }; -class qed5271be_device : public mips3_device -{ +class qed5271be_device : public mips3_device { public: - // construction/destruction - qed5271be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, QED5271BE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_BIG) - { } + // construction/destruction + qed5271be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, QED5271BE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_BIG, 32) // checkme + { + } }; -class qed5271le_device : public mips3_device -{ +class qed5271le_device : public mips3_device { public: - // construction/destruction - qed5271le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, QED5271LE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_LITTLE) - { } + // construction/destruction + qed5271le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, QED5271LE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class rm7000be_device : public mips3_device -{ +class rm7000be_device : public mips3_device { public: - // construction/destruction - rm7000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, RM7000BE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_BIG) - { } + // construction/destruction + rm7000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, RM7000BE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_BIG, 32) // checkme + { + } }; -class rm7000le_device : public mips3_device -{ +class rm7000le_device : public mips3_device { public: - // construction/destruction - rm7000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : mips3_device(mconfig, RM7000LE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_LITTLE) - { } + // construction/destruction + rm7000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mips3_device(mconfig, RM7000LE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_LITTLE, 32) // checkme + { + } }; -class mips3_frontend : public drc_frontend -{ +class mips3_frontend : public drc_frontend { public: - // construction/destruction - mips3_frontend(mips3_device *mips3, uint32_t window_start, uint32_t window_end, uint32_t max_sequence); + // construction/destruction + mips3_frontend(mips3_device *mips3, uint32_t window_start, uint32_t window_end, uint32_t max_sequence); protected: - // required overrides - virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override; + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override; private: - // internal helpers - bool describe_special(uint32_t op, opcode_desc &desc); - bool describe_regimm(uint32_t op, opcode_desc &desc); - bool describe_idt(uint32_t op, opcode_desc &desc); - bool describe_cop0(uint32_t op, opcode_desc &desc); - bool describe_cop1(uint32_t op, opcode_desc &desc); - bool describe_cop1x(uint32_t op, opcode_desc &desc); - bool describe_cop2(uint32_t op, opcode_desc &desc); - - // internal state - mips3_device *m_mips3; + // internal helpers + bool describe_special(uint32_t op, opcode_desc &desc); + bool describe_regimm(uint32_t op, opcode_desc &desc); + bool describe_idt(uint32_t op, opcode_desc &desc); + bool describe_cop0(uint32_t op, opcode_desc &desc); + bool describe_cop1(uint32_t op, opcode_desc &desc); + bool describe_cop1x(uint32_t op, opcode_desc &desc); + bool describe_cop2(uint32_t op, opcode_desc &desc); + + // internal state + mips3_device *m_mips3; }; /*************************************************************************** - COMPILER-SPECIFIC OPTIONS +COMPILER-SPECIFIC OPTIONS ***************************************************************************/ /* fix me -- how do we make this work?? */ diff --git a/src/devices/cpu/mips/mips3com.cpp b/src/devices/cpu/mips/mips3com.cpp index 9edd05f8b67..8b8accf8c4c 100644 --- a/src/devices/cpu/mips/mips3com.cpp +++ b/src/devices/cpu/mips/mips3com.cpp @@ -366,7 +366,11 @@ void mips3_device::tlb_map_entry(int tlbindex) } /* get the number of pages from the page mask */ - count = ((entry->page_mask >> 13) & 0x00fff) + 1; + /* R5900: if the S bit is set in EntryLo, it is the scratchpad, and is always 4 pages. */ + if ((entry->entry_lo[0] & 0x80000000) && m_flavor == MIPS3_TYPE_R5900) + count = 4; + else + count = ((entry->page_mask >> 13) & 0x00fff) + 1; /* loop over both the even and odd pages */ for (which = 0; which < 2; which++) diff --git a/src/devices/cpu/mips/mips3com.h b/src/devices/cpu/mips/mips3com.h index befde0cf60c..9365deff603 100644 --- a/src/devices/cpu/mips/mips3com.h +++ b/src/devices/cpu/mips/mips3com.h @@ -72,8 +72,8 @@ #define MIPS3_MAX_PADDR_SHIFT 32 /* cycle parameters */ -#define MIPS3_COUNT_READ_CYCLES 250 -#define MIPS3_CAUSE_READ_CYCLES 250 +#define MIPS3_COUNT_READ_CYCLES 1 +#define MIPS3_CAUSE_READ_CYCLES 1 /* TLB bits */ #define TLB_GLOBAL 0x01 diff --git a/src/devices/cpu/mips/mips3dsm.cpp b/src/devices/cpu/mips/mips3dsm.cpp index 0ee0bd36058..c93e8166344 100644 --- a/src/devices/cpu/mips/mips3dsm.cpp +++ b/src/devices/cpu/mips/mips3dsm.cpp @@ -799,11 +799,13 @@ uint32_t ee_disassembler::dasm_extra_base(uint32_t pc, uint32_t op, std::ostream uint32_t ee_disassembler::dasm_extra_special(uint32_t pc, uint32_t op, std::ostream &stream) { const int rs = (op >> 21) & 31; + const int rd = (op >> 11) & 31; switch (op & 63) { - case 0x29: util::stream_format(stream, "mtsa %s", reg[rs]); break; - default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break; + case 0x28: util::stream_format(stream, "mfsa %s", reg[rd]); break; + case 0x29: util::stream_format(stream, "mtsa %s", reg[rs]); break; + default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break; } return 0; } diff --git a/src/devices/cpu/mips/r3000.cpp b/src/devices/cpu/mips/r3000.cpp index 1cf74b4bff4..4a15b1f60a6 100644 --- a/src/devices/cpu/mips/r3000.cpp +++ b/src/devices/cpu/mips/r3000.cpp @@ -114,11 +114,12 @@ // DEVICE INTERFACE //************************************************************************** -DEFINE_DEVICE_TYPE(R3041, r3041_device, "r3041", "MIPS R3041") -DEFINE_DEVICE_TYPE(R3051, r3051_device, "r3051", "MIPS R3051") -DEFINE_DEVICE_TYPE(R3052, r3052_device, "r3052", "MIPS R3052") -DEFINE_DEVICE_TYPE(R3071, r3071_device, "r3071", "MIPS R3071") -DEFINE_DEVICE_TYPE(R3081, r3081_device, "r3081", "MIPS R3081") +DEFINE_DEVICE_TYPE(R3041, r3041_device, "r3041", "MIPS R3041") +DEFINE_DEVICE_TYPE(R3051, r3051_device, "r3051", "MIPS R3051") +DEFINE_DEVICE_TYPE(R3052, r3052_device, "r3052", "MIPS R3052") +DEFINE_DEVICE_TYPE(R3071, r3071_device, "r3071", "MIPS R3071") +DEFINE_DEVICE_TYPE(R3081, r3081_device, "r3081", "MIPS R3081") +DEFINE_DEVICE_TYPE(SONYPS2_IOP, iop_device, "sonyiop", "Sony Playstation 2 IOP") //------------------------------------------------- @@ -206,6 +207,14 @@ r3081_device::r3081_device(const machine_config &mconfig, const char *tag, devic //------------------------------------------------- +// iop_device - constructor +//------------------------------------------------- + +iop_device::iop_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : r3000_device(mconfig, SONYPS2_IOP, tag, owner, clock, CHIP_TYPE_IOP) { } + + +//------------------------------------------------- // device_start - start up the device //------------------------------------------------- @@ -262,6 +271,12 @@ void r3000_device::device_start() m_hasfpu = true; break; } + case CHIP_TYPE_IOP: + { + m_icache_size = 4096; + m_dcache_size = 1024; + break; + } } // allocate cache memory @@ -398,6 +413,12 @@ void r3000_device::device_reset() m_cpr[0][COP0_Status] = 0x0000; } +void iop_device::device_reset() +{ + r3000_device::device_reset(); + m_cpr[0][COP0_PRId] = 0x2; +} + //------------------------------------------------- // memory_space_config - return the configuration diff --git a/src/devices/cpu/mips/r3000.h b/src/devices/cpu/mips/r3000.h index 0abea62316d..64537788aa5 100644 --- a/src/devices/cpu/mips/r3000.h +++ b/src/devices/cpu/mips/r3000.h @@ -87,7 +87,8 @@ protected: CHIP_TYPE_R3051, CHIP_TYPE_R3052, CHIP_TYPE_R3071, - CHIP_TYPE_R3081 + CHIP_TYPE_R3081, + CHIP_TYPE_IOP }; r3000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, chip_type chiptype); @@ -291,12 +292,25 @@ public: }; +// ======================> iop_device + +class iop_device : public r3000_device +{ +public: + iop_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_reset() override; +}; + + // device type definition -DECLARE_DEVICE_TYPE(R3041, r3041_device) -DECLARE_DEVICE_TYPE(R3051, r3051_device) -DECLARE_DEVICE_TYPE(R3052, r3052_device) -DECLARE_DEVICE_TYPE(R3071, r3071_device) -DECLARE_DEVICE_TYPE(R3081, r3081_device) +DECLARE_DEVICE_TYPE(R3041, r3041_device) +DECLARE_DEVICE_TYPE(R3051, r3051_device) +DECLARE_DEVICE_TYPE(R3052, r3052_device) +DECLARE_DEVICE_TYPE(R3071, r3071_device) +DECLARE_DEVICE_TYPE(R3081, r3081_device) +DECLARE_DEVICE_TYPE(SONYPS2_IOP, iop_device) #endif // MAME_CPU_MIPS_R3000_H diff --git a/src/devices/machine/wd33c93.cpp b/src/devices/machine/wd33c93.cpp index 401e2666765..ec9c8017434 100644 --- a/src/devices/machine/wd33c93.cpp +++ b/src/devices/machine/wd33c93.cpp @@ -16,7 +16,7 @@ #include "emu.h" #include "wd33c93.h" -//#define VERBOSE 1 +#define VERBOSE 1 #include "logmacro.h" diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp index 0689bb9c68a..d6cc8b34e21 100644 --- a/src/emu/divtlb.cpp +++ b/src/emu/divtlb.cpp @@ -91,9 +91,11 @@ void device_vtlb_interface::interface_pre_start() memset(&m_live[0], 0, m_live.size()*sizeof(m_live[0])); // allocate the lookup table - m_table.resize((size_t) 1 << (m_addrwidth - m_pageshift)); - memset(&m_table[0], 0, m_table.size()*sizeof(m_table[0])); - // pointer to first element for quick access + m_table.resize((size_t)1 << (m_addrwidth - m_pageshift)); + memset(&m_table[0], 0, m_table.size() * sizeof(m_table[0])); + m_refcnt.resize((size_t)1 << (m_addrwidth - m_pageshift)); + memset(&m_refcnt[0], 0, m_refcnt.size() * sizeof(m_refcnt[0])); + // pointer to first element for quick access m_table_base = &m_table[0]; // allocate the fixed page count array @@ -114,6 +116,7 @@ void device_vtlb_interface::interface_post_start() { device().save_item(NAME(m_live)); device().save_item(NAME(m_table)); + device().save_item(NAME(m_refcnt)); if (m_fixed > 0) device().save_item(NAME(m_fixedpages)); } @@ -177,8 +180,9 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) int liveindex = m_dynindex++ % m_dynamic; // if an entry already exists at this index, free it - if (m_live[liveindex] != 0) + if (m_live[liveindex] != 0 && m_refcnt[m_live[liveindex] - 1] <= 1) m_table[m_live[liveindex] - 1] = 0; + m_refcnt[m_live[liveindex] - 1]--; // claim this new entry m_live[liveindex] = tableindex + 1; @@ -230,14 +234,19 @@ void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address // if an entry already exists at this index, free it if (m_live[liveindex] != 0) { - int pagecount = m_fixedpages[entrynum]; int oldtableindex = m_live[liveindex] - 1; - for (pagenum = 0; pagenum < pagecount; pagenum++) - m_table[oldtableindex + pagenum] = 0; + m_refcnt[oldtableindex]--; + if (m_refcnt[oldtableindex] == 0) { + int pagecount = m_fixedpages[entrynum]; + for (pagenum = 0; pagenum < pagecount; pagenum++) { + m_table[oldtableindex + pagenum] = 0; + } + } } // claim this new entry m_live[liveindex] = tableindex + 1; + m_refcnt[tableindex]++; // store the raw value, making sure the "fixed" flag is set value |= VTLB_FLAG_FIXED; diff --git a/src/emu/divtlb.h b/src/emu/divtlb.h index 3acfec4f215..03ee4d1ed84 100644 --- a/src/emu/divtlb.h +++ b/src/emu/divtlb.h @@ -83,6 +83,7 @@ private: std::vector<offs_t> m_live; // array of live entries by table index std::vector<int> m_fixedpages; // number of pages each fixed entry covers std::vector<vtlb_entry> m_table; // table of entries by address + std::vector<offs_t> m_refcnt; // table of entry reference counts by address vtlb_entry *m_table_base; // pointer to m_table[0] }; diff --git a/src/mame/drivers/ps2sony.cpp b/src/mame/drivers/ps2sony.cpp index e13fcffeb0d..4b36effbf38 100644 --- a/src/mame/drivers/ps2sony.cpp +++ b/src/mame/drivers/ps2sony.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders: +// copyright-holders:Ryan Holtz /********************************************************************************************************************** 2017-11-05 Skeleton PLACEHOLDER ONLY. @@ -158,30 +158,1006 @@ iLinkSGUID=0x-------- #include "emu.h" #include "cpu/mips/mips3.h" #include "cpu/mips/r3000.h" +#include "machine/ps2timer.h" #include "emupal.h" #include "screen.h" - class ps2sony_state : public driver_device { public: ps2sony_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_timer(*this, "timer%u", 0U) + , m_screen(*this, "screen") + , m_iop_ram(*this, "iop_ram") + , m_sp_ram(*this, "sp_ram") + , m_vu0_imem(*this, "vu0imem") + , m_vu0_dmem(*this, "vu0dmem") + , m_vu1_imem(*this, "vu1imem") + , m_vu1_dmem(*this, "vu1dmem") + , m_vblank_timer(nullptr) { } - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void ps2sony(machine_config &config); - void mem_map(address_map &map); -private: - virtual void video_start() override; - required_device<cpu_device> m_maincpu; + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + TIMER_CALLBACK_MEMBER(vblank); + + DECLARE_READ64_MEMBER(gs_regs0_r); + DECLARE_WRITE64_MEMBER(gs_regs0_w); + DECLARE_READ64_MEMBER(gs_regs1_r); + DECLARE_WRITE64_MEMBER(gs_regs1_w); + + DECLARE_READ32_MEMBER(ipu_r); + DECLARE_WRITE32_MEMBER(ipu_w); + DECLARE_READ64_MEMBER(vif0_fifo_r); + DECLARE_WRITE64_MEMBER(vif0_fifo_w); + DECLARE_READ64_MEMBER(vif1_fifo_r); + DECLARE_WRITE64_MEMBER(vif1_fifo_w); + DECLARE_READ64_MEMBER(gif_fifo_r); + DECLARE_WRITE64_MEMBER(gif_fifo_w); + DECLARE_READ64_MEMBER(ipu_fifo_r); + DECLARE_WRITE64_MEMBER(ipu_fifo_w); + DECLARE_READ32_MEMBER(dmac_channel_r); + DECLARE_WRITE32_MEMBER(dmac_channel_w); + DECLARE_READ32_MEMBER(dmac_r); + DECLARE_WRITE32_MEMBER(dmac_w); + DECLARE_READ32_MEMBER(intc_r); + DECLARE_WRITE32_MEMBER(intc_w); + DECLARE_READ32_MEMBER(sif_smflg_r); + DECLARE_WRITE32_MEMBER(sif_smflg_w); + DECLARE_WRITE8_MEMBER(debug_w); + DECLARE_READ32_MEMBER(unk_f430_r); + DECLARE_WRITE32_MEMBER(unk_f430_w); + DECLARE_READ32_MEMBER(unk_f440_r); + DECLARE_WRITE32_MEMBER(unk_f440_w); + DECLARE_READ32_MEMBER(unk_f520_r); + + void check_irq0(); + void raise_interrupt(int line); + + void mem_map(address_map &map); + void iop_map(address_map &map); + + required_device<cpu_device> m_maincpu; + required_device_array<ps2_timer_device, 4> m_timer; + required_device<screen_device> m_screen; + required_shared_ptr<uint64_t> m_iop_ram; + required_shared_ptr<uint64_t> m_sp_ram; + required_shared_ptr<uint64_t> m_vu0_imem; + required_shared_ptr<uint64_t> m_vu0_dmem; + required_shared_ptr<uint64_t> m_vu1_imem; + required_shared_ptr<uint64_t> m_vu1_dmem; + + uint64_t m_gs_base_regs[15]; + uint64_t m_gs_csr; + uint64_t m_gs_imr; + uint64_t m_gs_busdir; + uint64_t m_gs_sig_label_id; + + uint32_t m_unk_f430_reg; + uint32_t m_unk_f440_counter; + uint32_t m_unk_f440_reg; + uint32_t m_unk_f440_ret; + + uint32_t m_ipu_ctrl; + uint64_t m_ipu_in_fifo[0x1000]; + uint64_t m_ipu_in_fifo_index; + uint64_t m_ipu_out_fifo[0x1000]; + uint64_t m_ipu_out_fifo_index; + + enum + { + INT_GS = 0, + INT_SBUS, + INT_VB_ON, + INT_VB_OFF, + INT_VIF0, + INT_VIF1, + INT_VU0, + INT_VU1, + INT_IPU, + INT_TIMER0, + INT_TIMER1, + INT_TIMER2, + INT_TIMER3, + INT_SFIFO, + INT_VU0WD + }; + + uint32_t m_istat; + uint32_t m_imask; + + emu_timer *m_vblank_timer; }; +/************************************** + * + * Machine Hardware + * + */ + +READ32_MEMBER(ps2sony_state::dmac_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: /* D_CTRL */ + logerror("%s: dmac_r: D_CTRL (%08x)\n", machine().describe_context(), ret); + break; + case 2: /* D_STAT */ + logerror("%s: dmac_r: D_STAT (%08x)\n", machine().describe_context(), ret); + break; + case 4: /* D_PCR */ + logerror("%s: dmac_r: D_PCR (%08x)\n", machine().describe_context(), ret); + break; + case 6: /* D_SQWC */ + logerror("%s: dmac_r: D_SQWC (%08x)\n", machine().describe_context(), ret); + break; + case 8: /* D_RBSR */ + logerror("%s: dmac_r: D_RBSR (%08x)\n", machine().describe_context(), ret); + break; + case 10: /* D_RBOR */ + logerror("%s: dmac_r: D_RBOR (%08x)\n", machine().describe_context(), ret); + break; + case 12: /* D_STADR */ + logerror("%s: dmac_r: D_STADR (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: dmac_r: Unknown offset %08x\n", machine().describe_context(), 0x1000e000 + (offset << 3)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2sony_state::dmac_w) +{ + switch (offset) + { + case 0: /* D_CTRL */ + logerror("%s: dmac_w: D_CTRL = %08x\n", machine().describe_context(), data); + break; + case 2: /* D_STAT */ + logerror("%s: dmac_w: D_STAT = %08x\n", machine().describe_context(), data); + break; + case 4: /* D_PCR */ + logerror("%s: dmac_w: D_PCR = %08x\n", machine().describe_context(), data); + break; + case 6: /* D_SQWC */ + logerror("%s: dmac_w: D_SQWC = %08x\n", machine().describe_context(), data); + break; + case 8: /* D_RBSR */ + logerror("%s: dmac_w: D_RBSR = %08x\n", machine().describe_context(), data); + break; + case 10: /* D_RBOR */ + logerror("%s: dmac_w: D_RBOR = %08x\n", machine().describe_context(), data); + break; + case 12: /* D_STADR */ + logerror("%s: dmac_w: D_STADR = %08x\n", machine().describe_context(), data); + break; + default: + logerror("%s: dmac_w: Unknown offset %08x = %08X\n", machine().describe_context(), 0x1000e000 + (offset << 3), data); + break; + } +} + +READ32_MEMBER(ps2sony_state::dmac_channel_r) +{ + uint32_t ret = 0; + switch (offset + 0x8000/8) + { + case 0x8000/8: /* D0_CHCR */ + logerror("%s: dmac_channel_r: D0_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0x8010/8: /* D0_MADR */ + logerror("%s: dmac_channel_r: D0_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0x8020/8: /* D0_QWC */ + logerror("%s: dmac_channel_r: D0_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0x8030/8: /* D0_TADR */ + logerror("%s: dmac_channel_r: D0_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0x8040/8: /* D0_ASR0 */ + logerror("%s: dmac_channel_r: D0_ASR0 (%08x)\n", machine().describe_context(), ret); + break; + case 0x8050/8: /* D0_ASR1 */ + logerror("%s: dmac_channel_r: D0_ASR1 (%08x)\n", machine().describe_context(), ret); + break; + case 0x9000/8: /* D1_CHCR */ + logerror("%s: dmac_channel_r: D1_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0x9010/8: /* D1_MADR */ + logerror("%s: dmac_channel_r: D1_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0x9020/8: /* D1_QWC */ + logerror("%s: dmac_channel_r: D1_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0x9030/8: /* D1_TADR */ + logerror("%s: dmac_channel_r: D1_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0x9040/8: /* D1_ASR0 */ + logerror("%s: dmac_channel_r: D1_ASR0 (%08x)\n", machine().describe_context(), ret); + break; + case 0x9050/8: /* D1_ASR1 */ + logerror("%s: dmac_channel_r: D1_ASR1 (%08x)\n", machine().describe_context(), ret); + break; + case 0xa000/8: /* D2_CHCR */ + logerror("%s: dmac_channel_r: D2_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xa010/8: /* D2_MADR */ + logerror("%s: dmac_channel_r: D2_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xa020/8: /* D2_QWC */ + logerror("%s: dmac_channel_r: D2_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xa030/8: /* D2_TADR */ + logerror("%s: dmac_channel_r: D2_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xa040/8: /* D2_ASR0 */ + logerror("%s: dmac_channel_r: D2_ASR0 (%08x)\n", machine().describe_context(), ret); + break; + case 0xa050/8: /* D2_ASR1 */ + logerror("%s: dmac_channel_r: D2_ASR1 (%08x)\n", machine().describe_context(), ret); + break; + case 0xb000/8: /* D3_CHCR */ + logerror("%s: dmac_channel_r: D3_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xb010/8: /* D3_MADR */ + logerror("%s: dmac_channel_r: D3_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xb020/8: /* D3_QWC */ + logerror("%s: dmac_channel_r: D3_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xb400/8: /* D4_CHCR */ + logerror("%s: dmac_channel_r: D4_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xb410/8: /* D4_MADR */ + logerror("%s: dmac_channel_r: D4_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xb420/8: /* D4_QWC */ + logerror("%s: dmac_channel_r: D4_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xb430/8: /* D4_TADR */ + logerror("%s: dmac_channel_r: D4_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc000/8: /* D5_CHCR */ + logerror("%s: dmac_channel_r: D5_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc010/8: /* D5_MADR */ + logerror("%s: dmac_channel_r: D5_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc020/8: /* D5_QWC */ + logerror("%s: dmac_channel_r: D5_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xc400/8: /* D6_CHCR */ + logerror("%s: dmac_channel_r: D6_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc410/8: /* D6_MADR */ + logerror("%s: dmac_channel_r: D6_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc420/8: /* D6_QWC */ + logerror("%s: dmac_channel_r: D6_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xc430/8: /* D6_TADR */ + logerror("%s: dmac_channel_r: D6_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc800/8: /* D7_CHCR */ + logerror("%s: dmac_channel_r: D7_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc810/8: /* D7_MADR */ + logerror("%s: dmac_channel_r: D7_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xc820/8: /* D7_QWC */ + logerror("%s: dmac_channel_r: D7_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xd000/8: /* D8_CHCR */ + logerror("%s: dmac_channel_r: D8_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd010/8: /* D8_MADR */ + logerror("%s: dmac_channel_r: D8_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd020/8: /* D8_QWC */ + logerror("%s: dmac_channel_r: D8_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xd080/8: /* D8_SADR */ + logerror("%s: dmac_channel_r: D8_SADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd400/8: /* D9_CHCR */ + logerror("%s: dmac_channel_r: D9_CHCR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd410/8: /* D9_MADR */ + logerror("%s: dmac_channel_r: D9_MADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd420/8: /* D9_QWC */ + logerror("%s: dmac_channel_r: D9_QWC (%08x)\n", machine().describe_context(), ret); + break; + case 0xd430/8: /* D9_TADR */ + logerror("%s: dmac_channel_r: D9_TADR (%08x)\n", machine().describe_context(), ret); + break; + case 0xd480/8: /* D9_SADR */ + logerror("%s: dmac_channel_r: D9_SADR (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: dmac_channel_r: Unknown offset %08x\n", machine().describe_context(), 0x10008000 + (offset << 3)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2sony_state::dmac_channel_w) +{ + switch (offset + 0x8000/8) + { + case 0x8000/8: /* D0_CHCR */ + logerror("%s: dmac_channel_w: D0_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0x8010/8: /* D0_MADR */ + logerror("%s: dmac_channel_w: D0_MADR = %08x\n", machine().describe_context(), data); + break; + case 0x8020/8: /* D0_QWC */ + logerror("%s: dmac_channel_w: D0_QWC = %08x\n", machine().describe_context(), data); + break; + case 0x8030/8: /* D0_TADR */ + logerror("%s: dmac_channel_w: D0_TADR = %08x\n", machine().describe_context(), data); + break; + case 0x8040/8: /* D0_ASR0 */ + logerror("%s: dmac_channel_w: D0_ASR0 = %08x\n", machine().describe_context(), data); + break; + case 0x8050/8: /* D0_ASR1 */ + logerror("%s: dmac_channel_w: D0_ASR1 = %08x\n", machine().describe_context(), data); + break; + case 0x9000/8: /* D1_CHCR */ + logerror("%s: dmac_channel_w: D1_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0x9010/8: /* D1_MADR */ + logerror("%s: dmac_channel_w: D1_MADR = %08x\n", machine().describe_context(), data); + break; + case 0x9020/8: /* D1_QWC */ + logerror("%s: dmac_channel_w: D1_QWC = %08x\n", machine().describe_context(), data); + break; + case 0x9030/8: /* D1_TADR */ + logerror("%s: dmac_channel_w: D1_TADR = %08x\n", machine().describe_context(), data); + break; + case 0x9040/8: /* D1_ASR0 */ + logerror("%s: dmac_channel_w: D1_ASR0 = %08x\n", machine().describe_context(), data); + break; + case 0x9050/8: /* D1_ASR1 */ + logerror("%s: dmac_channel_w: D1_ASR1 = %08x\n", machine().describe_context(), data); + break; + case 0xa000/8: /* D2_CHCR */ + logerror("%s: dmac_channel_w: D2_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xa010/8: /* D2_MADR */ + logerror("%s: dmac_channel_w: D2_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xa020/8: /* D2_QWC */ + logerror("%s: dmac_channel_w: D2_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xa030/8: /* D2_TADR */ + logerror("%s: dmac_channel_w: D2_TADR = %08x\n", machine().describe_context(), data); + break; + case 0xa040/8: /* D2_ASR0 */ + logerror("%s: dmac_channel_w: D2_ASR0 = %08x\n", machine().describe_context(), data); + break; + case 0xa050/8: /* D2_ASR1 */ + logerror("%s: dmac_channel_w: D2_ASR1 = %08x\n", machine().describe_context(), data); + break; + case 0xb000/8: /* D3_CHCR */ + logerror("%s: dmac_channel_w: D3_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xb010/8: /* D3_MADR */ + logerror("%s: dmac_channel_w: D3_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xb020/8: /* D3_QWC */ + logerror("%s: dmac_channel_w: D3_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xb400/8: /* D4_CHCR */ + logerror("%s: dmac_channel_w: D4_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xb410/8: /* D4_MADR */ + logerror("%s: dmac_channel_w: D4_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xb420/8: /* D4_QWC */ + logerror("%s: dmac_channel_w: D4_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xb430/8: /* D4_TADR */ + logerror("%s: dmac_channel_w: D4_TADR = %08x\n", machine().describe_context(), data); + break; + case 0xc000/8: /* D5_CHCR */ + logerror("%s: dmac_channel_w: D5_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xc010/8: /* D5_MADR */ + logerror("%s: dmac_channel_w: D5_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xc020/8: /* D5_QWC */ + logerror("%s: dmac_channel_w: D5_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xc400/8: /* D6_CHCR */ + logerror("%s: dmac_channel_w: D6_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xc410/8: /* D6_MADR */ + logerror("%s: dmac_channel_w: D6_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xc420/8: /* D6_QWC */ + logerror("%s: dmac_channel_w: D6_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xc430/8: /* D6_TADR */ + logerror("%s: dmac_channel_w: D6_TADR = %08x\n", machine().describe_context(), data); + break; + case 0xc800/8: /* D7_CHCR */ + logerror("%s: dmac_channel_w: D7_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xc810/8: /* D7_MADR */ + logerror("%s: dmac_channel_w: D7_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xc820/8: /* D7_QWC */ + logerror("%s: dmac_channel_w: D7_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xd000/8: /* D8_CHCR */ + logerror("%s: dmac_channel_w: D8_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xd010/8: /* D8_MADR */ + logerror("%s: dmac_channel_w: D8_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xd020/8: /* D8_QWC */ + logerror("%s: dmac_channel_w: D8_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xd080/8: /* D8_SADR */ + logerror("%s: dmac_channel_w: D8_SADR = %08x\n", machine().describe_context(), data); + break; + case 0xd400/8: /* D9_CHCR */ + logerror("%s: dmac_channel_w: D9_CHCR = %08x\n", machine().describe_context(), data); + break; + case 0xd410/8: /* D9_MADR */ + logerror("%s: dmac_channel_w: D9_MADR = %08x\n", machine().describe_context(), data); + break; + case 0xd420/8: /* D9_QWC */ + logerror("%s: dmac_channel_w: D9_QWC = %08x\n", machine().describe_context(), data); + break; + case 0xd430/8: /* D9_TADR */ + logerror("%s: dmac_channel_w: D9_TADR = %08x\n", machine().describe_context(), data); + break; + case 0xd480/8: /* D9_SADR */ + logerror("%s: dmac_channel_w: D9_SADR = %08x\n", machine().describe_context(), data); + break; + default: + logerror("%s: dmac_channel_w: Unknown offset %08x = %08x\n", machine().describe_context(), 0x10008000 + (offset << 3), data); + break; + } +} + +READ64_MEMBER(ps2sony_state::vif0_fifo_r) +{ + uint64_t ret = 0ULL; + if (offset) + { + logerror("%s: vif0_fifo_r [127..64]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + else + { + logerror("%s: vif0_fifo_r [63..0]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::vif0_fifo_w) +{ + if (offset) + { + logerror("%s: vif0_fifo_w [127..64]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } + else + { + logerror("%s: vif0_fifo_w [63..0]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } +} + +READ64_MEMBER(ps2sony_state::vif1_fifo_r) +{ + uint64_t ret = 0ULL; + if (offset) + { + logerror("%s: vif1_fifo_r [127..64]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + else + { + logerror("%s: vif1_fifo_r [63..0]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::vif1_fifo_w) +{ + if (offset) + { + logerror("%s: vif1_fifo_w [127..64]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } + else + { + logerror("%s: vif1_fifo_w [63..0]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } +} + +READ64_MEMBER(ps2sony_state::gif_fifo_r) +{ + uint64_t ret = 0ULL; + if (offset) + { + logerror("%s: gif_fifo_r [127..64]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + else + { + logerror("%s: gif_fifo_r [63..0]: (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::gif_fifo_w) +{ + if (offset) + { + logerror("%s: gif_fifo_w [127..64]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } + else + { + logerror("%s: gif_fifo_w [63..0]: %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + } +} + +READ32_MEMBER(ps2sony_state::ipu_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: /* IPU_CMD */ + logerror("%s: ipu_r: IPU_CMD (%08x)\n", machine().describe_context(), ret); + break; + case 2: /* IPU_CTRL */ + ret = m_ipu_in_fifo_index | (m_ipu_out_fifo_index << 4); + logerror("%s: ipu_r: IPU_CTRL (%08x)\n", machine().describe_context(), ret); + break; + case 4: /* IPU_BP */ + ret = m_ipu_in_fifo_index << 8; + logerror("%s: ipu_r: IPU_BP (%08x)\n", machine().describe_context(), ret); + break; + case 6: /* IPU_TOP */ + logerror("%s: ipu_r: IPU_TOP (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: ipu_r: Unknown offset %08x\n", machine().describe_context(), 0x10002000 + (offset << 3)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2sony_state::ipu_w) +{ + switch (offset) + { + case 0: /* IPU_CMD */ + logerror("%s: ipu_w: IPU_CMD = %08x\n", machine().describe_context(), data); + switch ((data >> 28) & 0xf) + { + case 0x00: /* BCLR */ + m_ipu_in_fifo_index = 0; + logerror("%s: IPU command: BCLR (%08x)\n", machine().describe_context(), data); + break; + case 0x01: /* IDEC */ + logerror("%s: IPU command: IDEC (%08x)\n", machine().describe_context(), data); + logerror("%s: FB:%d QSC:%d DT_DECODE:%d SGN:%d DITHER:%d OFM:%s\n", machine().describe_context(), + data & 0x3f, (data >> 16) & 0x1f, BIT(data, 24), BIT(data, 25), BIT(data, 26), BIT(data, 27) ? "RGB16" : "RGB32"); + break; + case 0x02: /* BDEC */ + logerror("%s: IPU command: BDEC (%08x)\n", machine().describe_context(), data); + logerror("%s: FB:%d QSC:%d DT:%d DCR:%d MBI:%d\n", machine().describe_context(), + data & 0x3f, (data >> 16) & 0x1f, BIT(data, 25), BIT(data, 26), BIT(data, 27)); + break; + case 0x03: /* VDEC */ + { + static const char *vlc[4] = + { + "Macroblock Address Increment", + "Macroblock Type", + "Motion Code", + "DMVector" + }; + logerror("%s: IPU command: VDEC (%08x)\n", machine().describe_context(), data); + logerror("%s: FB:%d TBL:%s\n", machine().describe_context(), data & 0x3f, vlc[(data >> 26) & 3]); + break; + } + case 0x04: /* FDEC */ + logerror("%s: IPU command: FDEC (%08x)\n", machine().describe_context(), data); + logerror("%s: FB:%d\n", machine().describe_context(), data & 0x3f); + break; + case 0x05: /* SETIQ */ + logerror("%s: IPU command: SETIQ (%08x)\n", machine().describe_context(), data); + logerror("%s: FB:%d IQM:%s quantization matrix\n", machine().describe_context(), data & 0x3f, BIT(data, 27) ? "Non-intra" : "Intra"); + break; + case 0x06: /* SETVQ */ + logerror("%s: IPU command: SETVQ (%08x)\n", machine().describe_context(), data); + break; + case 0x07: /* CSC */ + logerror("%s: IPU command: CSC (%08x)\n", machine().describe_context(), data); + logerror("%s: MBC:%d DTE:%d OFM:%s\n", machine().describe_context(), data & 0x3ff, BIT(data, 26), BIT(data, 27) ? "RGB16" : "RGB32"); + break; + case 0x08: /* PACK */ + logerror("%s: IPU command: PACK (%08x)\n", machine().describe_context(), data); + logerror("%s: DITHER:%d OFM:%s\n", machine().describe_context(), BIT(data, 26), BIT(data, 27) ? "RGB16" : "INDX4"); + break; + case 0x09: /* SETTH */ + logerror("%s: IPU command: SETTH (%08x)\n", machine().describe_context(), data); + logerror("%s: TH0:%d TH1:%s\n", machine().describe_context(), data & 0x1ff, (data >> 16) & 0x1ff); + break; + default: + logerror("%s: Unknown IPU command: %08x\n", machine().describe_context(), data); + break; + } + break; + case 2: /* IPU_CTRL */ + logerror("%s: ipu_w: IPU_CTRL = %08x\n", machine().describe_context(), data); + if (BIT(data, 30)) + { + m_ipu_in_fifo_index = 0; + m_ipu_out_fifo_index = 0; + m_ipu_ctrl &= ~(0x8000c000); + } + break; + case 4: /* IPU_BP */ + logerror("%s: ipu_w: IPU_BP = %08x (Not Valid!)\n", machine().describe_context(), data); + break; + case 6: /* IPU_TOP */ + logerror("%s: ipu_w: IPU_TOP = %08x\n", machine().describe_context(), data); + break; + default: + logerror("%s: ipu_w: Unknown offset %08x = %08x\n", machine().describe_context(), 0x10002000 + (offset << 3), data); + break; + } +} + +READ64_MEMBER(ps2sony_state::ipu_fifo_r) +{ + uint64_t ret = 0ULL; + switch (offset) + { + case 0: + logerror("%s: ipu_fifo_r: IPU_OUT_FIFO[127..64] (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + case 1: + logerror("%s: ipu_fifo_r: IPU_OUT_FIFO[63..0] (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + case 2: + logerror("%s: ipu_fifo_r: IPU_IN_FIFO[127..64] (Not Valid!)\n", machine().describe_context()); + break; + case 3: + logerror("%s: ipu_fifo_r: IPU_IN_FIFO[63..0] (Not Valid!)\n", machine().describe_context()); + break; + default: + logerror("%s: ipu_fifo_r: Unknown offset %08x\n", machine().describe_context(), 0x10007000 + (offset << 1)); + break; + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::ipu_fifo_w) +{ + switch (offset) + { + case 0: + logerror("%s: ipu_fifo_w: IPU_OUT_FIFO[127..64] = %08x%08x (Not Valid!)\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + break; + case 1: + logerror("%s: ipu_fifo_w: IPU_OUT_FIFO[63..0] = %08x%08x (Not Valid!)\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + break; + case 2: + logerror("%s: ipu_fifo_w: IPU_IN_FIFO[127..64] = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + m_ipu_in_fifo[m_ipu_in_fifo_index] = data; + m_ipu_in_fifo_index++; + m_ipu_in_fifo_index &= 0xf; + break; + case 3: + logerror("%s: ipu_fifo_w: IPU_IN_FIFO[63..0] = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + break; + default: + logerror("%s: ipu_fifo_w: Unknown offset %08x = %08x%08x\n", machine().describe_context(), 0x10007000 + (offset << 1), (uint32_t)(data >> 32), (uint32_t)data); + break; + } +} + +void ps2sony_state::check_irq0() +{ + m_maincpu->set_input_line(MIPS3_IRQ0, (m_istat & m_imask) ? ASSERT_LINE : CLEAR_LINE); +} + +void ps2sony_state::raise_interrupt(int line) +{ + printf("raise_interrupt: %d\n", (1 << line)); + m_istat |= (1 << line); + check_irq0(); +} -void ps2sony_state::video_start() +READ32_MEMBER(ps2sony_state::intc_r) { + switch (offset) + { + case 0: // I_STAT + logerror("%s: intc_r: I_STAT %08x\n", machine().describe_context(), m_istat); + return m_istat; + case 2: // I_MASK + logerror("%s: intc_r: I_MASK %08x\n", machine().describe_context(), m_imask); + return m_imask; + default: + logerror("%s: intc_r: Unknown offset %08x\n", machine().describe_context(), 0x1000f000 + (offset << 2)); + return 0; + } +} + +WRITE32_MEMBER(ps2sony_state::intc_w) +{ + switch (offset) + { + case 0: // I_STAT + logerror("%s: intc_w: I_STAT = %08x\n", machine().describe_context(), data); + m_istat &= ~data; + check_irq0(); + break; + case 2: // I_MASK + logerror("%s: intc_w: I_MASK = %08x\n", machine().describe_context(), data); + COMBINE_DATA(&m_imask); + check_irq0(); + break; + default: + logerror("%s: intc_w: Unknown offset %08x = %08x\n", machine().describe_context(), 0x1000f000 + (offset << 2), data); + break; + } +} + +READ32_MEMBER(ps2sony_state::sif_smflg_r) +{ + uint32_t ret = 0x00010000; + logerror("%s: sif_smflg_r (%08x)\n", machine().describe_context(), ret); + return ret; +} + +WRITE32_MEMBER(ps2sony_state::sif_smflg_w) +{ + logerror("%s: sif_smflg_w = %08x\n", machine().describe_context(), data); +} + +void ps2sony_state::machine_start() +{ + if (!m_vblank_timer) + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2sony_state::vblank), this)); +} + +void ps2sony_state::machine_reset() +{ + m_unk_f430_reg = 0; + m_unk_f440_reg = 0; + m_unk_f440_ret = 0; + m_unk_f440_counter = 0; + + m_ipu_ctrl = 0; + memset(m_ipu_in_fifo, 0, sizeof(uint64_t)*0x1000); + m_ipu_in_fifo_index = 0; + memset(m_ipu_out_fifo, 0, sizeof(uint64_t)*0x1000); + m_ipu_out_fifo_index = 0; + + memset(m_gs_base_regs, 0, sizeof(uint64_t) * 15); + m_gs_csr = 0ULL; + m_gs_imr = 0ULL; + m_gs_busdir = 0ULL; + m_gs_sig_label_id = 0ULL; + + m_vblank_timer->adjust(m_screen->time_until_pos(480), 1); +} + +TIMER_CALLBACK_MEMBER(ps2sony_state::vblank) +{ + if (param) + { + // VBlank enter + printf("1 "); + raise_interrupt(INT_VB_ON); + m_vblank_timer->adjust(m_screen->time_until_pos(0), 0); + } + else + { + printf("0 "); + // VBlank exit + raise_interrupt(INT_VB_OFF); + m_vblank_timer->adjust(m_screen->time_until_pos(480), 1); + } +} + +WRITE8_MEMBER(ps2sony_state::debug_w) +{ + printf("%c", (char)data); +} + +READ32_MEMBER(ps2sony_state::unk_f520_r) +{ + // Unknown purpose - BIOS seems to expect this value initially + return 0x1201; +} + +READ32_MEMBER(ps2sony_state::unk_f430_r) +{ + logerror("%s: Unknown 1000f430 read: %08x\n", machine().describe_context(), 0); + //return m_unk_f430_reg; + //return ~0; + return 0; // BIOS seems unhappy if we return anything else +} + +WRITE32_MEMBER(ps2sony_state::unk_f430_w) +{ + m_unk_f430_reg = data & ~0x80000000; + const uint16_t cmd = (data >> 16) & 0xfff; + const uint8_t subcmd = (data >> 6) & 0xf; + switch (cmd) + { + case 0x0021: + if (subcmd == 1 && !BIT(m_unk_f440_reg, 7)) + { + m_unk_f440_counter = 0; + } + break; + } + logerror("%s: Unknown 1000f430 write: %08x (cmd:%02x lsb:%02x)\n", machine().describe_context(), data, (data >> 16) & 0xff, data & 0xff); +} + +READ32_MEMBER(ps2sony_state::unk_f440_r) +{ + uint32_t ret = 0; + + const uint8_t lsb5 = m_unk_f430_reg & 0x1f; + const uint16_t cmd = (uint16_t)(m_unk_f430_reg >> 16); + const uint8_t subcmd = (m_unk_f430_reg >> 6) & 0xf; + if (subcmd == 0) + { + switch (cmd) + { + case 0x21: + if (m_unk_f440_counter < 2) + { + ret = 0x1f; + m_unk_f440_counter++; + } + break; + + case 0x40: + ret = lsb5; + break; + + default: + fatalerror("!"); + break; + } + } + + logerror("%s: Unknown 1000f440 read: %08x\n", machine().describe_context(), ret); + return ret; +} + +WRITE32_MEMBER(ps2sony_state::unk_f440_w) +{ + logerror("%s: Unknown 1000f440 write: %08x\n", machine().describe_context(), data); + m_unk_f440_reg = data; +} + +/************************************** + * + * Video Hardware + * + */ + +READ64_MEMBER(ps2sony_state::gs_regs0_r) +{ + uint64_t ret = m_gs_base_regs[offset >> 1]; + switch (offset) + { + case 0x00: logerror("%s: gs_regs0_r: PMODE (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x02: logerror("%s: gs_regs0_r: SMODE1 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x04: logerror("%s: gs_regs0_r: SMODE2 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x06: logerror("%s: gs_regs0_r: SRFSH (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x08: logerror("%s: gs_regs0_r: SYNCH1 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x0a: logerror("%s: gs_regs0_r: SYNCH2 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x0c: logerror("%s: gs_regs0_r: SYNCV (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x0e: logerror("%s: gs_regs0_r: DISPFB1 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x10: logerror("%s: gs_regs0_r: DISPLAY1 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x12: logerror("%s: gs_regs0_r: DISPFB2 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x14: logerror("%s: gs_regs0_r: DISPLAY2 (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x16: logerror("%s: gs_regs0_r: EXTBUF (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x18: logerror("%s: gs_regs0_r: EXTDATA (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x1a: logerror("%s: gs_regs0_r: EXTWRITE (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + case 0x1c: logerror("%s: gs_regs0_r: BGCOLOR (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); break; + default: logerror("%s: gs_regs0_r: Unknown (%08x)\n", machine().describe_context(), 0x12000000 + (offset << 3)); break; + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::gs_regs0_w) +{ + switch (offset) + { + case 0x00: logerror("%s: gs_regs0_w: PMODE = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x02: logerror("%s: gs_regs0_w: SMODE1 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x04: logerror("%s: gs_regs0_w: SMODE2 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x06: logerror("%s: gs_regs0_w: SRFSH = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x08: logerror("%s: gs_regs0_w: SYNCH1 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x0a: logerror("%s: gs_regs0_w: SYNCH2 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x0c: logerror("%s: gs_regs0_w: SYNCV = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x0e: logerror("%s: gs_regs0_w: DISPFB1 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x10: logerror("%s: gs_regs0_w: DISPLAY1 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x12: logerror("%s: gs_regs0_w: DISPFB2 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x14: logerror("%s: gs_regs0_w: DISPLAY2 = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x16: logerror("%s: gs_regs0_w: EXTBUF = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x18: logerror("%s: gs_regs0_w: EXTDATA = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x1a: logerror("%s: gs_regs0_w: EXTWRITE = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + case 0x1c: logerror("%s: gs_regs0_w: BGCOLOR = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); break; + default: logerror("%s: gs_regs0_w: Unknown %08x = %08x%08x\n", machine().describe_context(), 0x12000000 + (offset << 3), (uint32_t)(data >> 32), (uint32_t)data); break; + } + COMBINE_DATA(&m_gs_base_regs[offset >> 1]); +} + +READ64_MEMBER(ps2sony_state::gs_regs1_r) +{ + uint64_t ret = 0; + switch (offset) + { + case 0x00: + ret = m_gs_csr; + logerror("%s: gs_regs1_r: CSR (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + case 0x02: + ret = m_gs_imr; + logerror("%s: gs_regs1_r: IMR (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + case 0x08: + ret = m_gs_busdir; + logerror("%s: gs_regs1_r: BUSDIR (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + case 0x10: + ret = m_gs_sig_label_id; + logerror("%s: gs_regs1_r: SIGLBLID (%08x%08x)\n", machine().describe_context(), (uint32_t)(ret >> 32), (uint32_t)ret); + break; + default: + logerror("%s: gs_regs1_r: Unknown (%08x)\n", machine().describe_context(), 0x12000000 + (offset << 3)); + break; + } + return ret; +} + +WRITE64_MEMBER(ps2sony_state::gs_regs1_w) +{ + switch (offset) + { + case 0x00: + logerror("%s: gs_regs1_w: CSR = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + COMBINE_DATA(&m_gs_csr); + break; + case 0x02: + logerror("%s: gs_regs1_w: IMR = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + COMBINE_DATA(&m_gs_imr); + break; + case 0x08: + logerror("%s: gs_regs1_w: BUSDIR = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + COMBINE_DATA(&m_gs_busdir); + break; + case 0x10: + logerror("%s: gs_regs1_w: SIGLBLID = %08x%08x\n", machine().describe_context(), (uint32_t)(data >> 32), (uint32_t)data); + COMBINE_DATA(&m_gs_sig_label_id); + break; + default: + logerror("%s: gs_regs1_w: Unknown %08x = %08x%08x\n", machine().describe_context(), 0x12000000 + (offset << 3), (uint32_t)(data >> 32), (uint32_t)data); + break; + } } uint32_t ps2sony_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) @@ -191,8 +1167,43 @@ uint32_t ps2sony_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma void ps2sony_state::mem_map(address_map &map) { - map(0x00000000, 0x01ffffff).ram(); // 32 MB RAM - map(0x1fc00000, 0x1fdfffff).rom().region("bios", 0); + map(0x00000000, 0x01ffffff).mirror(0xe000000).ram(); // 32 MB RAM + map(0x10000000, 0x100007ff).rw(m_timer[0], FUNC(ps2_timer_device::read), FUNC(ps2_timer_device::write)).umask64(0x00000000ffffffff); + map(0x10000800, 0x10000fff).rw(m_timer[1], FUNC(ps2_timer_device::read), FUNC(ps2_timer_device::write)).umask64(0x00000000ffffffff); + map(0x10001000, 0x100017ff).rw(m_timer[2], FUNC(ps2_timer_device::read), FUNC(ps2_timer_device::write)).umask64(0x00000000ffffffff); + map(0x10001800, 0x10001fff).rw(m_timer[3], FUNC(ps2_timer_device::read), FUNC(ps2_timer_device::write)).umask64(0x00000000ffffffff); + map(0x10002000, 0x10002fff).rw(FUNC(ps2sony_state::ipu_r), FUNC(ps2sony_state::ipu_w)).umask64(0x00000000ffffffff); + map(0x10004000, 0x1000400f).mirror(0xff0).rw(FUNC(ps2sony_state::vif0_fifo_r), FUNC(ps2sony_state::vif0_fifo_w)); + map(0x10005000, 0x1000500f).mirror(0xff0).rw(FUNC(ps2sony_state::vif1_fifo_r), FUNC(ps2sony_state::vif1_fifo_w)); + map(0x10006000, 0x1000600f).mirror(0xff0).rw(FUNC(ps2sony_state::gif_fifo_r), FUNC(ps2sony_state::gif_fifo_w)); + map(0x10007000, 0x1000701f).mirror(0xfe0).rw(FUNC(ps2sony_state::ipu_fifo_r), FUNC(ps2sony_state::ipu_fifo_w)); + map(0x10008000, 0x1000dfff).rw(FUNC(ps2sony_state::dmac_channel_r), FUNC(ps2sony_state::dmac_channel_w)).umask64(0x00000000ffffffff);; + map(0x1000e000, 0x1000efff).rw(FUNC(ps2sony_state::dmac_r), FUNC(ps2sony_state::dmac_w)).umask64(0x00000000ffffffff); + map(0x1000f000, 0x1000f017).rw(FUNC(ps2sony_state::intc_r), FUNC(ps2sony_state::intc_w)).umask64(0x00000000ffffffff); + map(0x1000f130, 0x1000f137).nopr(); + map(0x1000f180, 0x1000f187).w(FUNC(ps2sony_state::debug_w)).umask64(0x00000000000000ff); + map(0x1000f230, 0x1000f237).rw(FUNC(ps2sony_state::sif_smflg_r), FUNC(ps2sony_state::sif_smflg_w)).umask64(0x00000000ffffffff); + map(0x1000f430, 0x1000f437).rw(FUNC(ps2sony_state::unk_f430_r), FUNC(ps2sony_state::unk_f430_w)).umask64(0x00000000ffffffff); // Unknown + map(0x1000f440, 0x1000f447).rw(FUNC(ps2sony_state::unk_f440_r), FUNC(ps2sony_state::unk_f440_w)).umask64(0x00000000ffffffff); // Unknown + map(0x1000f520, 0x1000f527).r(FUNC(ps2sony_state::unk_f520_r)).umask64(0x00000000ffffffff); // Unknown + map(0x11000000, 0x11000fff).mirror(0x3000).ram().share(m_vu0_imem); + map(0x11004000, 0x11004fff).mirror(0x3000).ram().share(m_vu0_dmem); + map(0x11008000, 0x1100bfff).ram().share(m_vu1_imem); + map(0x1100c000, 0x1100ffff).ram().share(m_vu1_dmem); + map(0x12000000, 0x120003ff).mirror(0xc00).rw(FUNC(ps2sony_state::gs_regs0_r), FUNC(ps2sony_state::gs_regs0_w)); + map(0x12001000, 0x120013ff).mirror(0xc00).rw(FUNC(ps2sony_state::gs_regs1_r), FUNC(ps2sony_state::gs_regs1_w)); + map(0x1c000000, 0x1c1fffff).ram().share(m_iop_ram); // IOP has 2MB EDO RAM per Wikipedia, and writes go up to this point + map(0x1fc00000, 0x1fffffff).rom().region("bios", 0); + + map(0x70000000, 0x70003fff).ram().share(m_sp_ram); // 16KB Scratchpad RAM +} + +void ps2sony_state::iop_map(address_map &map) +{ + map(0x00000000, 0x001fffff).ram().share(m_iop_ram); + map(0x1f802070, 0x1f802073).noprw(); + map(0x1fc00000, 0x1fdfffff).rom().region("bios", 0); + } static INPUT_PORTS_START( ps2sony ) @@ -200,15 +1211,25 @@ INPUT_PORTS_END MACHINE_CONFIG_START(ps2sony_state::ps2sony) MCFG_DEVICE_ADD("maincpu", R5900LE, 294'912'000) + MCFG_CPU_FORCE_NO_DRC() MCFG_MIPS3_ICACHE_SIZE(16384) MCFG_MIPS3_DCACHE_SIZE(16384) MCFG_DEVICE_PROGRAM_MAP(mem_map) + MCFG_DEVICE_ADD("iop", SONYPS2_IOP, XTAL(67'737'600)/2) + MCFG_DEVICE_PROGRAM_MAP(iop_map) + + MCFG_QUANTUM_TIME(attotime::from_hz(1000000)) + MCFG_DEVICE_ADD(m_timer[0], SONYPS2_TIMER, 294912000/2, true) + MCFG_DEVICE_ADD(m_timer[1], SONYPS2_TIMER, 294912000/2, true) + MCFG_DEVICE_ADD(m_timer[2], SONYPS2_TIMER, 294912000/2, false) + MCFG_DEVICE_ADD(m_timer[3], SONYPS2_TIMER, 294912000/2, false) + /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_UPDATE_DRIVER(ps2sony_state, screen_update) - MCFG_SCREEN_SIZE(640, 480) + MCFG_SCREEN_SIZE(640, 525) MCFG_SCREEN_VISIBLE_AREA(0, 639, 0, 479) MCFG_PALETTE_ADD("palette", 65536) diff --git a/src/mame/machine/ps2timer.cpp b/src/mame/machine/ps2timer.cpp new file mode 100644 index 00000000000..2ba6668715d --- /dev/null +++ b/src/mame/machine/ps2timer.cpp @@ -0,0 +1,270 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 Timer device skeleton +* +* To Do: +* Everything +* +*/ + +#include "ps2timer.h" + +DEFINE_DEVICE_TYPE(SONYPS2_TIMER, ps2_timer_device, "ps2timer", "EE Core Timer") + +ps2_timer_device::ps2_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYPS2_TIMER, tag, owner, clock) + , m_compare_timer(nullptr) + , m_overflow_timer(nullptr) + , m_mode(0) + , m_last_enable_time(attotime::zero) + , m_last_update_time(attotime::zero) + , m_elapsed_time(attotime::zero) + , m_enabled(false) + , m_zero_return(false) + , m_count(0) + , m_compare(0) + , m_can_hold(false) + , m_hold(0) + , m_clk_select(CLKS_BUSCLK1) + , m_gate_enable(false) + , m_gate_select(GATS_HBLNK) + , m_gate_mode(GATM_LOW) + , m_cmp_int_enabled(false) + , m_cmp_int(false) + , m_ovf_int_enabled(false) + , m_ovf_int(false) +{ +} + +void ps2_timer_device::device_start() +{ + if (!m_compare_timer) + m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::compare), this)); + + if (!m_overflow_timer) + m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::overflow), this)); +} + +void ps2_timer_device::device_reset() +{ + m_mode = 0; + + m_last_enable_time = attotime::zero; + m_last_update_time = attotime::zero; + m_elapsed_time = attotime::zero; + + m_enabled = false; + m_zero_return = false; + + m_count = 0; + m_compare = 0; + + m_can_hold = false; + m_hold = 0; + + m_clk_select = CLKS_BUSCLK1; + + m_gate_enable = false; + m_gate_select = GATS_HBLNK; + m_gate_mode = GATM_LOW; + + m_cmp_int_enabled = false; + m_cmp_int = false; + + m_ovf_int_enabled = false; + m_ovf_int = false; + + m_compare_timer->adjust(attotime::never); + m_overflow_timer->adjust(attotime::never); +} + +void ps2_timer_device::update_gate() +{ + // TODO +} + +void ps2_timer_device::update_interrupts() +{ + // TODO +} + +void ps2_timer_device::update_compare_timer() +{ + // TODO +} + +void ps2_timer_device::update_overflow_timer() +{ + // TODO +} + +void ps2_timer_device::update_count() +{ + if (!m_enabled) return; + uint32_t frequency = 0; + + switch (m_clk_select) + { + case CLKS_BUSCLK1: + frequency = clock(); + break; + case CLKS_BUSCLK16: + frequency = clock() / 16; + break; + case CLKS_BUSCLK256: + frequency = clock() / 256; + break; + case CLKS_HBLNK: + frequency = clock() / 18700; + break; + } + + attotime curr_time = machine().scheduler().time(); + attotime time_delta = curr_time - m_last_update_time; + m_last_update_time = curr_time; + m_elapsed_time += time_delta; + uint32_t ticks = (uint32_t)m_elapsed_time.as_ticks(frequency); + if (ticks > 0) + { + m_elapsed_time -= attotime::from_ticks(ticks, frequency); + m_count += ticks; + } +} + +void ps2_timer_device::update_hold() +{ + // TODO +} + +void ps2_timer_device::set_mode(uint32_t data) +{ + static const char *clks_names[4] = { "BUSCLK", "BUSCLK/16", "BUSCLK/256", "HBLNK" }; + static const char *gatm_names[4] = { "low", "reset+rising", "reset+falling", "reset+both" }; + logerror("%s: CLKS=%s, GATE=%d, GATS=%cBLNK\n", machine().describe_context(), clks_names[data & 3], BIT(data, 2), BIT(data, 3) ? 'V' : 'H'); + logerror("%s: GATM=%s, ZRET=%d, CUE=%d\n", machine().describe_context(), gatm_names[(data >> 4) & 3], BIT(data, 6), BIT(data, 7)); + logerror("%s: CMPE=%d, OVFE=%d, %s, %s\n", machine().describe_context(), BIT(data, 8), BIT(data, 9), BIT(data, 10) ? "Clear Equal" : "", BIT(data, 11) ? "Clear Overflow" : ""); + + if (!(data & (MODE_EQUF | MODE_OVFF)) && data == m_mode) return; + + const uint32_t old = m_mode; + m_mode = data; + const uint32_t changed = old ^ data; + + m_clk_select = (timer_clock_select)(data & 3); + m_gate_enable = BIT(data, 2); + m_gate_select = BIT(data, 3) ? GATS_VBLNK : GATS_HBLNK; + m_gate_mode = (timer_gate_mode)((data >> 4) & 3); + m_zero_return = BIT(data, 6); + m_enabled = BIT(data, 7); + + if (changed & (MODE_GATE | MODE_GATS | MODE_GATM)) + { + update_gate(); + } + + if (changed & (MODE_CUE | MODE_CLKS | MODE_ZRET)) + { + update_compare_timer(); + update_overflow_timer(); + } + + if (changed & (MODE_CMPE | MODE_OVFE | MODE_EQUF | MODE_OVFF)) + { + m_cmp_int_enabled = BIT(data, 8); + m_ovf_int_enabled = BIT(data, 9); + m_cmp_int = BIT(data, 10) ? 0 : m_cmp_int; + m_ovf_int = BIT(data, 11) ? 0 : m_ovf_int; + update_interrupts(); + } +} + +TIMER_CALLBACK_MEMBER(ps2_timer_device::compare) +{ +} + +TIMER_CALLBACK_MEMBER(ps2_timer_device::overflow) +{ +} + +READ32_MEMBER(ps2_timer_device::read) +{ + uint32_t ret = 0; + switch (offset) + { + case 0x00: + { + const uint32_t old = m_count; + update_count(); + ret = m_count; + if (old != m_count) + logerror("%s: PS2 timer read: COUNT (%08x)\n", machine().describe_context(), ret); + break; + } + + case 0x02: + ret = m_mode; + logerror("%s: PS2 timer read: MODE (%08x)\n", machine().describe_context(), ret); + break; + + case 0x04: + ret = m_compare; + logerror("%s: PS2 timer read: COMP (%08x)\n", machine().describe_context(), ret); + break; + + case 0x06: + ret = m_hold; + logerror("%s: PS2 timer read: HOLD (%08x)\n", machine().describe_context(), ret); + break; + + default: + break; + } + return ret; +} + +WRITE32_MEMBER(ps2_timer_device::write) +{ + switch (offset) + { + case 0x00: + m_count = data; + logerror("%s: PS2 timer write: COUNT = %08x\n", machine().describe_context(), data); + update_compare_timer(); + update_overflow_timer(); + break; + + case 0x02: + set_mode(data); + break; + + case 0x04: + { + logerror("%s: PS2 timer write: COMP = %08x\n", machine().describe_context(), data); + if (m_compare == data) + break; + + m_compare = data; + update_compare_timer(); + break; + } + + case 0x06: + { + if (!m_can_hold) + break; + + logerror("%s: PS2 timer write: HOLD = %08x\n", machine().describe_context(), data); + if (m_hold == data) + break; + + m_hold = data; + update_hold(); + break; + } + + default: + break; + } +} diff --git a/src/mame/machine/ps2timer.h b/src/mame/machine/ps2timer.h new file mode 100644 index 00000000000..879526f1d92 --- /dev/null +++ b/src/mame/machine/ps2timer.h @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 Timer device skeleton +* +* To Do: +* Everything +* +*/ + +#ifndef MAME_MACHINE_PS2TIMER_H +#define MAME_MACHINE_PS2TIMER_H + +#pragma once + +#include "emu.h" + +class ps2_timer_device : public device_t +{ +public: + ps2_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, bool can_hold) + : ps2_timer_device(mconfig, tag, owner, clock) + { + m_can_hold = can_hold; + } + + ps2_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + +protected: + enum timer_mode_mask : uint32_t + { + MODE_CLKS = (3 << 0), + MODE_GATE = (1 << 2), + MODE_GATS = (1 << 3), + MODE_GATM = (3 << 4), + MODE_ZRET = (1 << 6), + MODE_CUE = (1 << 7), + MODE_CMPE = (1 << 8), + MODE_OVFE = (1 << 9), + MODE_EQUF = (1 << 10), + MODE_OVFF = (1 << 11), + }; + + enum timer_gate_mode : uint32_t + { + GATM_LOW = 0, + GATM_RISING, + GATM_FALLING, + GATM_BOTH + }; + + enum timer_clock_select : uint32_t + { + CLKS_BUSCLK1 = 0, + CLKS_BUSCLK16, + CLKS_BUSCLK256, + CLKS_HBLNK + }; + + enum timer_gate_select : uint32_t + { + GATS_HBLNK = 0, + GATS_VBLNK + }; + + virtual void device_start() override; + virtual void device_reset() override; + + TIMER_CALLBACK_MEMBER(compare); + TIMER_CALLBACK_MEMBER(overflow); + + void update_gate(); + void update_interrupts(); + + void update_compare_timer(); + void update_overflow_timer(); + + void update_count(); + void update_hold(); + + void set_mode(uint32_t data); + + emu_timer *m_compare_timer; + emu_timer *m_overflow_timer; + + uint32_t m_mode; + + attotime m_last_enable_time; + attotime m_last_update_time; + attotime m_elapsed_time; + bool m_enabled; + bool m_zero_return; + uint32_t m_count; + uint32_t m_compare; + + bool m_can_hold; + uint32_t m_hold; + + timer_clock_select m_clk_select; + + bool m_gate_enable; + timer_gate_select m_gate_select; + timer_gate_mode m_gate_mode; + + bool m_cmp_int_enabled; + bool m_cmp_int; + + bool m_ovf_int_enabled; + bool m_ovf_int; +}; + +DECLARE_DEVICE_TYPE(SONYPS2_TIMER, ps2_timer_device) + +#endif // MAME_MACHINE_PS2TIMER_H
\ No newline at end of file |