summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2026-04-12 23:00:45 +0200
committer hap <happppp@users.noreply.github.com>2026-04-12 23:01:02 +0200
commit149871cb7097679ee67236324ecca65631fd82ae (patch)
tree16ce62fb1f14a051d311bdf79935fc2477016f1f
parent0f5872aa2eeb46ae87c6a715946cce1704749d84 (diff)
grandmas/emirage: move chessboard to a device
-rw-r--r--scripts/src/machine.lua12
-rw-r--r--src/devices/machine/gmboard.cpp356
-rw-r--r--src/devices/machine/gmboard.h86
-rw-r--r--src/devices/machine/smartboard.cpp7
-rw-r--r--src/mame/excalibur/mirage.cpp329
-rw-r--r--src/mame/hegenerglaser/mmboard.h2
-rw-r--r--src/mame/layout/excal_mirage.lay64
-rw-r--r--src/mame/miltonbradley/grandmaster.cpp315
8 files changed, 521 insertions, 650 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index 5cd973dc5b1..874842acad6 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -2264,6 +2264,18 @@ end
---------------------------------------------------
--
+--@src/devices/machine/gmboard.h,MACHINES["MB_GMBOARD"] = true
+---------------------------------------------------
+
+if MACHINES["MB_GMBOARD"] then
+ files {
+ MAME_DIR .. "src/devices/machine/gmboard.cpp",
+ MAME_DIR .. "src/devices/machine/gmboard.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/machine/mb14241.h,MACHINES["MB14241"] = true
---------------------------------------------------
diff --git a/src/devices/machine/gmboard.cpp b/src/devices/machine/gmboard.cpp
new file mode 100644
index 00000000000..0ba17d6bab1
--- /dev/null
+++ b/src/devices/machine/gmboard.cpp
@@ -0,0 +1,356 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+Milton Bradley Grand Master motorized self-moving chessboard
+
+Electronic chessboard with motors underneath, that move a magnet around for
+automatically moving chesspieces (each piece has a magnet underneath).
+
+Used in:
+- Milton Bradley Grand Master
+- Fidelity Phantom / Chesster Phantom
+- Excalibur Mirage
+- Excalibur Phantom Force
+
+Hardware notes:
+- electronic chessboard, with room on each side for captured pieces
+- X/Y plotter motors, electromagnet (optionally including a hall affect sensor)
+
+Concept/design by Milton Bradley, for use in the Grand Master. Fidelity licensed
+or bought the design, and applied it nearly unchanged to Fidelity Phantom. Years
+later, the ex chief engineer of by then defunct Fidelity used the same technology
+while working for Excalibur.
+
+TODO:
+- optionally change output finders to callbacks, currently not needed
+- sensorboard undo buffer goes out of control, probably not worth solving this issue
+
+BTANB:
+- Motors gradually drift in Mirage, causing it to place/pick up pieces off-center.
+ It recalibrates itself once in a while but it's not enough. MAME's sensorboard
+ device can't deal with it, so there's a workaround (see realign_magnet_pos).
+ The programmer anecdotally blamed it on the hardware engineer, but it's mainly
+ a software bug.
+
+*/
+
+#include "emu.h"
+#include "gmboard.h"
+
+
+DEFINE_DEVICE_TYPE(MB_GMBOARD, gmboard_device, "mb_gmboard", "Milton Bradley Grand Master chessboard")
+
+//-------------------------------------------------
+// gmboard_device - constructor
+//-------------------------------------------------
+
+gmboard_device::gmboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, MB_GMBOARD, tag, owner, clock),
+ m_board(*this, "board"),
+ m_piece_hand(*this, "cpu_hand"),
+ m_out_motor(*this, "motor%u", 0U),
+ m_out_pos(*this, "pos_%c", unsigned('x')),
+ m_quad_cb(*this)
+{
+ // (just to prevent a divide by 0 if it's not configured)
+ m_width = 1;
+ m_height = 1;
+ m_square = 1;
+ m_x_offset = 0;
+ m_y_offset = 0;
+
+ m_speed = attotime::from_msec(200);
+}
+
+
+//-------------------------------------------------
+// initialization
+//-------------------------------------------------
+
+void gmboard_device::device_start()
+{
+ // resolve outputs
+ m_piece_hand.resolve();
+ m_out_motor.resolve();
+ m_out_pos.resolve();
+
+ // zerofill
+ m_magnet = 0;
+ memset(m_pieces_map, 0, sizeof(m_pieces_map));
+ memset(m_motor_dir, 0, sizeof(m_motor_dir));
+ memset(m_motor_max, 0, sizeof(m_motor_max));
+ memset(m_motor_pos, 0, sizeof(m_motor_pos));
+ memset(m_motor_quad, 0, sizeof(m_motor_quad));
+ memset(m_motor_drift, 0, sizeof(m_motor_drift));
+
+ // register for savestates
+ save_item(NAME(m_magnet));
+ save_item(NAME(m_pieces_map));
+ save_item(NAME(m_motor_dir));
+ save_item(NAME(m_motor_pos));
+ save_item(NAME(m_motor_quad));
+ save_item(NAME(m_motor_remain));
+ save_item(NAME(m_motor_drift));
+
+ init_motors();
+}
+
+void gmboard_device::device_reset()
+{
+ memset(m_motor_drift, 0, sizeof(m_motor_drift));
+ m_magnet = 0;
+
+ output_magnet_pos();
+}
+
+void gmboard_device::init_board(u8 data)
+{
+ m_board->preset_chess(data);
+
+ // reposition pieces if board will be rotated
+ if (data & 2)
+ {
+ for (int y = 0; y < 8; y++)
+ for (int x = 7; x >= 0; x--)
+ {
+ m_board->write_piece(x + 4, y, m_board->read_piece(x, y));
+ m_board->write_piece(x, y, 0);
+ }
+ }
+}
+
+void gmboard_device::clear_board(u8 data)
+{
+ memset(m_pieces_map, 0, sizeof(m_pieces_map));
+ m_piece_hand = 0;
+ m_board->clear_board(data);
+}
+
+
+//-------------------------------------------------
+// motor sim
+//-------------------------------------------------
+
+void gmboard_device::init_motors()
+{
+ m_motor_max[0] = m_width - 1;
+ m_motor_max[1] = m_height - 1;
+
+ // start at A1
+ m_motor_pos[0] = std::min<u32>(2 * m_square + m_x_offset, m_motor_max[0]);
+ m_motor_pos[1] = std::min<u32>(7 * m_square + m_y_offset, m_motor_max[1]);
+
+ m_motor_period = m_speed / m_square;
+
+ for (int i = 0; i < 2; i++)
+ {
+ m_motor_timer[i] = timer_alloc(FUNC(gmboard_device::motor_count), this);
+ m_motor_remain[i] = m_motor_period / 2;
+ }
+}
+
+void gmboard_device::get_scaled_pos(double *x, double *y)
+{
+ // scale down to 4 counts per square
+ *x = std::clamp(double(int(m_motor_pos[0]) - m_x_offset) / (m_square / 4.0) + 2.0, 0.0, 48.0);
+ *y = std::clamp(double(int(m_motor_pos[1]) - m_y_offset) / (m_square / 4.0) + 2.0, 0.0, 32.0);
+}
+
+void gmboard_device::output_magnet_pos()
+{
+ double x, y;
+ get_scaled_pos(&x, &y);
+
+ // put active state on x bit 11
+ const int active = m_magnet ? 0x800 : 0;
+ m_out_pos[0] = int(x * 25.0 + 0.5) | active;
+ m_out_pos[1] = int(y * 25.0 + 0.5);
+ m_out_motor[4] = m_magnet;
+}
+
+void gmboard_device::realign_magnet_pos()
+{
+ // compensate for gradual drift, see BTANB
+ for (int i = 0; i < 2; )
+ {
+ double pos[2];
+ get_scaled_pos(&pos[0], &pos[1]);
+
+ const double limit = 1.0 / (m_square / 16.0);
+ int inc = 0;
+
+ if ((round(pos[i]) - pos[i]) > limit && m_motor_pos[i] < m_motor_max[i] - 4)
+ inc = 1;
+ else if ((round(pos[i]) - pos[i]) < -limit && m_motor_pos[i] > 4)
+ inc = -1;
+ else
+ i++;
+
+ if (inc != 0)
+ {
+ m_motor_pos[i] += inc * 4;
+ m_motor_drift[i] -= inc;
+
+ logerror("motor %c drift error (%d total)\n", 'X' + i, m_motor_drift[i]);
+ }
+ }
+}
+
+void gmboard_device::magnet_w(int state)
+{
+ state = state ? 1 : 0;
+
+ if (state == m_magnet)
+ return;
+ m_magnet = state;
+
+ if (m_piece_hand != 0)
+ realign_magnet_pos();
+ output_magnet_pos();
+
+ double dx, dy;
+ get_scaled_pos(&dx, &dy);
+
+ int mx = dx + 0.5;
+ int my = dy + 0.5;
+
+ // convert motors position into board coordinates
+ int x = mx / 4 - 2;
+ int y = 7 - (my / 4);
+
+ if (x < 0)
+ x += 12;
+
+ const bool valid_pos = (mx & 3) == 2 && (my & 3) == 2;
+
+ // sensorboard handling is almost the same as fidelity/phantom.cpp
+ if (state)
+ {
+ if (valid_pos)
+ {
+ // pick up piece, unless it was picked up by the user
+ const int pos = (y << 4 & 0xf0) | (x & 0x0f);
+ if (pos != m_board->get_handpos())
+ {
+ m_piece_hand = m_board->read_piece(x, y);
+
+ if (m_piece_hand != 0)
+ {
+ m_board->write_piece(x, y, 0);
+ m_board->refresh();
+ }
+ }
+ }
+ else
+ {
+ // pick up piece from internal pieces map
+ m_piece_hand = m_pieces_map[my][mx];
+ m_pieces_map[my][mx] = 0;
+ }
+ }
+ else if (m_piece_hand != 0)
+ {
+ if (valid_pos)
+ {
+ // collision with piece on board (user interference)
+ if (m_board->read_piece(x, y) != 0)
+ popmessage("Collision at %c%d!", x + 'A', y + 1);
+ else
+ {
+ m_board->write_piece(x, y, m_piece_hand);
+ m_board->refresh();
+ }
+ }
+ else
+ {
+ // collision with internal pieces map (shouldn't happen)
+ if (m_pieces_map[my][mx] != 0)
+ popmessage("Internal collision!");
+ else
+ m_pieces_map[my][mx] = m_piece_hand;
+ }
+
+ m_piece_hand = 0;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(gmboard_device::motor_count)
+{
+ const int m = param ? 1 : 0;
+ assert(m_motor_dir[m] & 3);
+
+ // 1 quarter rotation per period
+ int inc = 0;
+ if (m_motor_dir[m] & 2)
+ {
+ if (m_motor_pos[m] < m_motor_max[m])
+ inc = 1;
+ }
+ else if (m_motor_pos[m] > 0)
+ inc = -1;
+
+ m_motor_remain[m] = m_motor_period;
+
+ if (inc == 0)
+ return;
+
+ m_motor_pos[m] += inc;
+ m_motor_timer[m]->adjust(m_motor_period, m);
+
+ output_magnet_pos();
+
+ // update quadrature encoder
+ static const u8 lut_quad[4] = { 0,1,3,2 };
+ m_motor_quad[m] = lut_quad[m_motor_pos[m] & 3];
+
+ m_quad_cb[m](m_motor_quad[m]);
+}
+
+void gmboard_device::motor_w(offs_t offset, u8 data)
+{
+ const int m = offset & 1;
+ data &= 3;
+
+ for (int i = 0; i < 2; i++)
+ m_out_motor[offset * 2 + i] = BIT(data, i);
+
+ // it's not moving when both directions are set
+ if (data == 3)
+ data = 0;
+
+ if (data == m_motor_dir[m])
+ return;
+
+ // remember remaining time
+ if (m_motor_dir[m] & 3 && !m_motor_timer[m]->remaining().is_never())
+ {
+ m_motor_remain[m] = m_motor_timer[m]->remaining();
+ m_motor_timer[m]->adjust(attotime::never);
+ }
+
+ // invert remaining time if direction flipped
+ if ((m_motor_dir[m] ^ data) & 1)
+ m_motor_remain[m] = m_motor_period - m_motor_remain[m];
+
+ m_motor_dir[m] = data;
+
+ // (re)start the timer
+ if (data & 3)
+ m_motor_timer[m]->adjust(m_motor_remain[m], m);
+}
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device-specific
+// machine configuration
+//-------------------------------------------------
+
+void gmboard_device::device_add_mconfig(machine_config &config)
+{
+ SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS);
+ m_board->set_size(8+4, 8);
+ m_board->clear_cb().set(FUNC(gmboard_device::clear_board));
+ m_board->init_cb().set(FUNC(gmboard_device::init_board));
+ m_board->set_delay(attotime::from_msec(150));
+}
diff --git a/src/devices/machine/gmboard.h b/src/devices/machine/gmboard.h
new file mode 100644
index 00000000000..dd5fa59156c
--- /dev/null
+++ b/src/devices/machine/gmboard.h
@@ -0,0 +1,86 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Milton Bradley Grand Master motorized self-moving chessboard
+
+*/
+
+#ifndef MAME_MACHINE_GMBOARD_H
+#define MAME_MACHINE_GMBOARD_H
+
+#pragma once
+
+#include "machine/sensorboard.h"
+
+class gmboard_device : public device_t
+{
+public:
+ gmboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ // configuration helpers
+ template <std::size_t N> auto quad_cb() { return m_quad_cb[N].bind(); } // x/y motor quadrature encoder state
+ gmboard_device &set_size(u16 width, u16 height, u16 square) { m_width = width; m_height = height; m_square = square; return *this; }
+ gmboard_device &set_offsets(u16 x_offset, u16 y_offset) { m_x_offset = x_offset; m_y_offset = y_offset; return *this; }
+ gmboard_device &set_speed(attotime speed) { m_speed = speed; return *this; }
+
+ sensorboard_device &get() { return *m_board; }
+
+ // external read/write handlers
+ int magnet_r() { return (started() && m_piece_hand) ? 1 : 0; }
+ void magnet_w(int state);
+ void motor_w(offs_t offset, u8 data);
+ u8 quad_r(offs_t offset) { return m_motor_quad[offset & 1]; }
+
+ u16 read_file(u8 x, bool reverse = false) { return m_board->read_file(x, reverse); }
+ u16 read_rank(u8 y, bool reverse = false) { return m_board->read_rank(y, reverse); }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+private:
+ required_device<sensorboard_device> m_board;
+ output_finder<> m_piece_hand;
+ output_finder<5> m_out_motor;
+ output_finder<2> m_out_pos;
+
+ u8 m_magnet;
+ u8 m_pieces_map[0x40][0x40];
+
+ u8 m_motor_dir[2];
+ u32 m_motor_max[2];
+ u32 m_motor_pos[2];
+ u8 m_motor_quad[2];
+ s32 m_motor_drift[2]; // diagnostics
+
+ attotime m_motor_period;
+ attotime m_motor_remain[2];
+ emu_timer *m_motor_timer[2];
+
+ u16 m_width; // motor range
+ u16 m_height; // "
+ u16 m_square; // number of quarter rotations per square
+ u16 m_x_offset; // unscaled offset relative to the bottom-left corner
+ u16 m_y_offset; // "
+ attotime m_speed; // time per square at full speed
+
+ devcb_write8::array<2> m_quad_cb;
+
+ void init_board(u8 data);
+ void clear_board(u8 data);
+ void init_motors();
+
+ void get_scaled_pos(double *x, double *y);
+ void output_magnet_pos();
+ void realign_magnet_pos();
+
+ TIMER_CALLBACK_MEMBER(motor_count);
+};
+
+
+DECLARE_DEVICE_TYPE(MB_GMBOARD, gmboard_device)
+
+#endif // MAME_MACHINE_GMBOARD_H
diff --git a/src/devices/machine/smartboard.cpp b/src/devices/machine/smartboard.cpp
index d699b1306df..22a73032075 100644
--- a/src/devices/machine/smartboard.cpp
+++ b/src/devices/machine/smartboard.cpp
@@ -1,6 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Sandro Ronco, hap
-/******************************************************************************
+/*
Tasc SmartBoard SB30 (analog)
@@ -18,7 +18,7 @@ SB20 and the newer SB30 are not emulated. They're on different hardware, with
embedded CPU to reduce I/O overhead. Note, those are not compatible with old
versions of Tasc R30.
-******************************************************************************/
+*/
#include "emu.h"
#include "smartboard.h"
@@ -128,8 +128,7 @@ ioport_constructor tasc_sb30_device::device_input_ports() const
void tasc_sb30_device::device_add_mconfig(machine_config &config)
{
- SENSORBOARD(config, m_board);
- m_board->set_type(sensorboard_device::INDUCTIVE);
+ SENSORBOARD(config, m_board).set_type(sensorboard_device::INDUCTIVE);
m_board->set_max_id(32);
m_board->init_cb().set(FUNC(tasc_sb30_device::init_cb));
m_board->spawn_cb().set(FUNC(tasc_sb30_device::spawn_cb));
diff --git a/src/mame/excalibur/mirage.cpp b/src/mame/excalibur/mirage.cpp
index 529a97a837d..d6a20c2e69c 100644
--- a/src/mame/excalibur/mirage.cpp
+++ b/src/mame/excalibur/mirage.cpp
@@ -6,7 +6,8 @@ Excalibur Mirage (model 702E)
It's Excalibur's first chess computer, and also Ron Nelson's official return to
chess programming. The x/y motorized magnet is similar to the one used in
-Fidelity Phantom (and Milton Bradley Grand Master before that).
+Fidelity Phantom (and Milton Bradley Grand Master before that), though the
+movement is a bit slower.
Before moving a piece, wait until the computer is done with its own move. After
capturing a piece, select the captured piece from the MAME sensorboard spawn
@@ -26,23 +27,16 @@ There's also a version with a fake wood housing instead of black plastic, it's
most likely the same hardware.
TODO:
-- like fphantom, sensorboard undo buffer fills up pretty quickly
- dump/add PROM version, maybe they improved the motor drift issue?
- it does a cold boot at every reset, so nvram won't work properly unless MAME
adds some kind of auxillary autosave state feature at power-off
-BTANB:
-- Motors gradually drift, causing it to place/pick up pieces off-center. It
- recalibrates itself once in a while but it's not enough. MAME's sensorboard
- device can't deal with it, so there's a workaround (see realign_magnet_pos).
- Ron Nelson blamed it on the hardware engineer, but it's a software fault.
-
*******************************************************************************/
#include "emu.h"
#include "cpu/h8/h8325.h"
-#include "machine/sensorboard.h"
+#include "machine/gmboard.h"
#include "sound/dac.h"
#include "video/pwm.h"
@@ -65,10 +59,7 @@ public:
m_lcd_pwm(*this, "lcd_pwm"),
m_dac(*this, "dac"),
m_inputs(*this, "IN.%u", 0),
- m_out_lcd(*this, "s%u.%u", 0U, 0U),
- m_piece_hand(*this, "cpu_hand"),
- m_out_motor(*this, "motor%u", 0U),
- m_out_pos(*this, "pos_%c", unsigned('x'))
+ m_out_lcd(*this, "s%u.%u", 0U, 0U)
{ }
void mirage(machine_config &config);
@@ -77,49 +68,20 @@ public:
protected:
virtual void machine_start() override ATTR_COLD;
- virtual void machine_reset() override ATTR_COLD;
private:
// devices/pointers
required_device<h83256_device> m_maincpu;
- required_device<sensorboard_device> m_board;
+ required_device<gmboard_device> m_board;
required_device<pwm_display_device> m_lcd_pwm;
required_device<dac_1bit_device> m_dac;
required_ioport_array<3> m_inputs;
output_finder<2, 24> m_out_lcd;
- output_finder<> m_piece_hand;
- output_finder<5> m_out_motor;
- output_finder<2> m_out_pos;
u16 m_inp_mux = 0;
u32 m_lcd_segs = 0;
u8 m_lcd_com = 0;
- u8 m_magnet = 0;
- u8 m_pieces_map[0x40][0x40] = { };
-
- u8 m_motor_control[2] = { };
- u32 m_motor_max[2] = { };
- u32 m_motor_pos[2] = { };
- s32 m_motor_drift[2] = { };
- u8 m_motor_quad[2] = { };
-
- attotime m_motor_period;
- attotime m_motor_remain[2];
- emu_timer *m_motor_timer[2];
-
- void init_board(u8 data);
- void clear_board(u8 data);
- void init_motors();
-
- void get_scaled_pos(double *x, double *y);
- void output_magnet_pos();
- void realign_magnet_pos();
- void update_piece(u8 magnet);
-
- TIMER_CALLBACK_MEMBER(motor_count);
- void motor_control(int m, u8 control);
-
// I/O handlers
void lcd_pwm_w(offs_t offset, u8 data);
void update_lcd();
@@ -134,263 +96,14 @@ private:
void p7_w(offs_t offset, u8 data, u8 mem_mask);
};
-
-
-/*******************************************************************************
- Initialization
-*******************************************************************************/
-
void mirage_state::machine_start()
{
- init_motors();
-
- // resolve outputs
m_out_lcd.resolve();
- m_piece_hand.resolve();
- m_out_motor.resolve();
- m_out_pos.resolve();
// register for savestates
save_item(NAME(m_inp_mux));
save_item(NAME(m_lcd_segs));
save_item(NAME(m_lcd_com));
-
- save_item(NAME(m_magnet));
- save_item(NAME(m_pieces_map));
- save_item(NAME(m_motor_control));
- save_item(NAME(m_motor_pos));
- save_item(NAME(m_motor_drift));
- save_item(NAME(m_motor_quad));
- save_item(NAME(m_motor_remain));
-}
-
-void mirage_state::machine_reset()
-{
- memset(m_motor_drift, 0, sizeof(m_motor_drift));
- output_magnet_pos();
-}
-
-void mirage_state::init_board(u8 data)
-{
- m_board->preset_chess(data);
-
- // reposition pieces if board will be rotated
- if (data & 2)
- {
- for (int y = 0; y < 8; y++)
- for (int x = 7; x >= 0; x--)
- {
- m_board->write_piece(x + 4, y, m_board->read_piece(x, y));
- m_board->write_piece(x, y, 0);
- }
- }
-}
-
-void mirage_state::clear_board(u8 data)
-{
- memset(m_pieces_map, 0, sizeof(m_pieces_map));
- m_piece_hand = 0;
- m_board->clear_board(data);
-}
-
-
-
-/*******************************************************************************
- Motor Sim
-*******************************************************************************/
-
-void mirage_state::init_motors()
-{
- m_motor_period = attotime::from_usec(800);
-
- for (int i = 0; i < 2; i++)
- {
- m_motor_timer[i] = timer_alloc(FUNC(mirage_state::motor_count), this);
- m_motor_remain[i] = m_motor_period / 2;
- }
-
- m_motor_max[1] = 1500 - 1;
- m_motor_pos[1] = 1480;
-
- m_motor_max[0] = 2020 - 1;
- m_motor_pos[0] = 24;
-}
-
-void mirage_state::get_scaled_pos(double *x, double *y)
-{
- // 176 counts per square
- *x = std::clamp(double(int(m_motor_pos[0]) - 20) / (176.0 / 4.0) + 2.0, 0.0, 48.0);
- *y = std::clamp(double(int(m_motor_pos[1]) - 160) / (176.0 / 4.0) + 2.0, 0.0, 32.0);
-}
-
-void mirage_state::output_magnet_pos()
-{
- double x, y;
- get_scaled_pos(&x, &y);
-
- // put active state on x bit 11
- const int active = m_magnet ? 0x800 : 0;
- m_out_pos[0] = int(x * 25.0 + 0.5) | active;
- m_out_pos[1] = int(y * 25.0 + 0.5);
-}
-
-void mirage_state::realign_magnet_pos()
-{
- // compensate for gradual drift, see BTANB
- for (int i = 0; i < 2; )
- {
- double pos[2];
- get_scaled_pos(&pos[0], &pos[1]);
-
- const double limit = 1.0 / 11.0; // 4 counts
- int inc = 0;
-
- if ((round(pos[i]) - pos[i]) > limit && m_motor_pos[i] < m_motor_max[i] - 4)
- inc = 1;
- else if ((round(pos[i]) - pos[i]) < -limit && m_motor_pos[i] > 4)
- inc = -1;
- else
- i++;
-
- if (inc != 0)
- {
- m_motor_pos[i] += inc * 4;
- m_motor_drift[i] -= inc;
-
- logerror("motor %c drift error (%d total)\n", 'X' + i, m_motor_drift[i]);
- }
- }
-}
-
-void mirage_state::update_piece(u8 magnet)
-{
- if (magnet == m_magnet)
- return;
-
- realign_magnet_pos();
-
- m_magnet = magnet;
- output_magnet_pos();
-
- double dx, dy;
- get_scaled_pos(&dx, &dy);
-
- int mx = dx + 0.5;
- int my = dy + 0.5;
-
- // convert motors position into board coordinates
- int x = mx / 4 - 2;
- int y = 7 - (my / 4);
-
- if (x < 0)
- x += 12;
-
- const bool valid_pos = (mx & 3) == 2 && (my & 3) == 2;
-
- // sensorboard handling is almost the same as fidelity/phantom.cpp
- if (magnet)
- {
- if (valid_pos)
- {
- // pick up piece, unless it was picked up by the user
- const int pos = (y << 4 & 0xf0) | (x & 0x0f);
- if (pos != m_board->get_handpos())
- {
- m_piece_hand = m_board->read_piece(x, y);
-
- if (m_piece_hand != 0)
- {
- m_board->write_piece(x, y, 0);
- m_board->refresh();
- }
- }
- }
- else
- {
- // pick up piece from internal pieces map
- m_piece_hand = m_pieces_map[my][mx];
- m_pieces_map[my][mx] = 0;
- }
- }
- else if (m_piece_hand != 0)
- {
- if (valid_pos)
- {
- // collision with piece on board (user interference)
- if (m_board->read_piece(x, y) != 0)
- popmessage("Collision at %c%d!", x + 'A', y + 1);
- else
- {
- m_board->write_piece(x, y, m_piece_hand);
- m_board->refresh();
- }
- }
- else
- {
- // collision with internal pieces map (shouldn't happen)
- if (m_pieces_map[my][mx] != 0)
- popmessage("Internal collision!");
- else
- m_pieces_map[my][mx] = m_piece_hand;
- }
-
- m_piece_hand = 0;
- }
-}
-
-TIMER_CALLBACK_MEMBER(mirage_state::motor_count)
-{
- const int m = param ? 1 : 0;
- assert(m_motor_control[m] & 2);
-
- // 1 quarter rotation per period
- int inc = 0;
- if (m_motor_control[m] & 1)
- {
- if (m_motor_pos[m] < m_motor_max[m])
- inc = 1;
- }
- else if (m_motor_pos[m] > 0)
- inc = -1;
-
- m_motor_remain[m] = m_motor_period;
-
- if (inc == 0)
- return;
-
- m_motor_pos[m] += inc;
- m_motor_timer[m]->adjust(m_motor_period, m);
-
- output_magnet_pos();
-
- // update quadrature encoder
- static const u8 lut_quad[4] = { 0,1,3,2 };
- m_motor_quad[m] = lut_quad[m_motor_pos[m] & 3];
-
- m_maincpu->set_input_line(INPUT_LINE_IRQ1 + m, (m_motor_quad[m] & 1) ? ASSERT_LINE : CLEAR_LINE);
-}
-
-void mirage_state::motor_control(int m, u8 control)
-{
- if (control == m_motor_control[m])
- return;
-
- // remember remaining time
- if (m_motor_control[m] & 2 && !m_motor_timer[m]->remaining().is_never())
- {
- m_motor_remain[m] = m_motor_timer[m]->remaining();
- m_motor_timer[m]->adjust(attotime::never);
- }
-
- // invert remaining time if direction flipped
- if ((m_motor_control[m] ^ control) & 1)
- m_motor_remain[m] = m_motor_period - m_motor_remain[m];
-
- m_motor_control[m] = control;
-
- // (re)start the timer
- if (control & 2)
- m_motor_timer[m]->adjust(m_motor_remain[m], m);
}
@@ -459,7 +172,7 @@ u8 mirage_state::p4_r()
u8 mirage_state::p5_r()
{
// P55: motor Y quadrature B
- return ~(BIT(m_motor_quad[1], 1) << 5);
+ return ~(BIT(m_board->quad_r(1), 1) << 5);
}
void mirage_state::p5_w(u8 data)
@@ -469,10 +182,7 @@ void mirage_state::p5_w(u8 data)
// P53: motor Y direction
// P54: motor Y on
- motor_control(1, data >> 3 & 3);
-
- for (int i = 0; i < 2; i++)
- m_out_motor[i] = BIT(data, i + 3);
+ m_board->motor_w(1, BIT(data, 4) << BIT(data, 3));
}
u8 mirage_state::p6_r()
@@ -483,8 +193,8 @@ u8 mirage_state::p6_r()
// P65: motor X quadrature A (IRQ1)
// P66: motor Y quadrature A (IRQ2)
- data |= m_motor_quad[0] << 5 & 0x20;
- data |= m_motor_quad[1] << 6 & 0x40;
+ data |= m_board->quad_r(0) << 5 & 0x20;
+ data |= m_board->quad_r(1) << 6 & 0x40;
return ~data;
}
@@ -498,7 +208,7 @@ void mirage_state::p6_w(u8 data)
u8 mirage_state::p7_r()
{
// P73: motor X quadrature B
- return ~(BIT(m_motor_quad[0], 1) << 3);
+ return ~(BIT(m_board->quad_r(0), 1) << 3);
}
void mirage_state::p7_w(offs_t offset, u8 data, u8 mem_mask)
@@ -509,13 +219,10 @@ void mirage_state::p7_w(offs_t offset, u8 data, u8 mem_mask)
// P74: motor X direction
// P75: motor X on
- motor_control(0, data >> 4 & 3);
+ m_board->motor_w(0, BIT(data, 5) << BIT(data, 4));
// P76: electromagnet
- update_piece(BIT(data, 6));
-
- for (int i = 0; i < 3; i++)
- m_out_motor[i + 2] = BIT(data, i + 4);
+ m_board->magnet_w(BIT(data, 6));
// P77: motor board power?
}
@@ -578,12 +285,12 @@ void mirage_state::mirage(machine_config &config)
m_maincpu->read_port7().set(FUNC(mirage_state::p7_r));
m_maincpu->write_port7().set(FUNC(mirage_state::p7_w));
- SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS);
- m_board->set_size(8+4, 8);
- m_board->clear_cb().set(FUNC(mirage_state::clear_board));
- m_board->init_cb().set(FUNC(mirage_state::init_board));
- m_board->set_delay(attotime::from_msec(150));
- //m_board->set_nvram_enable(true);
+ MB_GMBOARD(config, m_board);
+ m_board->set_size(2020, 1500, 176);
+ m_board->set_offsets(20, 160);
+ m_board->quad_cb<0>().set_inputline(m_maincpu, INPUT_LINE_IRQ1).bit(0);
+ m_board->quad_cb<1>().set_inputline(m_maincpu, INPUT_LINE_IRQ2).bit(0);
+ //subdevice<sensorboard_device>("board:board")->set_nvram_enable(true);
// video hardware
PWM_DISPLAY(config, m_lcd_pwm).set_size(2, 24);
diff --git a/src/mame/hegenerglaser/mmboard.h b/src/mame/hegenerglaser/mmboard.h
index 22fc6f30903..03e0cc023d5 100644
--- a/src/mame/hegenerglaser/mmboard.h
+++ b/src/mame/hegenerglaser/mmboard.h
@@ -25,7 +25,7 @@ public:
// configuration helpers
void set_disable_leds(bool disable_leds) { m_disable_leds = disable_leds; }
- void set_delay(attotime sensordelay) { m_sensordelay = sensordelay; }
+ void set_delay(attotime sensordelay) { m_sensordelay = sensordelay; }
sensorboard_device *get() { return m_board; }
diff --git a/src/mame/layout/excal_mirage.lay b/src/mame/layout/excal_mirage.lay
index 37feae221b2..5fcdfde97c5 100644
--- a/src/mame/layout/excal_mirage.lay
+++ b/src/mame/layout/excal_mirage.lay
@@ -244,19 +244,19 @@ authors:hap
<param name="y" start="0" increment="10" />
<param name="i" start="8" increment="-1" />
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x01"><bounds x="0" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x02"><bounds x="10" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x04"><bounds x="20" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x08"><bounds x="30" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x10"><bounds x="40" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x20"><bounds x="50" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x40"><bounds x="60" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x80"><bounds x="70" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
-
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x400"><bounds x="-20" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x800"><bounds x="-10" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x100"><bounds x="80" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
- <element ref="hlbb" inputtag="board:RANK.~i~" inputmask="0x200"><bounds x="90" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x01"><bounds x="0" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x02"><bounds x="10" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x04"><bounds x="20" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x08"><bounds x="30" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x10"><bounds x="40" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x20"><bounds x="50" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x40"><bounds x="60" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x80"><bounds x="70" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x400"><bounds x="-20" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x800"><bounds x="-10" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x100"><bounds x="80" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
+ <element ref="hlbb" inputtag="board:board:RANK.~i~" inputmask="0x200"><bounds x="90" y="~y~" width="10" height="10" /><color alpha="0.04" /></element>
<element name="piece_a~i~" ref="piece"><bounds x="0" y="~y~" width="10" height="10" /></element>
<element name="piece_b~i~" ref="piece"><bounds x="10" y="~y~" width="10" height="10" /></element>
@@ -323,8 +323,8 @@ authors:hap
<element ref="text_uib2"><bounds x="1.5" y="11.75" width="7" height="2" /></element>
<element ref="text_uib3"><bounds x="1.5" y="15.25" width="7" height="2" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x200"><bounds x="1" y="11.5" width="8" height="2.5" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x100"><bounds x="1" y="15" width="8" height="2.5" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x200"><bounds x="1" y="11.5" width="8" height="2.5" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x100"><bounds x="1" y="15" width="8" height="2.5" /><color alpha="0.25" /></element>
<!-- spawn -->
<element ref="text_uis1"><bounds x="0" y="20.5" width="10" height="2" /></element>
@@ -344,18 +344,18 @@ authors:hap
<element name="piece_ui11" ref="piece"><bounds x="5" y="40" width="4" height="4" /></element>
<element name="piece_ui12" ref="piece"><bounds x="5" y="44" width="4" height="4" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0001"><bounds x="1" y="23" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0002"><bounds x="1" y="27" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0004"><bounds x="1" y="31" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0008"><bounds x="5" y="23" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0010"><bounds x="5" y="27" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0020"><bounds x="5" y="31" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0040"><bounds x="1" y="36" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0080"><bounds x="1" y="40" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0100"><bounds x="1" y="44" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0200"><bounds x="5" y="36" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0400"><bounds x="5" y="40" width="4" height="4" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:SPAWN" inputmask="0x0800"><bounds x="5" y="44" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0001"><bounds x="1" y="23" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0002"><bounds x="1" y="27" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0004"><bounds x="1" y="31" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0008"><bounds x="5" y="23" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0010"><bounds x="5" y="27" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0020"><bounds x="5" y="31" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0040"><bounds x="1" y="36" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0080"><bounds x="1" y="40" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0100"><bounds x="1" y="44" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0200"><bounds x="5" y="36" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0400"><bounds x="5" y="40" width="4" height="4" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:SPAWN" inputmask="0x0800"><bounds x="5" y="44" width="4" height="4" /><color alpha="0.25" /></element>
<!-- hand -->
<element ref="text_uih1"><bounds x="0" y="51" width="10" height="2" /></element>
@@ -365,7 +365,7 @@ authors:hap
<element ref="cwhite"><bounds x="1" y="60.5" width="8" height="2.5" /></element>
<element ref="text_uih2"><bounds x="1.5" y="60.75" width="7" height="2" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x08"><bounds x="1" y="60.5" width="8" height="2.5" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x08"><bounds x="1" y="60.5" width="8" height="2.5" /><color alpha="0.25" /></element>
<!-- undo -->
<element ref="text_uiu1"><bounds x="0" y="66" width="10" height="2" /></element>
@@ -378,10 +378,10 @@ authors:hap
<element ref="text_uiu2c"><bounds x="5.2" y="69.5" width="1.7" height="4" /></element>
<element ref="text_uiu2d"><bounds x="7.3" y="69.5" width="1.7" height="4" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x10"><bounds x="1" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x20"><bounds x="3.1" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x40"><bounds x="5.2" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
- <element ref="hlub" inputtag="board:UI" inputmask="0x80"><bounds x="7.3" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x10"><bounds x="1" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x20"><bounds x="3.1" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x40"><bounds x="5.2" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
+ <element ref="hlub" inputtag="board:board:UI" inputmask="0x80"><bounds x="7.3" y="68.5" width="1.7" height="6" /><color alpha="0.25" /></element>
<element name="count_ui0" ref="text_uiu3a"><bounds x="0" y="75" width="4" height="2" /></element>
<element name="count_ui1" ref="text_uiu3c"><bounds x="6" y="75" width="4" height="2" /></element>
diff --git a/src/mame/miltonbradley/grandmaster.cpp b/src/mame/miltonbradley/grandmaster.cpp
index c3941a3b3b3..34f0dadbc8b 100644
--- a/src/mame/miltonbradley/grandmaster.cpp
+++ b/src/mame/miltonbradley/grandmaster.cpp
@@ -8,7 +8,6 @@ aka Phantom Chess Computer in the UK, and Milton in the rest of Europe
TODO:
- WIP
-- move chessboard to a device (currently copied from emirage)
*******************************************************************************/
@@ -17,8 +16,8 @@ TODO:
#include "cpu/m6502/m6502.h"
#include "machine/7474.h"
#include "machine/clock.h"
+#include "machine/gmboard.h"
#include "machine/input_merger.h"
-#include "machine/sensorboard.h"
#include "sound/dac.h"
#include "video/pwm.h"
@@ -40,10 +39,7 @@ public:
m_board(*this, "board"),
m_display(*this, "display"),
m_dac(*this, "dac"),
- m_inputs(*this, "IN.0"),
- m_piece_hand(*this, "cpu_hand"),
- m_out_motor(*this, "motor%u", 0U),
- m_out_pos(*this, "pos_%c", unsigned('x'))
+ m_inputs(*this, "IN.0")
{ }
void grandmas(machine_config &config);
@@ -56,41 +52,13 @@ private:
// devices/pointers
required_device<cpu_device> m_maincpu;
required_device_array<ttl7474_device, 3> m_irq_ff;
- required_device<sensorboard_device> m_board;
+ required_device<gmboard_device> m_board;
required_device<pwm_display_device> m_display;
required_device<dac_1bit_device> m_dac;
required_ioport m_inputs;
- output_finder<> m_piece_hand;
- output_finder<5> m_out_motor;
- output_finder<2> m_out_pos;
u8 m_inp_mux = 0;
- u8 m_magnet = 0;
- u8 m_pieces_map[0x40][0x40] = { };
-
- u8 m_motor_control[2] = { };
- u32 m_motor_max[2] = { };
- u32 m_motor_pos[2] = { };
- s32 m_motor_drift[2] = { };
- u8 m_motor_quad[2] = { };
-
- attotime m_motor_period;
- attotime m_motor_remain[2];
- emu_timer *m_motor_timer[2];
-
- void init_board(u8 data);
- void clear_board(u8 data);
- void init_motors();
-
- void get_scaled_pos(double *x, double *y);
- void output_magnet_pos();
- void realign_magnet_pos();
- void update_piece(u8 magnet);
-
- TIMER_CALLBACK_MEMBER(motor_count);
- void motor_control(int m, u8 control);
-
void main_map(address_map &map) ATTR_COLD;
u8 irq_clear_r(offs_t offset);
@@ -102,31 +70,9 @@ private:
u8 input_r(offs_t offset);
};
-
-
-/*******************************************************************************
- Initialization
-*******************************************************************************/
-
void grandmas_state::machine_start()
{
- init_motors();
-
- // resolve outputs
- m_piece_hand.resolve();
- m_out_motor.resolve();
- m_out_pos.resolve();
-
- // register for savestates
save_item(NAME(m_inp_mux));
-
- save_item(NAME(m_magnet));
- save_item(NAME(m_pieces_map));
- save_item(NAME(m_motor_control));
- save_item(NAME(m_motor_pos));
- save_item(NAME(m_motor_drift));
- save_item(NAME(m_motor_quad));
- save_item(NAME(m_motor_remain));
}
void grandmas_state::machine_reset()
@@ -134,240 +80,6 @@ void grandmas_state::machine_reset()
// make sure 7474 is not in an indeterminate state
for (int i = 0; i < 3; i++)
irq_clear_w(i);
-
- memset(m_motor_drift, 0, sizeof(m_motor_drift));
- output_magnet_pos();
-}
-
-void grandmas_state::init_board(u8 data)
-{
- m_board->preset_chess(data);
-
- // reposition pieces if board will be rotated
- if (data & 2)
- {
- for (int y = 0; y < 8; y++)
- for (int x = 7; x >= 0; x--)
- {
- m_board->write_piece(x + 4, y, m_board->read_piece(x, y));
- m_board->write_piece(x, y, 0);
- }
- }
-}
-
-void grandmas_state::clear_board(u8 data)
-{
- memset(m_pieces_map, 0, sizeof(m_pieces_map));
- m_piece_hand = 0;
- m_board->clear_board(data);
-}
-
-
-
-/*******************************************************************************
- Motor Sim
-*******************************************************************************/
-
-void grandmas_state::init_motors()
-{
- m_motor_period = attotime::from_usec(2500);
-
- for (int i = 0; i < 2; i++)
- {
- m_motor_timer[i] = timer_alloc(FUNC(grandmas_state::motor_count), this);
- m_motor_remain[i] = m_motor_period / 2;
- }
-
- m_motor_max[1] = 575 - 1;
- m_motor_pos[1] = 522;
-
- m_motor_max[0] = 750 - 1;
- m_motor_pos[0] = 139;
-}
-
-void grandmas_state::get_scaled_pos(double *x, double *y)
-{
- // 64 counts per square
- *x = std::clamp(double(int(m_motor_pos[0]) - 10) / (64.0 / 4.0) + 2.0, 0.0, 48.0);
- *y = std::clamp(double(int(m_motor_pos[1]) - 75) / (64.0 / 4.0) + 2.0, 0.0, 32.0);
-}
-
-void grandmas_state::output_magnet_pos()
-{
- double x, y;
- get_scaled_pos(&x, &y);
-
- // put active state on x bit 11
- const int active = m_magnet ? 0x800 : 0;
- m_out_pos[0] = int(x * 25.0 + 0.5) | active;
- m_out_pos[1] = int(y * 25.0 + 0.5);
-
- popmessage("%d %d",m_motor_pos[0], m_motor_pos[1]);
-}
-
-void grandmas_state::realign_magnet_pos()
-{
- return;
-
- // compensate for gradual drift, see BTANB
- for (int i = 0; i < 2; )
- {
- double pos[2];
- get_scaled_pos(&pos[0], &pos[1]);
-
- const double limit = 1.0 / 8.0; // 4 counts
- int inc = 0;
-
- if ((round(pos[i]) - pos[i]) > limit && m_motor_pos[i] < m_motor_max[i] - 4)
- inc = 1;
- else if ((round(pos[i]) - pos[i]) < -limit && m_motor_pos[i] > 4)
- inc = -1;
- else
- i++;
-
- if (inc != 0)
- {
- m_motor_pos[i] += inc * 4;
- m_motor_drift[i] -= inc;
-
- logerror("motor %c drift error (%d total)\n", 'X' + i, m_motor_drift[i]);
- }
- }
-}
-
-void grandmas_state::update_piece(u8 magnet)
-{
- if (magnet == m_magnet)
- return;
-
- realign_magnet_pos();
-
- m_magnet = magnet;
- output_magnet_pos();
-
- double dx, dy;
- get_scaled_pos(&dx, &dy);
-
- int mx = dx + 0.5;
- int my = dy + 0.5;
-
- // convert motors position into board coordinates
- int x = mx / 4 - 2;
- int y = 7 - (my / 4);
-
- if (x < 0)
- x += 12;
-
- const bool valid_pos = (mx & 3) == 2 && (my & 3) == 2;
-
- // sensorboard handling is almost the same as fidelity/phantom.cpp
- if (magnet)
- {
- if (valid_pos)
- {
- // pick up piece, unless it was picked up by the user
- const int pos = (y << 4 & 0xf0) | (x & 0x0f);
- if (pos != m_board->get_handpos())
- {
- m_piece_hand = m_board->read_piece(x, y);
-
- if (m_piece_hand != 0)
- {
- m_board->write_piece(x, y, 0);
- m_board->refresh();
- }
- }
- }
- else
- {
- // pick up piece from internal pieces map
- m_piece_hand = m_pieces_map[my][mx];
- m_pieces_map[my][mx] = 0;
- }
- }
- else if (m_piece_hand != 0)
- {
- if (valid_pos)
- {
- // collision with piece on board (user interference)
- if (m_board->read_piece(x, y) != 0)
- popmessage("Collision at %c%d!", x + 'A', y + 1);
- else
- {
- m_board->write_piece(x, y, m_piece_hand);
- m_board->refresh();
- }
- }
- else
- {
- // collision with internal pieces map (shouldn't happen)
- if (m_pieces_map[my][mx] != 0)
- popmessage("Internal collision!");
- else
- m_pieces_map[my][mx] = m_piece_hand;
- }
-
- m_piece_hand = 0;
- }
-}
-
-TIMER_CALLBACK_MEMBER(grandmas_state::motor_count)
-{
- const int m = param ? 1 : 0;
- assert(m_motor_control[m] & 3);
-
- // 1 quarter rotation per period
- int inc = 0;
- if (m_motor_control[m] & 2)
- {
- if (m_motor_pos[m] < m_motor_max[m])
- inc = 1;
- }
- else if (m_motor_pos[m] > 0)
- inc = -1;
-
- m_motor_remain[m] = m_motor_period;
-
- if (inc == 0)
- return;
-
- m_motor_pos[m] += inc;
- m_motor_timer[m]->adjust(m_motor_period, m);
-
- output_magnet_pos();
-
- // update quadrature encoder
- static const u8 lut_quad[4] = { 0,1,3,2 };
- m_motor_quad[m] = lut_quad[m_motor_pos[m] & 3];
-
- m_irq_ff[m + 1]->clock_w(m_motor_quad[m] >> 1 & 1);
-}
-
-void grandmas_state::motor_control(int m, u8 control)
-{
- // it's not moving when both directions are set
- if (control == 3)
- control = 0;
-
- if (control == m_motor_control[m])
- return;
-
- // remember remaining time
- if (m_motor_control[m] & 3 && !m_motor_timer[m]->remaining().is_never())
- {
- m_motor_remain[m] = m_motor_timer[m]->remaining();
- m_motor_timer[m]->adjust(attotime::never);
- }
-
- // invert remaining time if direction flipped
- if ((m_motor_control[m] ^ control) & 2)
- m_motor_remain[m] = m_motor_period - m_motor_remain[m];
-
- m_motor_control[m] = control;
-
- // (re)start the timer
- if (control & 3)
- m_motor_timer[m]->adjust(m_motor_remain[m], m);
}
@@ -394,7 +106,7 @@ u8 grandmas_state::irq_clear_r(offs_t offset)
u8 grandmas_state::status_r()
{
// d0: magnet sensor
- u8 data = m_piece_hand ? 1 : 0;
+ u8 data = m_board->magnet_r();
// d1,d3,d5: IRQ F/F Q
for (int i = 0; i < 3; i++)
@@ -402,7 +114,7 @@ u8 grandmas_state::status_r()
// d2,d4: motor y/x quadrature state
for (int i = 0; i < 2; i++)
- data |= ((m_motor_quad[i] ^ m_motor_quad[i] >> 1) & 1) << (i ? 2 : 4);
+ data |= ((m_board->quad_r(i) ^ m_board->quad_r(i) >> 1) & 1) << (i ? 2 : 4);
return data | 0xc0;
}
@@ -411,14 +123,13 @@ void grandmas_state::control_w(u8 data)
{
// d0: vertical motor down
// d1: vertical motor up
- motor_control(1, bitswap<2>(data, 0, 1));
-
// d2: horizontal motor left
// d3: horizontal motor right
- motor_control(0, data >> 2 & 3);
+ m_board->motor_w(1, bitswap<2>(data, 0, 1));
+ m_board->motor_w(0, data >> 2 & 3);
// d4: electromagnet
- update_piece(BIT(data, 4));
+ m_board->magnet_w(BIT(data, 4));
// d5: speaker out
m_dac->write(BIT(data, 5));
@@ -511,11 +222,11 @@ void grandmas_state::grandmas(machine_config &config)
irq_clock.set_period(attotime::from_ticks(0x1000, 3.58_MHz_XTAL / 2)); // CD4020 Q12
irq_clock.signal_handler().set(m_irq_ff[0], FUNC(ttl7474_device::clock_w));
- SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS);
- m_board->set_size(8+4, 8);
- m_board->clear_cb().set(FUNC(grandmas_state::clear_board));
- m_board->init_cb().set(FUNC(grandmas_state::init_board));
- m_board->set_delay(attotime::from_msec(150));
+ MB_GMBOARD(config, m_board);
+ m_board->set_size(750, 575, 64);
+ m_board->set_offsets(10, 75);
+ m_board->quad_cb<0>().set(m_irq_ff[1], FUNC(ttl7474_device::clock_w)).bit(1);
+ m_board->quad_cb<1>().set(m_irq_ff[2], FUNC(ttl7474_device::clock_w)).bit(1);
// video hardware
PWM_DISPLAY(config, m_display).set_size(2, 8);