vsmile_ctrl: fix controller not working if buttons are pushed too early

This commit is contained in:
Vas Crabb 2019-01-21 23:33:13 +11:00
parent 979e3bf7f2
commit a16fb19be9
5 changed files with 273 additions and 56 deletions

View File

@ -1,29 +1,42 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Ryan Holtz // copyright-holders:Ryan Holtz, Vas Crabb
#include "emu.h" #include "emu.h"
#include "pad.h" #include "pad.h"
#include <algorithm>
//#define VERBOSE 1
#include "logmacro.h"
//************************************************************************** //**************************************************************************
// GLOBAL VARIABLES // GLOBAL VARIABLES
//************************************************************************** //**************************************************************************
DEFINE_DEVICE_TYPE(VSMILE_PAD, vsmile_pad_device, "vsmile_pad", "V.Smile Control Pad") DEFINE_DEVICE_TYPE(VSMILE_PAD, vsmile_pad_device, "vsmile_pad", "V.Smile Joystick")
//************************************************************************** //**************************************************************************
// V.Smile control pad // V.Smile control pad
//************************************************************************** //**************************************************************************
DECLARE_ENUM_BITWISE_OPERATORS(vsmile_pad_device::stale_inputs)
ALLOW_SAVE_TYPE(vsmile_pad_device::stale_inputs);
vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: vsmile_ctrl_device_base(mconfig, VSMILE_PAD, tag, owner, clock) : vsmile_ctrl_device_base(mconfig, VSMILE_PAD, tag, owner, clock)
, m_io_joy(*this, "JOY") , m_io_joy(*this, "JOY")
, m_io_colors(*this, "COLORS") , m_io_colors(*this, "COLORS")
, m_io_buttons(*this, "BUTTONS") , m_io_buttons(*this, "BUTTONS")
, m_idle_timer(nullptr) , m_idle_timer(nullptr)
, m_ctrl_probe_count(0U) , m_sent_joy(0x00U)
, m_sent_colors(0x00U)
, m_sent_buttons(0x00U)
, m_stale(STALE_ALL)
, m_active(false)
{ {
std::fill(std::begin(m_ctrl_probe_history), std::end(m_ctrl_probe_history), 0U);
} }
vsmile_pad_device::~vsmile_pad_device() vsmile_pad_device::~vsmile_pad_device()
@ -36,27 +49,104 @@ void vsmile_pad_device::device_start()
m_idle_timer = machine().scheduler().timer_alloc( m_idle_timer = machine().scheduler().timer_alloc(
timer_expired_delegate(FUNC(vsmile_pad_device::handle_idle), this)); timer_expired_delegate(FUNC(vsmile_pad_device::handle_idle), this));
m_idle_timer->adjust(attotime::from_hz(1)); m_idle_timer->adjust(attotime::from_seconds(1));
m_sent_joy = 0x00U;
m_sent_colors = 0x00U;
m_sent_buttons = 0x00U;
m_stale = STALE_ALL;
m_active = false;
save_item(NAME(m_sent_joy));
save_item(NAME(m_sent_colors));
save_item(NAME(m_sent_buttons));
save_item(NAME(m_stale));
save_item(NAME(m_active));
save_item(NAME(m_ctrl_probe_history)); save_item(NAME(m_ctrl_probe_history));
save_item(NAME(m_ctrl_probe_count));
} }
void vsmile_pad_device::tx_complete() void vsmile_pad_device::tx_complete()
{ {
m_idle_timer->adjust(attotime::from_hz(1)); // update joystick
if ((m_stale & STALE_JOY) != STALE_NONE)
{
m_sent_joy = m_io_joy->read();
if ((m_stale & STALE_UP_DOWN) != STALE_NONE)
{
if (BIT(m_sent_joy, 0))
uart_tx_fifo_push(0x87); // up
else if (BIT(m_sent_joy, 1))
uart_tx_fifo_push(0x8f); // down
else
uart_tx_fifo_push(0x80);
}
if ((m_stale & STALE_LEFT_RIGHT) != STALE_NONE)
{
if (BIT(m_sent_joy, 2))
uart_tx_fifo_push(0xcf); // left
else if (BIT(m_sent_joy, 3))
uart_tx_fifo_push(0xc7); // right
else
uart_tx_fifo_push(0xc0);
}
}
// update colors
if ((m_stale & STALE_COLORS) != STALE_NONE)
{
m_sent_colors = m_io_colors->read();
uart_tx_fifo_push(0x90 | m_sent_colors);
}
// update buttons
if ((m_stale & STALE_BUTTONS) != STALE_NONE)
{
m_sent_buttons = m_io_buttons->read();
if (((m_stale & STALE_OK) != STALE_NONE) && BIT(m_sent_buttons, 0))
uart_tx_fifo_push(0xa1);
if (((m_stale & STALE_QUIT) != STALE_NONE) && BIT(m_sent_buttons, 1))
uart_tx_fifo_push(0xa2);
if (((m_stale & STALE_HELP) != STALE_NONE) && BIT(m_sent_buttons, 2))
uart_tx_fifo_push(0xa3);
if (((m_stale & STALE_ABC) != STALE_NONE) && BIT(m_sent_buttons, 3))
uart_tx_fifo_push(0xa4);
if (!m_sent_buttons)
uart_tx_fifo_push(0xa0);
}
// if nothing happens in the next second we'll queue a keep-alive
if (!m_active)
LOG("entered active state\n");
m_idle_timer->adjust(attotime::from_seconds(1));
m_active = true;
m_stale = STALE_NONE;
}
void vsmile_pad_device::tx_timeout()
{
if (m_active)
{
m_idle_timer->adjust(attotime::from_seconds(1));
m_active = false;
m_stale = STALE_ALL;
LOG("left active state\n");
}
} }
void vsmile_pad_device::rx_complete(uint8_t data, bool select) void vsmile_pad_device::rx_complete(uint8_t data, bool select)
{ {
if (select) if (select)
{ {
//printf("%s Receiving: %02x\n", tag(), data); if (((data & 0xf0) == 0x70) || ((data & 0xf0) == 0xb0))
if ((data >> 4) == 7 || (data >> 4) == 11)
{ {
m_ctrl_probe_history[0] = m_ctrl_probe_history[1]; m_ctrl_probe_history[0] = m_ctrl_probe_history[1];
m_ctrl_probe_history[1] = data; m_ctrl_probe_history[1] = data;
const uint8_t response = ((m_ctrl_probe_history[0] + m_ctrl_probe_history[1] + 0x0f) & 0x0f) ^ 0x05; uint8_t const response = ((m_ctrl_probe_history[0] + m_ctrl_probe_history[1] + 0x0f) & 0x0f) ^ 0x05;
LOG(
"received probe %02X, %02X, sending response %02X\n",
m_ctrl_probe_history[0],
m_ctrl_probe_history[1],
0xb0 | response);
uart_tx_fifo_push(0xb0 | response); uart_tx_fifo_push(0xb0 | response);
} }
} }
@ -70,67 +160,109 @@ void vsmile_pad_device::uart_tx_fifo_push(uint8_t data)
TIMER_CALLBACK_MEMBER(vsmile_pad_device::handle_idle) TIMER_CALLBACK_MEMBER(vsmile_pad_device::handle_idle)
{ {
LOG("idle timer expired, sending keep-alive 55\n");
queue_tx(0x55); queue_tx(0x55);
} }
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_joy_changed) INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_joy_changed)
{ {
const uint8_t value = m_io_joy->read(); if (m_active)
{
if (BIT(value, 2)) if (!is_tx_empty())
uart_tx_fifo_push(0xcf); {
else if (BIT(value, 3)) LOG("joy changed while transmission in progress, marking stale\n");
uart_tx_fifo_push(0xc7); m_stale |= stale_inputs(uintptr_t(param));
}
else else
uart_tx_fifo_push(0xc0); {
uint8_t const joy = m_io_joy->read();
if (BIT(value, 0)) if ((joy ^ m_sent_joy) & 0x03)
uart_tx_fifo_push(0x87); {
else if (BIT(value, 1)) if (BIT(joy, 0))
uart_tx_fifo_push(0x8f); uart_tx_fifo_push(0x87); // up
else if (BIT(joy, 1))
uart_tx_fifo_push(0x8f); // down
else else
uart_tx_fifo_push(0x80); uart_tx_fifo_push(0x80);
} }
if ((joy ^ m_sent_joy) & 0x0c)
{
if (BIT(joy, 2))
uart_tx_fifo_push(0xcf); // left
else if (BIT(joy, 3))
uart_tx_fifo_push(0xc7); // right
else
uart_tx_fifo_push(0xc0);
}
m_sent_joy = joy;
}
}
}
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_color_changed) INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_color_changed)
{ {
if (m_active)
{
if (!is_tx_empty())
{
LOG("colors changed while transmission in progress, marking stale\n");
m_stale |= STALE_COLORS;
}
else
{
m_sent_colors = m_io_colors->read();
uart_tx_fifo_push(0x90 | m_io_colors->read()); uart_tx_fifo_push(0x90 | m_io_colors->read());
} }
}
}
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_button_changed) INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_button_changed)
{ {
const uint8_t value = m_io_buttons->read(); if (m_active)
const size_t bit = reinterpret_cast<size_t>(param);
if (BIT(value, bit))
{ {
uart_tx_fifo_push(0xa1 + (uint8_t)bit); if (!is_tx_empty())
{
LOG("buttons changed while transmission in progress, marking stale\n");
m_stale |= stale_inputs(uintptr_t(param));
} }
else else
{ {
uint8_t const buttons = m_io_buttons->read();
if (BIT((m_sent_buttons ^ buttons) & buttons, 0))
uart_tx_fifo_push(0xa1);
if (BIT((m_sent_buttons ^ buttons) & buttons, 1))
uart_tx_fifo_push(0xa2);
if (BIT((m_sent_buttons ^ buttons) & buttons, 2))
uart_tx_fifo_push(0xa3);
if (BIT((m_sent_buttons ^ buttons) & buttons, 3))
uart_tx_fifo_push(0xa4);
if (!buttons)
uart_tx_fifo_push(0xa0); uart_tx_fifo_push(0xa0);
m_sent_buttons = buttons;
}
} }
} }
static INPUT_PORTS_START( vsmile_pad ) static INPUT_PORTS_START( vsmile_pad )
PORT_START("JOY") PORT_START("JOY")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, 0) PORT_NAME("Joypad Up") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_UP_DOWN) PORT_NAME("Joypad Up")
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, 0) PORT_NAME("Joypad Down") PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_UP_DOWN) PORT_NAME("Joypad Down")
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, 0) PORT_NAME("Joypad Left") PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_LEFT_RIGHT) PORT_NAME("Joypad Left")
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, 0) PORT_NAME("Joypad Right") PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_LEFT_RIGHT) PORT_NAME("Joypad Right")
PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_START("COLORS") PORT_START("COLORS")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, 0) PORT_NAME("Green") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Green")
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, 0) PORT_NAME("Blue") PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Blue")
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, 0) PORT_NAME("Yellow") PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Yellow")
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, 0) PORT_NAME("Red") PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Red")
PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_START("BUTTONS") PORT_START("BUTTONS")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, 0) PORT_NAME("OK") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_OK) PORT_NAME("OK")
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, 1) PORT_NAME("Quit") PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_QUIT) PORT_NAME("Quit")
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, 2) PORT_NAME("Help") PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_HELP) PORT_NAME("Help")
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, 3) PORT_NAME("ABC") PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_ABC) PORT_NAME("ABC")
PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END INPUT_PORTS_END

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Ryan Holtz // copyright-holders:Ryan Holtz, Vas Crabb
#ifndef MAME_BUS_VSMILE_PAD_H #ifndef MAME_BUS_VSMILE_PAD_H
#define MAME_BUS_VSMILE_PAD_H #define MAME_BUS_VSMILE_PAD_H
@ -16,10 +16,27 @@
class vsmile_pad_device : public vsmile_ctrl_device_base class vsmile_pad_device : public vsmile_ctrl_device_base
{ {
public: public:
enum stale_inputs : uint8_t
{
STALE_NONE = 0U,
STALE_LEFT_RIGHT = 1U << 0,
STALE_UP_DOWN = 1U << 1,
STALE_COLORS = 1U << 2,
STALE_OK = 1U << 3,
STALE_QUIT = 1U << 4,
STALE_HELP = 1U << 5,
STALE_ABC = 1U << 6,
STALE_JOY = STALE_LEFT_RIGHT | STALE_UP_DOWN,
STALE_BUTTONS = STALE_OK | STALE_QUIT | STALE_HELP | STALE_ABC,
STALE_ALL = STALE_JOY | STALE_COLORS | STALE_BUTTONS
};
// construction/destruction // construction/destruction
vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U); vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U);
virtual ~vsmile_pad_device(); virtual ~vsmile_pad_device();
// input handlers
DECLARE_INPUT_CHANGED_MEMBER(pad_joy_changed); DECLARE_INPUT_CHANGED_MEMBER(pad_joy_changed);
DECLARE_INPUT_CHANGED_MEMBER(pad_color_changed); DECLARE_INPUT_CHANGED_MEMBER(pad_color_changed);
DECLARE_INPUT_CHANGED_MEMBER(pad_button_changed); DECLARE_INPUT_CHANGED_MEMBER(pad_button_changed);
@ -31,6 +48,7 @@ protected:
// vsmile_ctrl_device_base implementation // vsmile_ctrl_device_base implementation
virtual void tx_complete() override; virtual void tx_complete() override;
virtual void tx_timeout() override;
virtual void rx_complete(uint8_t data, bool cts) override; virtual void rx_complete(uint8_t data, bool cts) override;
private: private:
@ -44,8 +62,10 @@ private:
emu_timer *m_idle_timer; emu_timer *m_idle_timer;
uint8_t m_sent_joy, m_sent_colors, m_sent_buttons;
stale_inputs m_stale;
bool m_active;
uint8_t m_ctrl_probe_history[2]; uint8_t m_ctrl_probe_history[2];
uint8_t m_ctrl_probe_count;
}; };

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Ryan Holtz // copyright-holders:Vas Crabb
#include "emu.h" #include "emu.h"
#include "vsmile_ctrl.h" #include "vsmile_ctrl.h"
@ -7,6 +7,9 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
//#define VERBOSE 1
#include "logmacro.h"
//************************************************************************** //**************************************************************************
// GLOBAL VARIABLES // GLOBAL VARIABLES
@ -125,6 +128,7 @@ vsmile_ctrl_device_base::vsmile_ctrl_device_base(
: device_t(mconfig, type, tag, owner, clock) : device_t(mconfig, type, tag, owner, clock)
, device_vsmile_ctrl_interface(mconfig, *this) , device_vsmile_ctrl_interface(mconfig, *this)
, m_tx_timer(nullptr) , m_tx_timer(nullptr)
, m_rts_timer(nullptr)
, m_tx_fifo_head(0U) , m_tx_fifo_head(0U)
, m_tx_fifo_tail(0U) , m_tx_fifo_tail(0U)
, m_tx_fifo_empty(true) , m_tx_fifo_empty(true)
@ -144,6 +148,10 @@ void vsmile_ctrl_device_base::device_start()
m_tx_timer = machine().scheduler().timer_alloc( m_tx_timer = machine().scheduler().timer_alloc(
timer_expired_delegate(FUNC(vsmile_ctrl_device_base::tx_timer_expired), this)); timer_expired_delegate(FUNC(vsmile_ctrl_device_base::tx_timer_expired), this));
// allocate a timer for RTS timeouts
m_rts_timer = machine().scheduler().timer_alloc(
timer_expired_delegate(FUNC(vsmile_ctrl_device_base::rts_timer_expired), this));
// start with transmit queue empty // start with transmit queue empty
m_tx_fifo_head = m_tx_fifo_tail = 0U; m_tx_fifo_head = m_tx_fifo_tail = 0U;
m_tx_fifo_empty = true; m_tx_fifo_empty = true;
@ -162,7 +170,10 @@ bool vsmile_ctrl_device_base::queue_tx(uint8_t data)
// return false on overrun and drop byte // return false on overrun and drop byte
bool const was_empty(m_tx_fifo_empty); bool const was_empty(m_tx_fifo_empty);
if (!was_empty && (m_tx_fifo_head == m_tx_fifo_tail)) if (!was_empty && (m_tx_fifo_head == m_tx_fifo_tail))
{
LOG("discarding byte %02X because FIFO is full (length %u, Tx %sactive)\n", data, ARRAY_LENGTH(m_tx_fifo), m_tx_active ? "" : "in");
return false; return false;
}
// queue the byte // queue the byte
m_tx_fifo[m_tx_fifo_tail] = data; m_tx_fifo[m_tx_fifo_tail] = data;
@ -175,9 +186,20 @@ bool vsmile_ctrl_device_base::queue_tx(uint8_t data)
rts_out(1); rts_out(1);
if (m_select) if (m_select)
{ {
LOG("transmitting byte %02X immediately (Tx was %sactive)\n", data, m_tx_active ? "" : "in");
m_tx_active = true; m_tx_active = true;
m_tx_timer->adjust(attotime::from_hz(9600 / 10)); m_tx_timer->adjust(attotime::from_hz(9600 / 10));
} }
else
{
LOG("asserting RTS to transmit byte %02X\n", data);
m_rts_timer->adjust(attotime::from_msec(500));
}
}
else
{
unsigned const fifo_used((m_tx_fifo_tail + ARRAY_LENGTH(m_tx_fifo) - m_tx_fifo_head) % ARRAY_LENGTH(m_tx_fifo));
LOG("queued byte %02X (%u bytes queued, Tx %sactive)\n", data, fifo_used, m_tx_active ? "" : "in");
} }
// data was queued // data was queued
@ -186,16 +208,27 @@ bool vsmile_ctrl_device_base::queue_tx(uint8_t data)
void vsmile_ctrl_device_base::select_w(int state) void vsmile_ctrl_device_base::select_w(int state)
{ {
m_select = bool(state); if (bool(state) != m_select)
if (m_select && !m_tx_fifo_empty && !m_tx_active)
{ {
if (state && !m_tx_fifo_empty && !m_tx_active)
{
m_rts_timer->reset();
unsigned const fifo_used((m_tx_fifo_tail + ARRAY_LENGTH(m_tx_fifo) - m_tx_fifo_head) % ARRAY_LENGTH(m_tx_fifo));
LOG("select asserted, starting transmission (%u bytes queued)\n", fifo_used);
m_tx_active = true; m_tx_active = true;
m_tx_timer->adjust(attotime::from_hz(9600 / 10)); m_tx_timer->adjust(attotime::from_hz(9600 / 10));
} }
else
{
LOG("select %sasserted (Tx %sactive)\n", state ? "" : "de", m_tx_active ? "" : "in");
}
m_select = bool(state);
}
} }
void vsmile_ctrl_device_base::data_w(uint8_t data) void vsmile_ctrl_device_base::data_w(uint8_t data)
{ {
LOG("received byte %02X (select %sasserted, Tx %sactive)\n", data, m_select ? "" : "de", m_tx_active ? "" : "in");
rx_complete(data, m_select); rx_complete(data, m_select);
} }
@ -213,21 +246,50 @@ TIMER_CALLBACK_MEMBER(vsmile_ctrl_device_base::tx_timer_expired)
// if queue is drained give implmentation a chance to queue more before dropping RTS // if queue is drained give implmentation a chance to queue more before dropping RTS
if (m_tx_fifo_empty) if (m_tx_fifo_empty)
{
LOG("transmitted byte %02X, queue empty (select %sasserted)\n", data, m_select ? "" : "de");
tx_complete(); tx_complete();
}
else
{
unsigned const fifo_used((m_tx_fifo_tail + ARRAY_LENGTH(m_tx_fifo) - m_tx_fifo_head) % ARRAY_LENGTH(m_tx_fifo));
LOG("transmitted byte %02X (%u bytes queued, select %sasserted)\n", data, fifo_used, m_select ? "" : "de");
}
// drop RTS if no more data, otherwise keep transmitting if CTS is still high // drop RTS if no more data, otherwise keep transmitting if CTS is still high
if (m_tx_fifo_empty) if (m_tx_fifo_empty)
{ {
LOG("nothing to transmit, deasserting RTS\n");
m_tx_active = false; m_tx_active = false;
rts_out(0); rts_out(0);
} }
else if (m_select) else if (m_select)
{ {
LOG("select asserted, transmitting next byte %02X\n", m_tx_fifo[m_tx_fifo_head]);
m_tx_timer->adjust(attotime::from_hz(9600 / 10)); m_tx_timer->adjust(attotime::from_hz(9600 / 10));
} }
else else
{ {
LOG("select deasserted, waiting to transmit\n");
m_tx_active = false; m_tx_active = false;
m_rts_timer->adjust(attotime::from_msec(500));
}
}
TIMER_CALLBACK_MEMBER(vsmile_ctrl_device_base::rts_timer_expired)
{
assert(!m_tx_fifo_empty);
assert(!m_tx_active);
// clear out anything queued and let the implementation deal with it
if (!m_tx_fifo_empty)
{
unsigned const fifo_used((m_tx_fifo_tail + ARRAY_LENGTH(m_tx_fifo) - m_tx_fifo_head) % ARRAY_LENGTH(m_tx_fifo));
LOG("timeout waiting for select after asserting RTS (%u bytes queued)\n", fifo_used);
m_tx_fifo_head = m_tx_fifo_tail = 0U;
m_tx_fifo_empty = true;
tx_timeout();
} }
} }
@ -236,5 +298,5 @@ TIMER_CALLBACK_MEMBER(vsmile_ctrl_device_base::tx_timer_expired)
void vsmile_controllers(device_slot_interface &device) void vsmile_controllers(device_slot_interface &device)
{ {
device.option_add("pad", VSMILE_PAD); device.option_add("joy", VSMILE_PAD);
} }

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Ryan Holtz // copyright-holders:Vas Crabb
#ifndef MAME_BUS_VSMILE_VSMILE_CTRL_H #ifndef MAME_BUS_VSMILE_VSMILE_CTRL_H
#define MAME_BUS_VSMILE_VSMILE_CTRL_H #define MAME_BUS_VSMILE_VSMILE_CTRL_H
@ -103,6 +103,7 @@ protected:
virtual void device_start() override; virtual void device_start() override;
// UART simulation helpers // UART simulation helpers
bool is_tx_empty() const { return m_tx_fifo_empty; }
bool queue_tx(uint8_t data); bool queue_tx(uint8_t data);
private: private:
@ -112,12 +113,14 @@ private:
// UART simulation handlers // UART simulation handlers
virtual void tx_complete() = 0; virtual void tx_complete() = 0;
virtual void tx_timeout() = 0;
virtual void rx_complete(uint8_t data, bool select) = 0; virtual void rx_complete(uint8_t data, bool select) = 0;
// internal helpers // internal helpers
TIMER_CALLBACK_MEMBER(tx_timer_expired); TIMER_CALLBACK_MEMBER(tx_timer_expired);
TIMER_CALLBACK_MEMBER(rts_timer_expired);
emu_timer *m_tx_timer; emu_timer *m_tx_timer, *m_rts_timer;
uint8_t m_tx_fifo[32]; uint8_t m_tx_fifo[32];
uint8_t m_tx_fifo_head, m_tx_fifo_tail; uint8_t m_tx_fifo_head, m_tx_fifo_tail;

View File

@ -435,7 +435,7 @@ void vsmile_state::vsmile(machine_config &config)
m_spg->portc_out().set(FUNC(vsmile_state::portc_w)); m_spg->portc_out().set(FUNC(vsmile_state::portc_w));
m_spg->uart_tx().set(FUNC(vsmile_state::uart_rx)); m_spg->uart_tx().set(FUNC(vsmile_state::uart_rx));
VSMILE_CTRL_PORT(config, m_ctrl[0], vsmile_controllers, "pad"); VSMILE_CTRL_PORT(config, m_ctrl[0], vsmile_controllers, "joy");
m_ctrl[0]->rts_cb().set(FUNC(vsmile_state::ctrl_rts_w<0>)); m_ctrl[0]->rts_cb().set(FUNC(vsmile_state::ctrl_rts_w<0>));
m_ctrl[0]->data_cb().set(FUNC(vsmile_state::ctrl_tx_w)); m_ctrl[0]->data_cb().set(FUNC(vsmile_state::ctrl_tx_w));