diff options
Diffstat (limited to 'src/devices/machine/iopsio2.cpp')
-rw-r--r-- | src/devices/machine/iopsio2.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/devices/machine/iopsio2.cpp b/src/devices/machine/iopsio2.cpp new file mode 100644 index 00000000000..a779d8d4631 --- /dev/null +++ b/src/devices/machine/iopsio2.cpp @@ -0,0 +1,309 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony PlayStation 2 IOP SIO2 device skeleton +* +* To Do: +* Everything +* +*/ + +#include "iopsio2.h" + +DEFINE_DEVICE_TYPE(SONYIOP_SIO2, iop_sio2_device, "iopsio2", "PlayStation 2 IOP SIO2") + +/*static*/ const size_t iop_sio2_device::BUFFER_SIZE = 512; // total guess based on memcard block size + +iop_sio2_device::iop_sio2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYIOP_SIO2, tag, owner, clock) + , m_intc(*this, finder_base::DUMMY_TAG) + , m_pad0(*this, finder_base::DUMMY_TAG) + , m_pad1(*this, finder_base::DUMMY_TAG) + , m_mc0(*this, finder_base::DUMMY_TAG) +{ +} + +void iop_sio2_device::device_start() +{ + if (!m_response_timer) + m_response_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_sio2_device::response_timer), this)); + + save_item(NAME(m_buffer)); + save_item(NAME(m_curr_byte)); + save_item(NAME(m_end_byte)); + save_item(NAME(m_ctrl)); + + save_item(NAME(m_unknown_0x6c)); + save_item(NAME(m_unknown_0x70)); + save_item(NAME(m_unknown_0x74)); + + save_item(NAME(m_cmdbuf)); + save_item(NAME(m_curr_port)); + save_item(NAME(m_cmd_size)); + save_item(NAME(m_cmd_length)); + save_item(NAME(m_databuf[0])); + save_item(NAME(m_databuf[1])); + + save_item(NAME(m_target_device)); +} + +void iop_sio2_device::device_reset() +{ + memset(m_buffer, 0, BUFFER_SIZE); + m_curr_byte = 0; + m_end_byte = 0; + m_ctrl = 0; + + m_unknown_0x6c = 0; + m_unknown_0x70 = 0xf; + m_unknown_0x74 = 0; + + memset(m_cmdbuf, 0, sizeof(uint32_t) * 16); + m_curr_port = 0; + m_cmd_size = 0; + m_cmd_length = 0; + memset(m_databuf, 0, sizeof(uint32_t) * 4 * 2); + + m_target_device = 0; +} + +READ32_MEMBER(iop_sio2_device::read) +{ + uint32_t ret = 0; + switch (offset) + { + case 0x64/4: + ret = receive(); + //logerror("%s: read: FIFO RECV %08x & %08x\n", machine().describe_context(), ret, mem_mask); + break; + case 0x68/4: // Control? + ret = m_ctrl; + //logerror("%s: read: CTRL %08x & %08x\n", machine().describe_context(), ret, mem_mask); + break; + case 0x6c/4: + ret = m_unknown_0x6c; + //logerror("%s: read: Unknown 0x6c (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + case 0x70/4: + ret = m_unknown_0x70; + //logerror("%s: read: Unknown 0x70 (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + case 0x74/4: + ret = m_unknown_0x74; + //logerror("%s: read: Unknown 0x74 (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + case 0x80/4: + // Unknown. Case is here to prevent log spam. + break; + default: + logerror("%s: read: Unknown offset %08x & %08x\n", machine().describe_context(), 0x1f808200 + (offset << 2), mem_mask); + break; + } + return ret; +} + +WRITE32_MEMBER(iop_sio2_device::write) +{ + switch (offset) + { + case 0x00/4: case 0x04/4: case 0x08/4: case 0x0c/4: case 0x10/4: case 0x14/4: case 0x18/4: case 0x1c/4: + case 0x20/4: case 0x24/4: case 0x28/4: case 0x2c/4: case 0x30/4: case 0x34/4: case 0x38/4: case 0x3c/4: + //logerror("%s: write: CMDBUF[%d] = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask); + COMBINE_DATA(&m_cmdbuf[offset]); + break; + case 0x40/4: case 0x44/4: + //logerror("%s: write: DATABUF[0][%d] = %08x & %08x\n", machine().describe_context(), offset - 0x40/4, data, mem_mask); + COMBINE_DATA(&m_databuf[0][offset - 0x40/4]); + break; + case 0x48/4: case 0x4c/4: + //logerror("%s: write: DATABUF[1][%d] = %08x & %08x\n", machine().describe_context(), offset - 0x48/4, data, mem_mask); + COMBINE_DATA(&m_databuf[1][offset - 0x48/4]); + break; + case 0x50/4: case 0x54/4: + //logerror("%s: write: DATABUF[2][%d] = %08x & %08x\n", machine().describe_context(), offset - 0x50/4, data, mem_mask); + COMBINE_DATA(&m_databuf[2][offset - 0x50/4]); + break; + case 0x58/4: case 0x5c/4: + //logerror("%s: write: DATABUF[3][%d] = %08x & %08x\n", machine().describe_context(), offset - 0x58/4, data, mem_mask); + COMBINE_DATA(&m_databuf[3][offset - 0x58/4]); + break; + case 0x60/4: + //logerror("%s: write: XMIT %08x & %08x\n", machine().describe_context(), data, mem_mask); + transmit_to_device_hack((uint8_t)data); + break; + case 0x68/4: // Control? + { + //logerror("%s: write: Control? %08x & %08x\n", machine().describe_context(), data, mem_mask); + //uint32_t old_ctrl = m_ctrl; + m_ctrl = data & ~CTRL_IRQ; + if (data & CTRL_IRQ) + { + m_intc->raise_interrupt(iop_intc_device::INT_SIO2); + } + else + { + m_curr_port = 0; + m_cmd_size = 0; + m_cmd_length = 0; + m_end_byte = 0; + m_curr_byte = 0; + m_target_device = 0; + } + break; + } + case 0x80/4: + // Unknown. Case is here to prevent log spam. + break; + default: + logerror("%s: write: Unknown offset %08x = %08x & %08x\n", machine().describe_context(), 0x1f808200 + (offset << 2), data, mem_mask); + break; + } +} + +uint8_t iop_sio2_device::receive() +{ + if (m_curr_byte >= m_end_byte) + { + //logerror("D:%d == E:%d, returning 0\n", m_curr_byte, m_end_byte); + return 0; + } + const uint8_t ret = m_buffer[m_curr_byte]; + //logerror("buf[%d] = %02x\n", m_curr_byte, ret); + m_curr_byte++; + if (m_curr_byte >= m_end_byte) + { + //logerror("Reached end of buffer, resetting to 0\n"); + m_curr_byte = 0; + m_end_byte = 0; + } + return ret; +} + +void iop_sio2_device::transmit(uint8_t data) +{ + //logerror("%s: Transmitting: %02x\n", machine().describe_context(), data); + if (!m_cmd_size && m_cmdbuf[m_curr_port]) + { + m_cmd_size = (m_cmdbuf[m_curr_port++] & 0x0001ff00) >> 8; + m_cmd_length = m_cmd_size; + } + + // TODO: Transmit serially to actual slot device at 250kHz-2MHz as needed + transmit_to_device_hack(data); +} + +ps2_pad_device* iop_sio2_device::pad(uint8_t port) +{ + return (port == 0) ? m_pad0.target() : m_pad1.target(); +} + +TIMER_CALLBACK_MEMBER(iop_sio2_device::response_timer) +{ + if (param < 2) + { + pad(param)->process_fifos(); + while (pad(param)->xmit_fifo_depth() && m_end_byte < BUFFER_SIZE) + { + receive_from_device_hack(pad(param)->xmit_fifo_pop()); + } + } + else + { + } +} + +void iop_sio2_device::transmit_to_device_hack(uint8_t data) +{ + if (m_target_device == 0) + { + select_device_hack(data); + } + + //bool cmd_complete = false; + if (m_cmd_size) + { + m_cmd_size--; + if (!m_cmd_size) + { + //cmd_complete = true; + } + } + + switch (m_target_device) + { + case ps2_pad_device::SIO_DEVICE_ID: + m_unknown_0x6c = 0x0001d100; // TODO: As above + receive_from_device_hack(0); + + /*m_unknown_0x6c = 0x00001100; // TODO: What do these bits mean and why does the code expect them? + pad(m_curr_port)->recv_fifo_push(data); + + if (!m_cmd_size) + { + m_response_timer->adjust(attotime::from_ticks(8*pad(m_curr_port)->xmit_fifo_depth(), 250'000), m_curr_port); + m_curr_port++; + }*/ + break; + + case ps2_mc_device::SIO_DEVICE_ID: + /*if (m_cmd_size || cmd_complete) + { + logerror("Pushing %02x to memory card, m_cmd_size is %d\n", data, m_cmd_size); + m_mc0->recv_fifo_push(data); + } + + if (cmd_complete) + { + logerror("Command is complete, processing fifos\n"); + m_unknown_0x6c = 0x00001100; + m_mc0->process_fifos(); + while (m_mc0->xmit_fifo_depth() && m_end_byte < BUFFER_SIZE) + { + logerror("xmit fifo is %d, end byte is %d\n", m_mc0->xmit_fifo_depth(), m_end_byte); + receive_from_device_hack(m_mc0->xmit_fifo_pop()); + } + m_unknown_0x74 = m_cmd_length; + }*/ + m_unknown_0x6c = 0x0001d100; // TODO: As above + receive_from_device_hack(0); + break; + + default: + m_unknown_0x6c = 0x0001d100; // TODO: As above + receive_from_device_hack(0); + logerror("%s: Unknown device selected, can't write data %02x\n", machine().describe_context(), data); + break; + } +} + +void iop_sio2_device::select_device_hack(uint8_t data) +{ + switch (data) + { + case ps2_pad_device::SIO_DEVICE_ID: + m_target_device = data; + // TODO: Select transmit frequency, etc. + //logerror("%s: Selecting transmit device: Pad\n", machine().describe_context()); + break; + case ps2_mc_device::SIO_DEVICE_ID: + m_target_device = data; + //logerror("%s: Selecting transmit device: Memcard\n", machine().describe_context()); + break; + + default: + m_target_device = 0xff; + //logerror("%s: Selecting transmit device: Unknown\n", machine().describe_context()); + break; + } +} + +void iop_sio2_device::receive_from_device_hack(uint8_t data) +{ + if (m_end_byte == BUFFER_SIZE) + { + return; + } + m_buffer[m_end_byte++] = data; + //logerror("%s: Receiving byte from device (new top: %d)\n", machine().describe_context(), m_end_byte); +} |