From 0f01ef7441908554ffabb6bb46e4bef971e340e2 Mon Sep 17 00:00:00 2001 From: hap Date: Fri, 15 Mar 2019 20:06:21 +0100 Subject: mk1: rewrote most of the driver (nw) New working clone added ----------- CompuChess [hap] --- src/mame/drivers/mk1.cpp | 338 ++++++++++++++++++++++++++++--------------- src/mame/layout/cmpchess.lay | 262 +++++++++++++++++++++++++++++++++ src/mame/layout/mk1.lay | 288 ++++++++++++++++++++++++++++++++---- src/mame/mame.lst | 1 + 4 files changed, 741 insertions(+), 148 deletions(-) create mode 100644 src/mame/layout/cmpchess.lay diff --git a/src/mame/drivers/mk1.cpp b/src/mame/drivers/mk1.cpp index aa5ce577ccd..e24794400da 100644 --- a/src/mame/drivers/mk1.cpp +++ b/src/mame/drivers/mk1.cpp @@ -1,21 +1,26 @@ // license:GPL-2.0+ -// copyright-holders:Peter Trauner +// copyright-holders:Peter Trauner, Wilbert Pol, hap /****************************************************************************** Driver file to handle emulation of the Novag/Videomaster Chess Champion MK I -by PeT mess@utanet.at 2000,2001. +Initial version by PeT mess@utanet.at 2000,2001. -Minor updates by Wilbert Pol - 2007 - -The MK I was a clone of Data Cash Systems's Compuchess (1977, one of the first +The MK I was a clone of Data Cash Systems's CompuChess (1977, one of the first chess computers). The ROM is identical. DCS sued Novag Industries for copyright infringement and somehow didn't manage to win the case. -Hardware descriptions: -- An F8 3850 CPU accompanied by a 3853 memory interface +Unlike CompuChess, MK I was a large success, we can assume that it kickstarted +Novag's chess computer generation. It was also distributed as "Computer Chess" +by JS&A, in the same casing as MK I. + +To start playing, enter difficulty level (1-6), then when it says "bP", press A +for new game, B for empty board, or C for continue. + +MK I hardware description: +- An F8 3850 CPU accompanied by a 3853 memory interface, approx 2MHz Variations seen: - - MOSTEK MK 3853N 7915 Philippines ( static memory interface for f8) - - MOSTEK MK 3850N-3 7917 Philipines (fairchild f8 cpu) + - MOSTEK MK 3853N 7915 Philippines (static memory interface for F8) + - MOSTEK MK 3850N-3 7917 Philipines (Fairchild F8 CPU) - 3850PK F7901 SINGAPORE (Fairchild F8 CPU) - 3853PK F7851 SINGAPORE (static memory interface for F8) - 2KB 2316 compatible ROM @@ -35,8 +40,8 @@ Hardware descriptions: - The digit display is driven by two other components: - SN75492N MALAYSIA 7840B - ULN2033A 7847 -- Hardware addressing is controlled by a NBF4001AE. -- Unknown if there is a speaker. +- Hardware addressing is controlled by a HBF4001AE. +- No speaker. ******************************************************************************/ @@ -44,171 +49,270 @@ Hardware descriptions: #include "cpu/f8/f8.h" #include "machine/f3853.h" #include "machine/timer.h" -#include "mk1.lh" +// internal artwork +#include "cmpchess.lh" // clickable +#include "mk1.lh" // clickable + + +namespace { class mk1_state : public driver_device { public: - mk1_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_digits(*this, "digit%u", 0U) - , m_leds(*this, "led%u", 0U) + mk1_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_keypad(*this, "LINE%u", 1U), + m_delay_display(*this, "delay_display_%u", 0), + m_out_digit(*this, "digit%u", 0U) { } + void cmpchess(machine_config &config); void mk1(machine_config &config); -private: - DECLARE_READ8_MEMBER(mk1_f8_r); - DECLARE_WRITE8_MEMBER(mk1_f8_w); - TIMER_DEVICE_CALLBACK_MEMBER(mk1_update_leds); - void mk1_io(address_map &map); - void mk1_mem(address_map &map); + DECLARE_INPUT_CHANGED_MEMBER(reset_switch); +protected: virtual void machine_start() override; - uint8_t m_f8[2]; - uint8_t m_led_data[4]; +private: + // devices/pointers required_device m_maincpu; - output_finder<4> m_digits; - output_finder<4> m_leds; + required_ioport_array<4> m_keypad; + required_device_array m_delay_display; + output_finder<4> m_out_digit; + + void main_io(address_map &map); + void main_map(address_map &map); + + TIMER_DEVICE_CALLBACK_MEMBER(blink) { m_blink = !m_blink; update_display(); } + TIMER_DEVICE_CALLBACK_MEMBER(delay_display); + void update_display(); + + DECLARE_READ8_MEMBER(input_r); + DECLARE_WRITE8_MEMBER(digit_select_w); + DECLARE_WRITE8_MEMBER(digit_data_w); + + u8 m_digit_select; + u8 m_digit_data; + bool m_blink; }; +void mk1_state::machine_start() +{ + // resolve handlers + m_out_digit.resolve(); + + // zerofill + m_digit_select = 0; + m_digit_data = 0; + m_blink = false; + + // register for savestates + save_item(NAME(m_digit_select)); + save_item(NAME(m_digit_data)); + save_item(NAME(m_blink)); +} -READ8_MEMBER( mk1_state::mk1_f8_r ) +INPUT_CHANGED_MEMBER(mk1_state::reset_switch) { - uint8_t i, data = m_f8[offset]; + // reset switch is tied to F3850 RESET pin + m_maincpu->set_input_line(INPUT_LINE_RESET, newval ? ASSERT_LINE : CLEAR_LINE); - if ( offset == 0 ) + // clear display + if (newval) { - if (BIT(data, 0)) data |= ioport("LINE1")->read(); - if (BIT(data, 1)) data |= ioport("LINE2")->read(); - if (BIT(data, 2)) data |= ioport("LINE3")->read(); - if (BIT(data, 3)) data |= ioport("LINE4")->read(); + m_digit_select = 0xff; + for (int i = 0; i < 4; i++) + m_out_digit[i] = 0; + } +} + + + +/****************************************************************************** + Devices, I/O +******************************************************************************/ - for (i = 4; i < 8; i++) +// display handling + +TIMER_DEVICE_CALLBACK_MEMBER(mk1_state::delay_display) +{ + // clear digits if inactive + if (BIT(m_digit_select, param)) + m_out_digit[param] = 0; +} + +void mk1_state::update_display() +{ + // output digits if active + for (int i = 0; i < 4; i++) + { + if (!BIT(m_digit_select, i)) { - if (BIT(data, i)) - { - if (BIT(ioport("LINE1")->read(), i)) data |= 1; - if (BIT(ioport("LINE2")->read(), i)) data |= 2; - if (BIT(ioport("LINE3")->read(), i)) data |= 4; - if (BIT(ioport("LINE4")->read(), i)) data |= 8; - } + // display panel goes into automated blink mode if DP segment is held high + // and DP segment itself only appears to be active if no other segments are + u8 mask = (m_digit_data == 1) ? 0x80 : 0x7f; + mask = (m_blink && m_digit_data & 1) ? 0 : mask; + m_out_digit[i] = bitswap<8>(m_digit_data,0,2,1,3,4,5,6,7) & mask; } } - return data; } -WRITE8_MEMBER( mk1_state::mk1_f8_w ) -{ - /* 0 is high and allows also input */ - m_f8[offset] = data; - if ( ! ( m_f8[1] & 1 ) ) m_led_data[0] = bitswap<8>( m_f8[0],2,1,3,4,5,6,7,0 ); - if ( ! ( m_f8[1] & 2 ) ) m_led_data[1] = bitswap<8>( m_f8[0],2,1,3,4,5,6,7,0 ); - if ( ! ( m_f8[1] & 4 ) ) m_led_data[2] = bitswap<8>( m_f8[0],2,1,3,4,5,6,7,0 ); - if ( ! ( m_f8[1] & 8 ) ) m_led_data[3] = bitswap<8>( m_f8[0],2,1,3,4,5,6,7,0 ); -} +// F3850 ports -void mk1_state::mk1_mem(address_map &map) +WRITE8_MEMBER(mk1_state::digit_data_w) { - map(0x0000, 0x07ff).rom(); - map(0x1800, 0x18ff).ram(); + // digit segment data, and also input mux + m_digit_data = data; + update_display(); } +WRITE8_MEMBER(mk1_state::digit_select_w) +{ + // d0-d3: digit select (active low) + // they're strobed, so on rising edge, delay them going off to prevent flicker or stuck display + for (int i = 0; i < 4; i++) + if (BIT(~m_digit_select & data, i)) + m_delay_display[i]->adjust(attotime::from_msec(20), i); + + m_digit_select = data; + update_display(); +} -void mk1_state::mk1_io(address_map &map) +READ8_MEMBER(mk1_state::input_r) { - map(0x0, 0x1).rw(FUNC(mk1_state::mk1_f8_r), FUNC(mk1_state::mk1_f8_w)); - map(0xc, 0xf).rw("smi", FUNC(f3853_device::read), FUNC(f3853_device::write)); + u8 data = m_digit_data; + + // d0-d3: multiplexed inputs from d4-d7 + for (int i = 0; i < 4; i++) + if (m_digit_data & m_keypad[i]->read()) + data |= 1 << i; + + // d4-d7: multiplexed inputs from d0-d3 + for (int i = 0; i < 4; i++) + if (BIT(m_digit_data, i)) + data |= m_keypad[i]->read(); + + return data; } -static INPUT_PORTS_START( mk1 ) - PORT_START("RESET") /* 0 */ - PORT_DIPNAME ( 0x01, 0x01, "Switch") - PORT_DIPSETTING( 0, "L" ) - PORT_DIPSETTING( 1, "S" ) - - PORT_START("LINE1") /* 1 */ - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White A King") PORT_CODE(KEYCODE_A) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White B Queen") PORT_CODE(KEYCODE_B) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White C Bishop") PORT_CODE(KEYCODE_C) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White D PLAY") PORT_CODE(KEYCODE_D) - PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("LINE2") /* 2 */ - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White E Knight") PORT_CODE(KEYCODE_E) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White F Castle") PORT_CODE(KEYCODE_F) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White G Pawn") PORT_CODE(KEYCODE_G) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("White H md") PORT_CODE(KEYCODE_H) - PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("LINE3") /* 3 */ - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 1 King") PORT_CODE(KEYCODE_1) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 2 Queen") PORT_CODE(KEYCODE_2) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 3 Bishop") PORT_CODE(KEYCODE_3) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 4 fp") PORT_CODE(KEYCODE_4) - PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("LINE4") /* 4 */ - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 5 Knight") PORT_CODE(KEYCODE_5) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 6 Castle") PORT_CODE(KEYCODE_6) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 7 Pawn") PORT_CODE(KEYCODE_7) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Black 8 ep") PORT_CODE(KEYCODE_8) - PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) -INPUT_PORTS_END +/****************************************************************************** + Address Maps +******************************************************************************/ -TIMER_DEVICE_CALLBACK_MEMBER(mk1_state::mk1_update_leds) +void mk1_state::main_map(address_map &map) { - for (int i = 0; i < 4; i++) - { - m_digits[i] = m_led_data[i] >> 1; - m_leds[i] = m_led_data[i] & 0x01; - m_led_data[i] = 0; - } + map(0x0000, 0x07ff).rom(); + map(0x1800, 0x18ff).ram(); } - -void mk1_state::machine_start() +void mk1_state::main_io(address_map &map) { - m_digits.resolve(); - m_leds.resolve(); + map(0x00, 0x00).rw(FUNC(mk1_state::input_r), FUNC(mk1_state::digit_data_w)); + map(0x01, 0x01).w(FUNC(mk1_state::digit_select_w)); + map(0x0c, 0x0f).rw("smi", FUNC(f3853_device::read), FUNC(f3853_device::write)); } -void mk1_state::mk1(machine_config &config) + +/****************************************************************************** + Input Ports +******************************************************************************/ + +static INPUT_PORTS_START( cmpchess ) + PORT_START("LINE1") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_A) PORT_NAME("A / White King") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("B / White Queen") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("C / White Bishop") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_D) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("D / Play") + + PORT_START("LINE2") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("E / White Knight") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F) PORT_NAME("F / White Rook") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) PORT_NAME("G / White Pawn") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_M) PORT_NAME("H / md") // more data + + PORT_START("LINE3") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1 / Black King") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2 / Black Queen") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3 / Black Bishop") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4 / fp") // find piece(position) + + PORT_START("LINE4") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5 / Black Knight") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6 / Black Rook") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("7 / Black Pawn") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("8 / ep") // enter piece(position) + + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CODE(KEYCODE_R) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, mk1_state, reset_switch, nullptr) PORT_NAME("Reset Switch") // L.S. switch on the MK I +INPUT_PORTS_END + + + +/****************************************************************************** + Machine Configs +******************************************************************************/ + +void mk1_state::cmpchess(machine_config &config) { /* basic machine hardware */ - F8(config, m_maincpu, 2000000); // MK3850, approx 2MHz - m_maincpu->set_addrmap(AS_PROGRAM, &mk1_state::mk1_mem); - m_maincpu->set_addrmap(AS_IO, &mk1_state::mk1_io); + F8(config, m_maincpu, 3.579545_MHz_XTAL/2); // Fairchild 3850PK + m_maincpu->set_addrmap(AS_PROGRAM, &mk1_state::main_map); + m_maincpu->set_addrmap(AS_IO, &mk1_state::main_io); m_maincpu->set_irq_acknowledge_callback("smi", FUNC(f3853_device::int_acknowledge)); - f3853_device &smi(F3853(config, "smi", 2000000)); + f3853_device &smi(F3853(config, "smi", 3.579545_MHz_XTAL/2)); smi.int_req_callback().set_inputline("maincpu", F8_INPUT_LINE_INT_REQ); /* video hardware */ - config.set_default_layout(layout_mk1); + for (int i = 0; i < 4; i++) + TIMER(config, m_delay_display[i]).configure_generic(FUNC(mk1_state::delay_display)); + + TIMER(config, "blink_display").configure_periodic(FUNC(mk1_state::blink), attotime::from_msec(250)); // approximation + config.set_default_layout(layout_cmpchess); +} + +void mk1_state::mk1(machine_config &config) +{ + cmpchess(config); + + /* basic machine hardware */ + m_maincpu->set_clock(2000000); // it's a bit faster than cmpchess + subdevice("smi")->set_clock(2000000); - TIMER(config, "led_timer").configure_periodic(FUNC(mk1_state::mk1_update_leds), attotime::from_hz(30)); + config.set_default_layout(layout_mk1); } + +/****************************************************************************** + ROM Definitions +******************************************************************************/ + +ROM_START( cmpchess ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("32014-4950", 0x0000, 0x0800, CRC(278f7bf3) SHA1(b384c95ba691d52dfdddd35987a71e9746a46170) ) +ROM_END + ROM_START( ccmk1 ) - ROM_REGION(0x10000,"maincpu",0) - ROM_LOAD("82c210-1", 0x0000, 0x800, CRC(278f7bf3) SHA1(b384c95ba691d52dfdddd35987a71e9746a46170)) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("82c210-1", 0x0000, 0x0800, CRC(278f7bf3) SHA1(b384c95ba691d52dfdddd35987a71e9746a46170) ) ROM_END +} // anonymous namespace -/*************************************************************************** - Game driver(s) -***************************************************************************/ +/****************************************************************************** + Drivers +******************************************************************************/ -// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS -CONS( 1978, ccmk1, 0, 0, mk1, mk1, mk1_state, empty_init, "Novag", "Chess Champion: MK I", MACHINE_NO_SOUND_HW ) +// YEAR NAME PARENT CMP MACHINE INPUT STATE INIT COMPANY, FULLNAME, FLAGS +CONS( 1977, cmpchess, 0, 0, cmpchess, cmpchess, mk1_state, empty_init, "Data Cash Systems", "CompuChess", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +CONS( 1978, ccmk1, cmpchess, 0, mk1, cmpchess, mk1_state, empty_init, "Novag", "Chess Champion: MK I", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) diff --git a/src/mame/layout/cmpchess.lay b/src/mame/layout/cmpchess.lay new file mode 100644 index 00000000000..fe162d2d718 --- /dev/null +++ b/src/mame/layout/cmpchess.lay @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/mk1.lay b/src/mame/layout/mk1.lay index 532bd44a27b..301f9cde1e3 100644 --- a/src/mame/layout/mk1.lay +++ b/src/mame/layout/mk1.lay @@ -1,42 +1,268 @@ + + + + + + + + - - - + - + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 38bb23a2e21..684cafa4500 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -21716,6 +21716,7 @@ mjsister // (c) 1986 Toaplan @source:mk1.cpp ccmk1 // Chess Champion MK I +cmpchess @source:mk14.cpp mk14 // -- cgit v1.2.3