diff options
| author | 2026-04-12 23:00:45 +0200 | |
|---|---|---|
| committer | 2026-04-12 23:01:02 +0200 | |
| commit | 149871cb7097679ee67236324ecca65631fd82ae (patch) | |
| tree | 16ce62fb1f14a051d311bdf79935fc2477016f1f | |
| parent | 0f5872aa2eeb46ae87c6a715946cce1704749d84 (diff) | |
grandmas/emirage: move chessboard to a device
| -rw-r--r-- | scripts/src/machine.lua | 12 | ||||
| -rw-r--r-- | src/devices/machine/gmboard.cpp | 356 | ||||
| -rw-r--r-- | src/devices/machine/gmboard.h | 86 | ||||
| -rw-r--r-- | src/devices/machine/smartboard.cpp | 7 | ||||
| -rw-r--r-- | src/mame/excalibur/mirage.cpp | 329 | ||||
| -rw-r--r-- | src/mame/hegenerglaser/mmboard.h | 2 | ||||
| -rw-r--r-- | src/mame/layout/excal_mirage.lay | 64 | ||||
| -rw-r--r-- | src/mame/miltonbradley/grandmaster.cpp | 315 |
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); |
