summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/iopsio2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/iopsio2.cpp')
-rw-r--r--src/devices/machine/iopsio2.cpp309
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);
+}