// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************
*
* Sony PlayStation 2 memory card device skeleton
*
* To Do:
* Everything
*
*/
#include "emu.h"
#include "ps2mc.h"
DEFINE_DEVICE_TYPE(SONYPS2_MC, ps2_mc_device, "ps2mc", "PlayStation 2 Memory Card")
/*static*/ const size_t ps2_mc_device::BUFFER_SIZE = 512; // Total guess
/*static*/ const uint8_t ps2_mc_device::DEFAULT_TERMINATOR = 0x55;
ps2_mc_device::ps2_mc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SONYPS2_MC, tag, owner, clock)
{
}
ps2_mc_device::~ps2_mc_device()
{
}
void ps2_mc_device::device_start()
{
save_item(NAME(m_recv_buf));
save_item(NAME(m_xmit_buf));
save_item(NAME(m_curr_recv));
save_item(NAME(m_curr_xmit));
save_item(NAME(m_end_recv));
save_item(NAME(m_end_xmit));
save_item(NAME(m_cmd));
save_item(NAME(m_cmd_size));
save_item(NAME(m_terminator));
save_item(NAME(m_status));
}
void ps2_mc_device::device_reset()
{
memset(m_recv_buf, 0, BUFFER_SIZE);
memset(m_xmit_buf, 0, BUFFER_SIZE);
m_curr_recv = 0;
m_curr_xmit = 0;
m_end_recv = 0;
m_end_xmit = 0;
m_cmd = 0;
m_cmd_size = 0;
m_terminator = DEFAULT_TERMINATOR;
m_status = 0;
}
void ps2_mc_device::recv_fifo_push(uint8_t data)
{
if (m_end_recv >= BUFFER_SIZE)
{
return;
}
m_recv_buf[m_end_recv++] = data;
//logerror("%s: Receiving %02x from SIO2, new top: %d\n", machine().describe_context(), data, m_end_recv);
}
void ps2_mc_device::xmit_fifo_push(uint8_t data)
{
if (m_end_xmit >= BUFFER_SIZE)
{
return;
}
//logerror("%s: Pushing %02x onto transmit FIFO\n", machine().describe_context(), data);
m_xmit_buf[m_end_xmit++] = data;
}
uint8_t ps2_mc_device::xmit_fifo_pop()
{
uint8_t ret = 0;
if (m_curr_xmit < m_end_xmit)
{
ret = m_xmit_buf[m_curr_xmit++];
}
if (m_curr_xmit >= m_end_xmit)
{
m_curr_xmit = 0;
m_end_xmit = 0;
}
return ret;
}
uint8_t ps2_mc_device::recv_fifo_pop()
{
uint8_t ret = 0;
if (m_curr_recv < m_end_recv)
{
ret = m_recv_buf[m_curr_recv++];
}
if (m_curr_recv >= m_end_recv)
{
m_curr_recv = 0;
m_end_recv = 0;
}
//logerror("recv_fifo_pop %02x, %d/%d\n", ret, m_curr_recv, m_end_recv);
return ret;
}
void ps2_mc_device::process_fifos()
{
m_status = 0;
m_cmd_size = 0;
while (recv_fifo_depth())
{
const uint8_t data = recv_fifo_pop();
m_cmd_size++;
if (m_cmd_size == 1)
{
if (data == SIO_DEVICE_ID)
{
xmit_fifo_push(0x2b);
}
else
{
logerror("%s: Unknkown command byte 1: %02x\n", machine().describe_context(), data);
}
}
else if (m_cmd_size == 2)
{
process_command(data);
}
}
m_curr_recv = 0;
m_end_recv = 0;
}
void ps2_mc_device::process_command(uint8_t data)
{
m_cmd = data;
switch (m_cmd)
{
case CMD_UNKNOWN_F3:
//logerror("%s: MC command: Unknown 0xf3\n", machine().describe_context());
cmd_init();
m_status = 0;
break;
case CMD_INIT:
//logerror("%s: MC command: Init (%02x)\n", machine().describe_context(), m_cmd);
cmd_init();
break;
case CMD_GET_TERM:
//logerror("%s: MC command: Get Terminator\n", machine().describe_context());
cmd_get_term();
break;
default:
logerror("%s: Unknown MC command: %02x\n", machine().describe_context(), m_cmd);
break;
}
}
void ps2_mc_device::cmd_init()
{
while (recv_fifo_depth())
{
recv_fifo_pop();
if (m_cmd_size == 2)
{
m_status = 0x8c;
xmit_fifo_push(m_terminator);
}
m_cmd_size++;
}
}
void ps2_mc_device::cmd_get_term()
{
while (recv_fifo_depth())
{
recv_fifo_pop();
if (m_cmd_size == 2)
{
m_status = 0x8b;
xmit_fifo_push(m_terminator);
xmit_fifo_push(0x55);
}
m_cmd_size++;
}
}