diff options
author | mooglyguy <therealmogminer@gmail.com> | 2018-07-01 02:11:59 +0200 |
---|---|---|
committer | mooglyguy <therealmogminer@gmail.com> | 2018-07-01 02:12:13 +0200 |
commit | 9d60df7b06298e6285fb2ef8d5d4b3d1f8cb89cd (patch) | |
tree | 0d9a2f603a3871934e54a8244ff73a3afdcd7c60 | |
parent | 65a876f81829bfb60adb56b7ae22b6b0b090e7d8 (diff) |
ps2sony: Fixed some R3000 bugs, started fleshing out IOP devices, nw
-rw-r--r-- | scripts/target/mame/mess.lua | 4 | ||||
-rw-r--r-- | src/devices/cpu/mips/r3000.cpp | 29 | ||||
-rw-r--r-- | src/mame/drivers/ps2sony.cpp | 345 | ||||
-rw-r--r-- | src/mame/machine/iopdma.cpp | 138 | ||||
-rw-r--r-- | src/mame/machine/iopdma.h | 58 | ||||
-rw-r--r-- | src/mame/machine/ioptimer.cpp | 262 | ||||
-rw-r--r-- | src/mame/machine/ioptimer.h | 100 | ||||
-rw-r--r-- | src/mame/machine/ps2timer.cpp | 1 |
8 files changed, 908 insertions, 29 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 3009590149e..a87724077bb 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -3063,6 +3063,10 @@ files { MAME_DIR .. "src/mame/drivers/ps2sony.cpp", MAME_DIR .. "src/mame/machine/ps2timer.cpp", MAME_DIR .. "src/mame/machine/ps2timer.h", + MAME_DIR .. "src/mame/machine/ioptimer.cpp", + MAME_DIR .. "src/mame/machine/ioptimer.h", + MAME_DIR .. "src/mame/machine/iopdma.cpp", + MAME_DIR .. "src/mame/machine/iopdma.h", } createMESSProjects(_target, _subtarget, "sord") diff --git a/src/devices/cpu/mips/r3000.cpp b/src/devices/cpu/mips/r3000.cpp index 4a15b1f60a6..fd906584aa7 100644 --- a/src/devices/cpu/mips/r3000.cpp +++ b/src/devices/cpu/mips/r3000.cpp @@ -211,7 +211,10 @@ r3081_device::r3081_device(const machine_config &mconfig, const char *tag, devic //------------------------------------------------- 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) { } + : r3000_device(mconfig, SONYPS2_IOP, tag, owner, clock, CHIP_TYPE_IOP) +{ + m_endianness = ENDIANNESS_LITTLE; +} //------------------------------------------------- @@ -384,7 +387,6 @@ void r3000_device::device_start() save_item(NAME(m_dcache)); } - //------------------------------------------------- // device_post_load - //------------------------------------------------- @@ -416,7 +418,7 @@ void r3000_device::device_reset() void iop_device::device_reset() { r3000_device::device_reset(); - m_cpr[0][COP0_PRId] = 0x2; + m_cpr[0][COP0_PRId] = 0x1f; } @@ -506,31 +508,43 @@ inline uint32_t r3000_device::readop(offs_t pc) uint8_t r3000_device::readmem(offs_t offset) { + if (SR & SR_IsC) + return 0; return m_program->read_byte(offset); } uint16_t r3000_device::readmem_word(offs_t offset) { + if (SR & SR_IsC) + return 0; return m_program->read_word(offset); } uint32_t r3000_device::readmem_dword(offs_t offset) { + if (SR & SR_IsC) + return 0; return m_program->read_dword(offset); } void r3000_device::writemem(offs_t offset, uint8_t data) { + if (SR & SR_IsC) + return; m_program->write_byte(offset, data); } void r3000_device::writemem_word(offs_t offset, uint16_t data) { + if (SR & SR_IsC) + return; m_program->write_word(offset, data); } void r3000_device::writemem_dword(offs_t offset, uint32_t data) { + if (SR & SR_IsC) + return; m_program->write_dword(offset, data); } @@ -624,7 +638,7 @@ void r3000_device::writecache_le_dword(offs_t offset, uint32_t data) inline void r3000_device::generate_exception(int exception) { // set the exception PC - m_cpr[0][COP0_EPC] = m_pc; + m_cpr[0][COP0_EPC] = (exception == EXCEPTION_SYSCALL ? m_ppc : m_pc); // put the cause in the low 8 bits and clear the branch delay flag CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); @@ -641,10 +655,11 @@ inline void r3000_device::generate_exception(int exception) SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c); // based on the BEV bit, we either go to ROM or RAM - m_pc = (SR & SR_BEV) ? 0xbfc00000 : 0x80000000; + bool bev = (SR & SR_BEV) ? true : false; + m_pc = bev ? 0xbfc00000 : 0x80000000; - // most exceptions go to offset 0x180, except for TLB stuff - if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) + // most exceptions go to offset 0x180, except for TLB stuff and syscall (if BEV is unset) + if ((exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) || !bev) m_pc += 0x80; else m_pc += 0x180; diff --git a/src/mame/drivers/ps2sony.cpp b/src/mame/drivers/ps2sony.cpp index d14d2733564..31d4f22ae96 100644 --- a/src/mame/drivers/ps2sony.cpp +++ b/src/mame/drivers/ps2sony.cpp @@ -159,6 +159,8 @@ iLinkSGUID=0x-------- #include "cpu/mips/mips3.h" #include "cpu/mips/r3000.h" #include "machine/ps2timer.h" +#include "machine/ioptimer.h" +#include "machine/iopdma.h" #include "emupal.h" #include "screen.h" @@ -168,7 +170,10 @@ public: ps2sony_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_iop(*this, "iop") , m_timer(*this, "timer%u", 0U) + , m_iop_timer(*this, "iop_timer") + , m_iop_dma(*this, "iop_dma") , m_screen(*this, "screen") , m_iop_ram(*this, "iop_ram") , m_sp_ram(*this, "sp_ram") @@ -210,25 +215,46 @@ protected: 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_READ32_MEMBER(sif_r); + DECLARE_WRITE32_MEMBER(sif_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); + DECLARE_READ64_MEMBER(board_id_r); + + DECLARE_WRITE64_MEMBER(ee_iop_ram_w); + DECLARE_READ64_MEMBER(ee_iop_ram_r); + DECLARE_READ32_MEMBER(iop_intc_r); + DECLARE_WRITE32_MEMBER(iop_intc_w); + DECLARE_READ32_MEMBER(iop_sif_r); + DECLARE_WRITE32_MEMBER(iop_sif_w); + DECLARE_READ32_MEMBER(iop_dma_ctrl0_r); + DECLARE_WRITE32_MEMBER(iop_dma_ctrl0_w); + DECLARE_READ32_MEMBER(iop_dma_ctrl1_r); + DECLARE_WRITE32_MEMBER(iop_dma_ctrl1_w); + DECLARE_WRITE32_MEMBER(iop_debug_w); + + DECLARE_WRITE_LINE_MEMBER(iop_timer_irq); void check_irq0(); void raise_interrupt(int line); + void check_iop_irq(); + void raise_iop_interrupt(int line); + void mem_map(address_map &map); void iop_map(address_map &map); required_device<cpu_device> m_maincpu; + required_device<iop_device> m_iop; required_device_array<ps2_timer_device, 4> m_timer; + required_device<iop_timer_device> m_iop_timer; + required_device<iop_dma_device> m_iop_dma; required_device<screen_device> m_screen; - required_shared_ptr<uint64_t> m_iop_ram; + required_shared_ptr<uint32_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; @@ -252,6 +278,14 @@ protected: uint64_t m_ipu_out_fifo[0x1000]; uint64_t m_ipu_out_fifo_index; + uint32_t m_sif_ms_mailbox; + uint32_t m_sif_sm_mailbox; + uint32_t m_sif_ms_flag; + uint32_t m_sif_sm_flag; + uint32_t m_sif_ctrl; + + uint32_t m_dmac_d5_chcr; + enum { INT_GS = 0, @@ -274,6 +308,10 @@ protected: uint32_t m_istat; uint32_t m_imask; + uint32_t m_iop_istat; + uint32_t m_iop_imask; + uint32_t m_iop_ienable; + emu_timer *m_vblank_timer; }; @@ -428,6 +466,7 @@ READ32_MEMBER(ps2sony_state::dmac_channel_r) logerror("%s: dmac_channel_r: D4_TADR (%08x)\n", machine().describe_context(), ret); break; case 0xc000/8: /* D5_CHCR */ + ret = m_dmac_d5_chcr; logerror("%s: dmac_channel_r: D5_CHCR (%08x)\n", machine().describe_context(), ret); break; case 0xc010/8: /* D5_MADR */ @@ -493,6 +532,8 @@ READ32_MEMBER(ps2sony_state::dmac_channel_r) WRITE32_MEMBER(ps2sony_state::dmac_channel_w) { + static const char* mode_strings[4] = { "Normal", "Chain", "Interleave", "Undefined" }; + switch (offset + 0x8000/8) { case 0x8000/8: /* D0_CHCR */ @@ -571,7 +612,9 @@ WRITE32_MEMBER(ps2sony_state::dmac_channel_w) 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); + logerror("%s: dmac_channel_w: D5_CHCR = %08x (DIR=%s Memory, MOD=%s, ASP=%d, TTE=%s DMAtag, \n", machine().describe_context(), data, BIT(data, 0) ? "From" : "To", mode_strings[(data >> 1) & 3], (data >> 3) & 3, BIT(data, 6) ? "Transfers" : "Does not transfer"); + logerror("%s: TIE=%d, START=%d, TAG=%04x\n", machine().describe_context(), BIT(data, 7), BIT(data, 8), data >> 16); + COMBINE_DATA(&m_dmac_d5_chcr); break; case 0xc010/8: /* D5_MADR */ logerror("%s: dmac_channel_w: D5_MADR = %08x\n", machine().describe_context(), data); @@ -875,19 +918,95 @@ void ps2sony_state::check_irq0() m_maincpu->set_input_line(MIPS3_IRQ0, (m_istat & m_imask) ? ASSERT_LINE : CLEAR_LINE); } +void ps2sony_state::check_iop_irq() +{ + bool active = (m_iop_ienable && (m_iop_istat & m_iop_imask)); + logerror("%s: check_iop_irq: %d\n", machine().describe_context(), active ? 1 : 0); + m_iop->set_input_line(R3000_IRQ0, active ? 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::raise_iop_interrupt(int line) +{ + logerror("%s: raise_iop_interrupt: %d\n", machine().describe_context(), line); + m_iop_istat |= (1 << line); + check_iop_irq(); +} + +WRITE_LINE_MEMBER(ps2sony_state::iop_timer_irq) +{ + logerror("%s: iop_timer_irq: %d\n", machine().describe_context(), state); + if (state) + raise_iop_interrupt(16); +} + +WRITE32_MEMBER(ps2sony_state::iop_debug_w) +{ + //printf("%08x ", data); +} + +READ32_MEMBER(ps2sony_state::iop_intc_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: // I_STAT + ret = m_iop_istat; + logerror("%s: iop_intc_r: I_STAT %08x\n", machine().describe_context(), ret); + break; + case 1: // I_MASK + ret = m_iop_imask; + logerror("%s: iop_intc_r: I_MASK %08x\n", machine().describe_context(), ret); + break; + case 2: // I_ENABLE + ret = m_iop_ienable; + m_iop_ienable = 0; + check_iop_irq(); + logerror("%s: iop_intc_r: I_ENABLE %08x\n", machine().describe_context(), ret); + break; + default: + logerror("%s: iop_intc_r: Unknown offset %08x\n", machine().describe_context(), 0x1f801070 + (offset << 2)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2sony_state::iop_intc_w) +{ + switch (offset) + { + case 0: // I_STAT + logerror("%s: iop_intc_w: I_STAT = %08x\n", machine().describe_context(), data); + m_iop_istat &= data; + check_iop_irq(); + break; + case 1: // I_MASK + logerror("%s: iop_intc_w: I_MASK = %08x\n", machine().describe_context(), data); + m_iop_imask = data; + check_iop_irq(); + break; + case 2: // I_ENABLE + logerror("%s: iop_intc_w: I_ENABLE = %08x\n", machine().describe_context(), data); + m_iop_ienable = BIT(data, 0); + check_iop_irq(); + break; + default: + logerror("%s: iop_intc_w: Unknown offset %08x = %08x\n", machine().describe_context(), 0x1f801070 + (offset << 2), data); + break; + } +} + 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); + //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); @@ -909,7 +1028,7 @@ WRITE32_MEMBER(ps2sony_state::intc_w) break; case 2: // I_MASK logerror("%s: intc_w: I_MASK = %08x\n", machine().describe_context(), data); - COMBINE_DATA(&m_imask); + m_imask ^= data & 0x7fff; check_irq0(); break; default: @@ -918,26 +1037,162 @@ WRITE32_MEMBER(ps2sony_state::intc_w) } } -READ32_MEMBER(ps2sony_state::sif_smflg_r) +READ32_MEMBER(ps2sony_state::iop_sif_r) { - uint32_t ret = 0x00010000; - logerror("%s: sif_smflg_r (%08x)\n", machine().describe_context(), ret); + uint32_t ret = 0; + switch (offset) + { + case 0: + ret = m_sif_ms_mailbox; + logerror("%s: iop_sif_r: SIF master->slave mailbox (%08x)\n", machine().describe_context(), ret); + break; + case 4: + ret = m_sif_sm_mailbox; + logerror("%s: iop_sif_r: SIF slave->master mailbox (%08x)\n", machine().describe_context(), ret); + break; + case 8: + ret = m_sif_ms_flag; + logerror("%s: iop_sif_r: SIF master->slave flag (%08x)\n", machine().describe_context(), ret); + break; + case 12: + ret = m_sif_sm_flag; + logerror("%s: iop_sif_r: SIF slave->master flag (%08x)\n", machine().describe_context(), ret); + break; + case 16: + ret = m_sif_ctrl | 0xf0000002; + logerror("%s: iop_sif_r: SIF control register (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: iop_sif_r: Unknown read (%08x)\n", machine().describe_context(), 0x1d000000 + (offset << 2)); + break; + } return ret; } -WRITE32_MEMBER(ps2sony_state::sif_smflg_w) +WRITE32_MEMBER(ps2sony_state::iop_sif_w) { - logerror("%s: sif_smflg_w = %08x\n", machine().describe_context(), data); + switch (offset) + { + case 4: + logerror("%s: iop_sif_w: SIF set slave->master mailbox (%08x)\n", machine().describe_context(), data); + m_sif_sm_mailbox = data; + break; + case 12: + if (m_sif_sm_flag == 0 && data != 0) + { + //raise_interrupt(INT_SBUS); + } + logerror("%s: iop_sif_w: SIF set slave->master flag (%08x)\n", machine().describe_context(), data); + m_sif_sm_flag |= data; + break; + default: + logerror("%s: iop_sif_w: Unknown write %08x = %08x\n", machine().describe_context(), 0x1d000000 + (offset << 2), data); + break; + } +} + +READ32_MEMBER(ps2sony_state::sif_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: + ret = m_sif_ms_mailbox; + logerror("%s: sif_r: SIF master->slave mailbox (%08x)\n", machine().describe_context(), ret); + break; + case 2: + ret = m_sif_sm_mailbox; + logerror("%s: sif_r: SIF slave->master mailbox (%08x)\n", machine().describe_context(), ret); + break; + case 4: + ret = m_sif_ms_flag; + logerror("%s: sif_r: SIF master->slave flag (%08x)\n", machine().describe_context(), ret); + break; + case 6: + ret = m_sif_sm_flag; + logerror("%s: sif_r: SIF slave->master flag (%08x)\n", machine().describe_context(), ret); + break; + case 8: + ret = m_sif_ctrl; + logerror("%s: sif_r: SIF control (%08x)\n", machine().describe_context(), ret); + break; + default: + logerror("%s: sif_r: Unknown (%08x)\n", machine().describe_context(), 0x1000f200 + (offset << 3)); + break; + } + return ret; +} + +WRITE32_MEMBER(ps2sony_state::sif_w) +{ + switch (offset) + { + case 0: + logerror("%s: sif_w: SIF set master->slave mailbox (%08x)\n", machine().describe_context(), data); + m_sif_ms_mailbox |= data; + break; + case 4: + logerror("%s: sif_w: SIF set master->slave flag (%08x)\n", machine().describe_context(), data); + m_sif_ms_flag |= data; + break; + case 6: + logerror("%s: sif_w: SIF clear slave->master flag (%08x)\n", machine().describe_context(), data); + m_sif_sm_flag &= ~data; + break; + case 8: + logerror("%s: sif_w: SIF control = %08x\n", machine().describe_context(), data); + m_sif_ctrl = data; // ?? + break; + default: + logerror("%s: sif_w: Unknown %08x = %08x\n", machine().describe_context(), 0x1000f200 + (offset << 3), data); + break; + } } void ps2sony_state::machine_start() { + save_item(NAME(m_gs_base_regs)); + save_item(NAME(m_gs_csr)); + save_item(NAME(m_gs_imr)); + save_item(NAME(m_gs_busdir)); + save_item(NAME(m_gs_sig_label_id)); + + save_item(NAME(m_unk_f430_reg)); + save_item(NAME(m_unk_f440_counter)); + save_item(NAME(m_unk_f440_reg)); + save_item(NAME(m_unk_f440_ret)); + + save_item(NAME(m_ipu_ctrl)); + save_item(NAME(m_ipu_in_fifo)); + save_item(NAME(m_ipu_in_fifo_index)); + save_item(NAME(m_ipu_out_fifo)); + save_item(NAME(m_ipu_out_fifo_index)); + + save_item(NAME(m_sif_ms_flag)); + save_item(NAME(m_sif_sm_flag)); + save_item(NAME(m_sif_ctrl)); + + save_item(NAME(m_dmac_d5_chcr)); + + save_item(NAME(m_istat)); + save_item(NAME(m_imask)); + + save_item(NAME(m_iop_istat)); + save_item(NAME(m_iop_imask)); + save_item(NAME(m_iop_ienable)); + 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_istat = 0; + m_imask = 0; + + m_iop_istat = 0; + m_iop_imask = 0; + m_unk_f430_reg = 0; m_unk_f440_reg = 0; m_unk_f440_ret = 0; @@ -956,6 +1211,14 @@ void ps2sony_state::machine_reset() m_gs_sig_label_id = 0ULL; m_vblank_timer->adjust(m_screen->time_until_pos(480), 1); + + m_sif_ms_mailbox = 0; + m_sif_sm_mailbox = 0; + m_sif_ms_flag = 0; + m_sif_sm_flag = 0; + m_sif_ctrl = 0; + + m_dmac_d5_chcr = 0; } TIMER_CALLBACK_MEMBER(ps2sony_state::vblank) @@ -963,15 +1226,15 @@ TIMER_CALLBACK_MEMBER(ps2sony_state::vblank) if (param) { // VBlank enter - printf("1 "); raise_interrupt(INT_VB_ON); + raise_iop_interrupt(0); m_vblank_timer->adjust(m_screen->time_until_pos(0), 0); } else { - printf("0 "); // VBlank exit raise_interrupt(INT_VB_OFF); + raise_iop_interrupt(11); m_vblank_timer->adjust(m_screen->time_until_pos(480), 1); } } @@ -981,6 +1244,28 @@ WRITE8_MEMBER(ps2sony_state::debug_w) printf("%c", (char)data); } +WRITE64_MEMBER(ps2sony_state::ee_iop_ram_w) +{ + const uint32_t offset_hi = (offset << 1); + const uint32_t offset_lo = (offset << 1) + 1; + const uint32_t mask_hi = (uint32_t)(mem_mask >> 32); + const uint32_t mask_lo = (uint32_t)mem_mask; + m_iop_ram[offset_hi] &= ~mask_hi; + m_iop_ram[offset_hi] |= (uint32_t)(data >> 32) & mask_hi; + m_iop_ram[offset_lo] &= ~mask_lo; + m_iop_ram[offset_lo] |= (uint32_t)data & mask_lo; +} + +READ64_MEMBER(ps2sony_state::ee_iop_ram_r) +{ + return ((uint64_t)m_iop_ram[offset << 1] << 32) | m_iop_ram[(offset << 1) + 1]; +} + +READ64_MEMBER(ps2sony_state::board_id_r) +{ + return 0x1234; +} + READ32_MEMBER(ps2sony_state::unk_f520_r) { // Unknown purpose - BIOS seems to expect this value initially @@ -1182,7 +1467,7 @@ void ps2sony_state::mem_map(address_map &map) 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(0x1000f200, 0x1000f24f).rw(FUNC(ps2sony_state::sif_r), FUNC(ps2sony_state::sif_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 @@ -1192,7 +1477,8 @@ void ps2sony_state::mem_map(address_map &map) 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(0x1c000000, 0x1c1fffff).rw(FUNC(ps2sony_state::ee_iop_ram_r), FUNC(ps2sony_state::ee_iop_ram_w)); // IOP has 2MB EDO RAM per Wikipedia, and writes go up to this point + map(0x1f803800, 0x1f803807).r(FUNC(ps2sony_state::board_id_r)); map(0x1fc00000, 0x1fffffff).rom().region("bios", 0); map(0x70000000, 0x70003fff).ram().share(m_sp_ram); // 16KB Scratchpad RAM @@ -1201,30 +1487,45 @@ void ps2sony_state::mem_map(address_map &map) 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); - + map(0x1d000000, 0x1d00004f).rw(FUNC(ps2sony_state::iop_sif_r), FUNC(ps2sony_state::iop_sif_w)); + map(0x1f402004, 0x1f402007).nopr(); + map(0x1f801070, 0x1f80107b).rw(FUNC(ps2sony_state::iop_intc_r), FUNC(ps2sony_state::iop_intc_w)); + map(0x1f8010f0, 0x1f8010f7).rw(m_iop_dma, FUNC(iop_dma_device::ctrl0_r), FUNC(iop_dma_device::ctrl0_w)); + map(0x1f801450, 0x1f801453).noprw(); + map(0x1f8014a0, 0x1f8014af).rw(m_iop_timer, FUNC(iop_timer_device::read), FUNC(iop_timer_device::write)); + map(0x1f801570, 0x1f801577).rw(m_iop_dma, FUNC(iop_dma_device::ctrl1_r), FUNC(iop_dma_device::ctrl1_w)); + map(0x1f801578, 0x1f80157b).noprw(); + map(0x1f802070, 0x1f802073).w(FUNC(ps2sony_state::iop_debug_w)).nopr(); + map(0x1fc00000, 0x1fffffff).rom().region("bios", 0); + map(0x1ffe0130, 0x1ffe0133).nopw(); } static INPUT_PORTS_START( ps2sony ) INPUT_PORTS_END MACHINE_CONFIG_START(ps2sony_state::ps2sony) - MCFG_DEVICE_ADD("maincpu", R5900LE, 294'912'000) + MCFG_DEVICE_ADD(m_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_ADD(m_iop, SONYPS2_IOP, XTAL(67'737'600)/2) MCFG_DEVICE_PROGRAM_MAP(iop_map) - MCFG_QUANTUM_TIME(attotime::from_hz(1000000)) + MCFG_QUANTUM_PERFECT_CPU("maincpu") + MCFG_QUANTUM_PERFECT_CPU("iop") + 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) + MCFG_DEVICE_ADD(m_iop_timer, SONYIOP_TIMER, XTAL(67'737'600)/2) + MCFG_IOP_TIMER_IRQ_CALLBACK(WRITELINE(*this, ps2sony_state, iop_timer_irq)) + + MCFG_DEVICE_ADD(m_iop_dma, SONYIOP_DMA, XTAL(67'737'600)/2) + /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) diff --git a/src/mame/machine/iopdma.cpp b/src/mame/machine/iopdma.cpp new file mode 100644 index 00000000000..552b2148f45 --- /dev/null +++ b/src/mame/machine/iopdma.cpp @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 IOP DMA device skeleton +* +* To Do: +* Everything +* +*/ + +#include "iopdma.h" + +DEFINE_DEVICE_TYPE(SONYIOP_DMA, iop_dma_device, "iopdma", "Sony IOP DMA") + +iop_dma_device::iop_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYIOP_DMA, tag, owner, clock) +{ +} + +void iop_dma_device::device_start() +{ +} + +void iop_dma_device::device_reset() +{ + m_dpcr[0] = 0; + m_dpcr[1] = 0; + m_dicr[0] = 0; + m_dicr[1] = 0; +} + +READ32_MEMBER(iop_dma_device::ctrl0_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: // 0x1f8010f0, DPCR + ret = m_dpcr[0]; + logerror("%s: ctrl0_r: DPCR (%08x)\n", machine().describe_context(), ret); + break; + case 1: // 0x1f8010f4, DICR + ret = m_dicr[0]; + logerror("%s: ctrl0_r: DICR (%08x)\n", machine().describe_context(), ret); + break; + default: + // Can't happen + break; + } + return ret; +} + +WRITE32_MEMBER(iop_dma_device::ctrl0_w) +{ + switch (offset) + { + case 0: // 0x1f8010f0, DPCR + logerror("%s: ctrl0_w: DPCR = %08x\n", machine().describe_context(), data); + set_dpcr(data, 0); + break; + case 1: // 0x1f8010f4, DICR + logerror("%s: ctrl0_w: DICR = %08x\n", machine().describe_context(), data); + set_dicr(data, 0); + break; + default: + // Can't happen + break; + } +} + +READ32_MEMBER(iop_dma_device::ctrl1_r) +{ + uint32_t ret = 0; + switch (offset) + { + case 0: // 0x1f801570, DPCR2 + ret = m_dpcr[1]; + logerror("%s: ctrl1_r: DPCR2 (%08x)\n", machine().describe_context(), ret); + break; + case 1: // 0x1f801574, DICR2 + ret = m_dicr[1]; + logerror("%s: ctrl1_r: DICR2 (%08x)\n", machine().describe_context(), ret); + break; + default: + // Can't happen + break; + } + return ret; +} + +WRITE32_MEMBER(iop_dma_device::ctrl1_w) +{ + switch (offset) + { + case 0: // 0x1f8010f0, DPCR + logerror("%s: ctrl1_w: DPCR2 = %08x\n", machine().describe_context(), data); + set_dpcr(data, 1); + break; + case 1: // 0x1f8010f4, DICR + logerror("%s: ctrl1_w: DICR2 = %08x\n", machine().describe_context(), data); + set_dicr(data, 1); + break; + default: + // Can't happen + break; + } +} + +void iop_dma_device::update_interrupts() +{ + // TODO +} + +void iop_dma_device::set_dpcr(uint32_t data, uint32_t index) +{ + m_dpcr[index] = data; + for (uint32_t channel = index*8, bit = 0; channel < index*8 + 8; channel++, bit += 4) + { + const uint8_t field = (data >> bit) & 0xf; + const bool was_enabled = m_channels[channel].m_enabled; + const bool is_enabled = BIT(field, 3); + m_channels[channel].m_enabled = is_enabled; + m_channels[channel].m_priority = field & 7; + if (!was_enabled && is_enabled) + { + // Check for running status? + } + } +} + +void iop_dma_device::set_dicr(uint32_t data, uint32_t index) +{ + m_dicr[index] = data; + m_int_ctrl[index].m_mask = (data >> 16) & 0x7f; + m_int_ctrl[index].m_status &= ~((data >> 24) & 0x7f); + m_int_ctrl[index].m_enabled = BIT(data, 23); + update_interrupts(); +} diff --git a/src/mame/machine/iopdma.h b/src/mame/machine/iopdma.h new file mode 100644 index 00000000000..f199e75df05 --- /dev/null +++ b/src/mame/machine/iopdma.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 IOP DMA device skeleton +* +* To Do: +* Everything +* +*/ + +#ifndef MAME_MACHINE_IOPDMA_H +#define MAME_MACHINE_IOPDMA_H + +#pragma once + +#include "emu.h" + +class iop_dma_device : public device_t +{ +public: + iop_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ32_MEMBER(ctrl0_r); + DECLARE_WRITE32_MEMBER(ctrl0_w); + DECLARE_READ32_MEMBER(ctrl1_r); + DECLARE_WRITE32_MEMBER(ctrl1_w); + +protected: + struct intctrl_t + { + uint8_t m_mask; + uint8_t m_status; + bool m_enabled; + }; + + struct channel_t + { + uint8_t m_priority; + bool m_enabled; + }; + + virtual void device_start() override; + virtual void device_reset() override; + + void set_dpcr(uint32_t data, uint32_t index); + void set_dicr(uint32_t data, uint32_t index); + void update_interrupts(); + + uint32_t m_dpcr[2]; + uint32_t m_dicr[2]; + channel_t m_channels[16]; + intctrl_t m_int_ctrl[2]; +}; + +DECLARE_DEVICE_TYPE(SONYIOP_DMA, iop_dma_device) + +#endif // MAME_MACHINE_IOPDMA_H
\ No newline at end of file diff --git a/src/mame/machine/ioptimer.cpp b/src/mame/machine/ioptimer.cpp new file mode 100644 index 00000000000..13246ae72f7 --- /dev/null +++ b/src/mame/machine/ioptimer.cpp @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 IOP Timer device skeleton +* +* To Do: +* Everything +* +*/ + +#include "ioptimer.h" + +DEFINE_DEVICE_TYPE(SONYIOP_TIMER, iop_timer_device, "ioptimer", "Sony IOP Timer") + +iop_timer_device::iop_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYIOP_TIMER, tag, owner, clock) + , m_compare_timer(nullptr) + , m_overflow_timer(nullptr) + , m_last_update_time(attotime::zero) + , m_elapsed_time(attotime::zero) + , m_zero_return(false) + , m_count(0) + , m_compare(0) + , m_gate_enable(false) + , m_gate_mode(GATM_LOW) + , m_cmp_int_enabled(false) + , m_cmp_int(false) + , m_ovf_int_enabled(false) + , m_ovf_int(false) + , m_ienable(false) + , m_int_cb(*this) +{ +} + +void iop_timer_device::device_start() +{ + m_int_cb.resolve_safe(); + + if (!m_compare_timer) + m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::compare), this)); + + if (!m_overflow_timer) + m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::overflow), this)); +} + +void iop_timer_device::device_reset() +{ + m_ctrl = 0; + + m_last_update_time = attotime::zero; + m_elapsed_time = attotime::zero; + + m_zero_return = false; + + m_count = 0; + m_compare = 0; + + m_gate_enable = false; + m_gate_mode = GATM_LOW; + + m_cmp_int_enabled = false; + m_cmp_int = false; + + m_ovf_int_enabled = false; + m_ovf_int = false; + + m_ienable = false; + + m_compare_timer->adjust(attotime::never); + m_overflow_timer->adjust(attotime::never); +} + +void iop_timer_device::update_gate() +{ + // TODO +} + +void iop_timer_device::update_interrupts() +{ + if (!m_int_cb.isnull()) + { + bool interrupt = m_ienable && ((m_ovf_int && m_ovf_int_enabled) || (m_cmp_int && m_cmp_int_enabled)); + m_int_cb(interrupt); + } +} + +void iop_timer_device::update_compare_timer() +{ + // TODO: Compare timer functionality is a total guess + if (!m_ienable || !m_cmp_int_enabled) + m_compare_timer->adjust(attotime::never); + m_compare_timer->adjust(attotime::from_ticks(m_compare - m_count, clock())); +} + +void iop_timer_device::update_overflow_timer() +{ + // TODO: Overflow timer functionality is not used yet, total guess + /* + uint32_t ticks = 0; + if (m_zero_return) + { + if (m_compare > m_count) + ticks = m_compare - m_count; + else + ticks = (uint32_t)(0x100000000ULL - (m_count - m_compare)); + } + else + { + ticks = (uint32_t)(0x100000000ULL - m_count); + } + */ + m_overflow_timer->adjust(attotime::never); +} + +void iop_timer_device::update_count() +{ + 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(clock()); + if (ticks > 0) + { + m_elapsed_time -= attotime::from_ticks(ticks, clock()); + m_count += ticks; + } +} + +void iop_timer_device::set_ctrl(uint32_t data) +{ + static const char *gatm_names[4] = { "low?", "reset+rising?", "reset+falling?", "reset+both?" }; + logerror("%s: set_ctrl: GATE=%d, GATM=%s, ZRET=%d\n", machine().describe_context(), data & CTRL_GATE, gatm_names[(data & CTRL_GATM) >> 1], (data & CTRL_ZRET) >> 3); + logerror("%s: CMPE=%d, OVFE=%d, REP_INT=%d, TOG_INT=%d\n", machine().describe_context(), (data & CTRL_CMPE) >> 4, (data & CTRL_OVFE) >> 5, (data & CTRL_REPI) >> 6, (data & CTRL_TOGI) >> 7); + + const uint32_t old = m_ctrl; + m_ctrl = data | CTRL_INTE; + const uint32_t changed = old ^ data; + + if (!changed) return; + + m_gate_enable = data & CTRL_GATE; + m_gate_mode = (timer_gate_mode)((data & CTRL_GATM) >> 1); + m_zero_return = (data & CTRL_ZRET) >> 3; + m_cmp_int_enabled = (data & CTRL_CMPE) >> 4; + m_ovf_int_enabled = (data & CTRL_OVFE) >> 5; + m_repeat_int = (data & CTRL_REPI) >> 6; + m_toggle_int = (data & CTRL_TOGI) >> 7; + m_ienable = 1; + + m_count = 0; + if (changed & CTRL_CMPE) + { + if (data & CTRL_CMPE) + update_compare_timer(); + else + m_compare_timer->adjust(attotime::never); + } + + if (changed & CTRL_OVFE) + { + if (data & CTRL_OVFE) + update_overflow_timer(); + else + m_overflow_timer->adjust(attotime::never); + } + + if (changed & CTRL_INTE) + { + update_interrupts(); + } +} + +TIMER_CALLBACK_MEMBER(iop_timer_device::compare) +{ + if (m_zero_return) + { + m_count = 0; // Guess + update_compare_timer(); + } + else + { + m_compare_timer->adjust(attotime::never); + } + + if (m_cmp_int_enabled) + m_cmp_int = 1; + + update_interrupts(); +} + +TIMER_CALLBACK_MEMBER(iop_timer_device::overflow) +{ + if (m_ovf_int_enabled) + m_ovf_int = 1; + + update_interrupts(); +} + +READ32_MEMBER(iop_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: IOP timer read: COUNT (%08x)\n", machine().describe_context(), ret); + break; + } + + case 0x01: + ret = m_ctrl | (m_ovf_int ? CTRL_OVFF : 0) | (m_cmp_int ? CTRL_CMPF : 0); + logerror("%s: IOP timer read: MODE (%08x)\n", machine().describe_context(), ret); + break; + + case 0x02: + ret = m_compare; + logerror("%s: IOP timer read: COMPARE (%08x)\n", machine().describe_context(), ret); + break; + + default: + break; + } + return ret; +} + +WRITE32_MEMBER(iop_timer_device::write) +{ + switch (offset) + { + case 0x00: + m_count = data; + logerror("%s: IOP timer write: COUNT = %08x\n", machine().describe_context(), data); + update_compare_timer(); + update_overflow_timer(); + break; + + case 0x01: + set_ctrl(data); + break; + + case 0x02: + { + logerror("%s: IOP timer write: COMPARE = %08x\n", machine().describe_context(), data); + if (m_compare == data) + break; + + m_compare = data; + if (!m_toggle_int) + m_ienable = true; + update_compare_timer(); + break; + } + + default: + break; + } +} diff --git a/src/mame/machine/ioptimer.h b/src/mame/machine/ioptimer.h new file mode 100644 index 00000000000..34137c2eab6 --- /dev/null +++ b/src/mame/machine/ioptimer.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony Playstation 2 IOP Timer device skeleton +* +* To Do: +* Everything +* +*/ + +#ifndef MAME_MACHINE_IOPTIMER_H +#define MAME_MACHINE_IOPTIMER_H + +#pragma once + +#include "emu.h" + +#define MCFG_IOP_TIMER_IRQ_CALLBACK(_write) \ + devcb = &downcast<iop_timer_device &>(*device).set_int_cb(DEVCB_##_write); + +class iop_timer_device : public device_t +{ +public: + iop_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template <class Object> devcb_base &set_int_cb(Object &&cb) { return m_int_cb.set_callback(std::forward<Object>(cb)); } + + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + +protected: + enum timer_ctrl_mask : uint32_t + { + CTRL_GATE = (1 << 0), + CTRL_GATM = (3 << 1), + CTRL_ZRET = (1 << 3), + CTRL_CMPE = (1 << 4), + CTRL_OVFE = (1 << 5), + CTRL_REPI = (1 << 6), + CTRL_TOGI = (1 << 7), + CTRL_INTE = (1 << 10), + CTRL_CMPF = (1 << 11), + CTRL_OVFF = (1 << 12), + }; + + enum timer_gate_mode : uint32_t + { + GATM_LOW = 0, + GATM_RISING, + GATM_FALLING, + GATM_BOTH + }; + + virtual void device_start() override; + virtual void device_reset() override; + + TIMER_CALLBACK_MEMBER(compare); + TIMER_CALLBACK_MEMBER(overflow); + + void set_ctrl(uint32_t data); + + void update_gate(); + void update_interrupts(); + + void update_compare_timer(); + void update_overflow_timer(); + + void update_count(); + + emu_timer *m_compare_timer; + emu_timer *m_overflow_timer; + + uint32_t m_ctrl; + + attotime m_last_update_time; + attotime m_elapsed_time; + bool m_zero_return; + uint32_t m_count; + uint32_t m_compare; + + bool m_gate_enable; + timer_gate_mode m_gate_mode; + + bool m_cmp_int_enabled; + bool m_cmp_int; + + bool m_ovf_int_enabled; + bool m_ovf_int; + + bool m_repeat_int; + bool m_toggle_int; + + bool m_ienable; + devcb_write_line m_int_cb; +}; + +DECLARE_DEVICE_TYPE(SONYIOP_TIMER, iop_timer_device) + +#endif // MAME_MACHINE_IOPTIMER_H
\ No newline at end of file diff --git a/src/mame/machine/ps2timer.cpp b/src/mame/machine/ps2timer.cpp index 2ba6668715d..ec3d6bb5f37 100644 --- a/src/mame/machine/ps2timer.cpp +++ b/src/mame/machine/ps2timer.cpp @@ -130,6 +130,7 @@ void ps2_timer_device::update_count() { m_elapsed_time -= attotime::from_ticks(ticks, frequency); m_count += ticks; + m_count &= 0xffff; } } |