summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/bbc/userport/pointer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/bbc/userport/pointer.cpp')
-rw-r--r--src/devices/bus/bbc/userport/pointer.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/devices/bus/bbc/userport/pointer.cpp b/src/devices/bus/bbc/userport/pointer.cpp
new file mode 100644
index 00000000000..a56f1f1378e
--- /dev/null
+++ b/src/devices/bus/bbc/userport/pointer.cpp
@@ -0,0 +1,277 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ AMX Mouse
+
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/AMX_Mouse.html
+
+ Marconi RB2 Tracker Ball
+
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Marconi_MarcusRB2.html
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_Trackerball.html
+
+ The Tracker Ball outputs are fed directly into the user port with the port defined as
+ an input. The CB1 and CB2 lines are used in conjunction with PB3 and PB4 for
+ sensing pulses and determining the direction of rotation of the ball.
+
+ The connections are:—
+ CB1 X1
+ CB2 Y2
+ PB0 Left switch button
+ PB1 Middle switch button
+ PB2 Right switch button
+ PB3 X2
+ PB4 Y1
+
+ Quadrature implementation derived from SmallyMouse2,
+ see https://github.com/simoninns/SmallyMouse2
+
+**********************************************************************/
+
+#include "emu.h"
+#include "pointer.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(BBC_AMXMOUSE, bbc_amxmouse_device, "bbc_amxmouse", "AMX Mouse (BBC Micro)")
+DEFINE_DEVICE_TYPE(BBC_M512MOUSE, bbc_m512mouse_device, "bbc_m512mouse", "Acorn Master 512 Mouse")
+DEFINE_DEVICE_TYPE(BBC_TRACKER, bbc_tracker_device, "bbc_tracker", "Marconi RB2 Tracker Ball")
+
+
+//-------------------------------------------------
+// INPUT_PORTS( amxmouse )
+//-------------------------------------------------
+
+static INPUT_PORTS_START( amxmouse )
+ PORT_START("POINTER_X")
+ PORT_BIT(0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("POINTER_Y")
+ PORT_BIT(0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("BUTTONS")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Mouse Left Button (Execute)") PORT_CODE(MOUSECODE_BUTTON1)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Mouse Middle Button (Move)") PORT_CODE(MOUSECODE_BUTTON3)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Mouse Right Button (Cancel)") PORT_CODE(MOUSECODE_BUTTON2)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// INPUT_PORTS( m512mouse )
+//-------------------------------------------------
+
+static INPUT_PORTS_START( m512mouse )
+ PORT_START("POINTER_X")
+ PORT_BIT(0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("POINTER_Y")
+ PORT_BIT(0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("BUTTONS")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Mouse Left Button") PORT_CODE(MOUSECODE_BUTTON1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Mouse Right Button") PORT_CODE(MOUSECODE_BUTTON2)
+INPUT_PORTS_END
+
+//-------------------------------------------------
+// INPUT_PORTS( tracker )
+//-------------------------------------------------
+
+static INPUT_PORTS_START( tracker )
+ PORT_START("POINTER_X")
+ PORT_BIT(0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("POINTER_Y")
+ PORT_BIT(0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_pointer_device, pointer_changed, 0) PORT_RESET
+
+ PORT_START("BUTTONS")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Left Button") PORT_CODE(MOUSECODE_BUTTON1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Middle Button") PORT_CODE(MOUSECODE_BUTTON3)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Right Button") PORT_CODE(MOUSECODE_BUTTON2)
+INPUT_PORTS_END
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor bbc_amxmouse_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( amxmouse );
+}
+
+ioport_constructor bbc_m512mouse_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( m512mouse );
+}
+
+ioport_constructor bbc_tracker_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( tracker );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// bbc_pointer_device - constructor
+//-------------------------------------------------
+
+bbc_pointer_device::bbc_pointer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_bbc_userport_interface(mconfig, *this)
+ , m_pointer_x(*this, "POINTER_X")
+ , m_pointer_y(*this, "POINTER_Y")
+ , m_buttons(*this, "BUTTONS")
+{
+}
+
+bbc_amxmouse_device::bbc_amxmouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_pointer_device(mconfig, BBC_AMXMOUSE, tag, owner, clock)
+{
+}
+
+bbc_m512mouse_device::bbc_m512mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_pointer_device(mconfig, BBC_M512MOUSE, tag, owner, clock)
+{
+}
+
+bbc_tracker_device::bbc_tracker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_pointer_device(mconfig, BBC_TRACKER, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void bbc_pointer_device::device_start()
+{
+ m_pointer_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bbc_pointer_device::pointer_poll), this));
+ m_pointer_timer->adjust(attotime::zero, 0, attotime::from_hz(1400));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void bbc_pointer_device::device_reset()
+{
+ m_xdir = 0;
+ m_ydir = 0;
+ m_direction_x = 0;
+ m_direction_y = 0;
+ m_distance_x = 0;
+ m_distance_y = 0;
+ m_phase_x = 0;
+ m_phase_y = 0;
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+INPUT_CHANGED_MEMBER(bbc_pointer_device::pointer_changed)
+{
+ int x = m_pointer_x->read();
+ int y = m_pointer_y->read();
+ x -= (x & 0x80) ? 0x100 : 0;
+ y -= (y & 0x80) ? 0x100 : 0;
+
+ // Set the mouse movement direction and record the movement units
+ m_direction_x = (x > 0) ? 1 : 0;
+ m_distance_x = abs(x);
+
+ m_direction_y = (y > 0) ? 1 : 0;
+ m_distance_y = abs(y);
+}
+
+TIMER_CALLBACK_MEMBER(bbc_pointer_device::pointer_poll)
+{
+ // Process X output
+ if (m_distance_x)
+ {
+ // Set the output pins according to the current phase
+ switch (m_phase_x)
+ {
+ case 0:
+ m_slot->cb1_w(1); // Set X1 to 1
+ break;
+ case 1:
+ m_xdir = 1; // Set X2 to 1
+ break;
+ case 2:
+ m_slot->cb1_w(0); // Set X1 to 0
+ break;
+ case 3:
+ m_xdir = 0; // Set X2 to 0
+ break;
+ }
+
+ // Change phase
+ if (m_direction_x == 0)
+ m_phase_x--;
+ else
+ m_phase_x++;
+
+ // Decrement the distance left to move
+ m_distance_x--;
+
+ // Range check the phase
+ m_phase_x &= 3;
+ }
+
+ // Process Y output
+ if (m_distance_y)
+ {
+ // Set the output pins according to the current phase
+ switch (m_phase_y)
+ {
+ case 3:
+ m_slot->cb2_w(0); // Set Y1 to 0
+ break;
+ case 2:
+ m_ydir = 0; // Set Y2 to 0
+ break;
+ case 1:
+ m_slot->cb2_w(1); // Set Y1 to 1
+ break;
+ case 0:
+ m_ydir = 1; // Set Y2 to 1
+ break;
+ }
+
+ // Change phase
+ if (m_direction_y == 0)
+ m_phase_y--;
+ else
+ m_phase_y++;
+
+ // Decrement the distance left to move
+ m_distance_y--;
+
+ // Range check the phase
+ m_phase_y &= 3;
+ }
+}
+
+READ8_MEMBER(bbc_amxmouse_device::pb_r)
+{
+ return (m_buttons->read() & 0xe0) | (m_xdir << 0) | (m_ydir << 2) | 0x1a;
+}
+
+READ8_MEMBER(bbc_m512mouse_device::pb_r)
+{
+ return (m_buttons->read() & 0x07) | (m_xdir << 3) | (m_ydir << 4) | 0xe0;
+}
+
+READ8_MEMBER(bbc_tracker_device::pb_r)
+{
+ return (m_buttons->read() & 0x07) | (m_xdir << 3) | (m_ydir << 4) | 0xe0;
+}