diff options
Diffstat (limited to 'src/devices/bus/sunmouse/hlemouse.cpp')
-rw-r--r-- | src/devices/bus/sunmouse/hlemouse.cpp | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/src/devices/bus/sunmouse/hlemouse.cpp b/src/devices/bus/sunmouse/hlemouse.cpp new file mode 100644 index 00000000000..4cf26a76651 --- /dev/null +++ b/src/devices/bus/sunmouse/hlemouse.cpp @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#include "emu.h" +#include "hlemouse.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_BIT (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_BIT) +//#define LOG_OUTPUT_STREAM std::cerr + +#include "logmacro.h" + +#define LOGBIT(...) LOGMASKED(LOG_BIT, __VA_ARGS__) + + +/* + Mostly compatible with the Mouse Systems "non-rotatable" protocol. + The only real difference is that the mouse may send a 3-byte frame + if the movement in each axis doesn't exceed the range -120 to 127 + counts (values in the range -128 to -121 are indistinguishable from + button states). +*/ + + +/*************************************************************************** + DEVICE TYPE GLOBALS +***************************************************************************/ + +DEFINE_DEVICE_TYPE_NS(SUN_1200BAUD_HLE_MOUSE, bus::sunmouse, hle_1200baud_device, "sunmouse_hle1200", "Sun Mouse (1200 Baud, HLE)") +DEFINE_DEVICE_TYPE_NS(SUN_4800BAUD_HLE_MOUSE, bus::sunmouse, hle_4800baud_device, "sunmouse_hle4800", "Sun Mouse (4800 Baud, HLE)") + +namespace bus { namespace sunmouse { + +namespace { + +INPUT_PORTS_START( mouse ) + PORT_START("BTN") + PORT_BIT( 0xfff8, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + + PORT_START("X") + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + + PORT_START("Y") + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) +INPUT_PORTS_END + + +uint8_t extract_delta_byte(int32_t &delta) +{ + int32_t const result(std::min<int32_t>(std::max<int32_t>(delta, -120), 127)); + delta -= result; + return uint8_t(int8_t(result)); +} + +} // anonymous namespace + + + +/*************************************************************************** + BASE HLE MOUSE DEVICE +***************************************************************************/ + +hle_device_base::hle_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + uint32_t clock, + unsigned multiplier) + : device_t(mconfig, type, tag, owner, clock) + , device_serial_interface(mconfig, *this) + , device_sun_mouse_port_interface(mconfig, *this) + , m_buttons(*this, "BTN") + , m_x_axis(*this, "X") + , m_y_axis(*this, "Y") + , m_multiplier(multiplier) + , m_x_delta(0) + , m_y_delta(0) + , m_x_val(0U) + , m_y_val(0U) + , m_btn_sent(0x00U) + , m_btn_val(0x00U) + , m_phase(0U) +{ +} + + +hle_device_base::~hle_device_base() +{ +} + + +INPUT_CHANGED_MEMBER( hle_device_base::input_changed ) +{ + if (is_transmit_register_empty()) + { + assert((0U == m_phase) || (3U == m_phase)); + + check_inputs(); + if (0U == m_phase) + { + if (m_x_delta || m_y_delta || (m_btn_sent != m_btn_val)) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + } + else if (m_x_delta || m_y_delta) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending X delta\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_x_delta)); + } + else if (m_btn_sent != m_btn_val) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + m_phase = 0U; + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + } + else + { + LOG("Ignoring input changed while transmit register not empty\n"); + } +} + + +ioport_constructor hle_device_base::device_input_ports() const +{ + return INPUT_PORTS_NAME(mouse); +} + + +void hle_device_base::device_start() +{ + save_item(NAME(m_x_delta)); + save_item(NAME(m_y_delta)); + save_item(NAME(m_x_val)); + save_item(NAME(m_y_val)); + save_item(NAME(m_phase)); + + set_data_frame(START_BIT_COUNT, DATA_BIT_COUNT, PARITY, STOP_BITS); + set_rate(BAUD * m_multiplier); + receive_register_reset(); + transmit_register_reset(); + + output_rxd(0); + + m_x_delta = 0; + m_y_delta = 0; + m_btn_sent = 0x00U; + m_phase = 0U; +} + + +void hle_device_base::device_reset() +{ + m_x_val = m_x_axis->read(); + m_y_val = m_y_axis->read(); + m_btn_val = m_buttons->read(); +} + + +void hle_device_base::tra_callback() +{ + int const bit(transmit_register_get_data_bit() ? 0 : 1); + LOGBIT("Send bit !%d\n", bit); + output_rxd(bit); +} + + +void hle_device_base::tra_complete() +{ + check_inputs(); + + if (4U <= m_phase) + m_phase = 0U; + else + ++m_phase; + + switch (m_phase) + { + // sent second Y delta - send button state if anything changed + case 0U: + if (m_x_delta || m_y_delta || (m_btn_sent != m_btn_val)) + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + else + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - nothing to send\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + } + break; + + // can wait after sending first Y delta + case 3U: + if (!m_x_delta && !m_y_delta && (m_btn_sent == m_btn_val)) + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - nothing to send\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + //break; uncommenting this causes problems with early versions of Solaris + } + case 1U: + LOG("Sent %s (B=%X->%x X=%d Y=%d) - sending X delta\n", + (1U == m_phase) ? "button state" : "Y delta", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_x_delta)); + break; + + // sent X delta - always follow with Y delta + case 2U: + case 4U: + LOG("Sent X delta (B=%X->%x X=%d Y=%d) - sending Y delta\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_y_delta)); + break; + } +} + + +void hle_device_base::check_inputs() +{ + // read new axis values and get difference + uint16_t const x_val(m_x_axis->read()); + uint16_t const y_val(m_y_axis->read()); + int16_t x_delta(x_val - m_x_val); + int16_t y_delta(y_val - m_y_val); + + // deal with wraparound + if (0x0800 <= x_delta) + x_delta -= 0x1000; + else if (-0x8000 >= x_delta) + x_delta += 0x1000; + if (0x0800 <= y_delta) + y_delta -= 0x1000; + else if (-0x8000 >= y_delta) + x_delta += 0x1000; + + // update state + m_x_delta += x_delta; + m_y_delta -= y_delta; + m_x_val = x_val; + m_y_val = y_val; + + // read new button values + m_btn_val = m_buttons->read(); +} + + + +/*************************************************************************** + 1200 BAUD HLE MOUSE DEVICE +***************************************************************************/ + +hle_1200baud_device::hle_1200baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : hle_device_base(mconfig, SUN_1200BAUD_HLE_MOUSE, tag, owner, clock, 8U) // FIXME: hack because z80scc isn't working properly +{ +} + + + +/*************************************************************************** + 4800 BAUD HLE MOUSE DEVICE +***************************************************************************/ + +hle_4800baud_device::hle_4800baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : hle_device_base(mconfig, SUN_4800BAUD_HLE_MOUSE, tag, owner, clock, 4U) +{ +} + +} } // namespace bus::sunmouse |