diff options
Diffstat (limited to 'src/mame/chess')
-rw-r--r-- | src/mame/chess/README.md | 3 | ||||
-rw-r--r-- | src/mame/chess/ave_arb.cpp | 357 | ||||
-rw-r--r-- | src/mame/chess/compuchess.cpp | 510 | ||||
-rw-r--r-- | src/mame/chess/conchess.cpp | 389 | ||||
-rw-r--r-- | src/mame/chess/conic_cchess2.cpp | 285 | ||||
-rw-r--r-- | src/mame/chess/conic_cchess3.cpp | 161 | ||||
-rw-r--r-- | src/mame/chess/krypton_regency.cpp | 350 | ||||
-rw-r--r-- | src/mame/chess/regence.cpp | 249 | ||||
-rw-r--r-- | src/mame/chess/tasc.cpp | 369 |
9 files changed, 2673 insertions, 0 deletions
diff --git a/src/mame/chess/README.md b/src/mame/chess/README.md new file mode 100644 index 00000000000..920114aeeda --- /dev/null +++ b/src/mame/chess/README.md @@ -0,0 +1,3 @@ +# **src/mame/chess** # + +Generic folder for chess computer drivers, where the number of drivers is too small to place them in specific company folders.
\ No newline at end of file diff --git a/src/mame/chess/ave_arb.cpp b/src/mame/chess/ave_arb.cpp new file mode 100644 index 00000000000..9b2ee1f60fe --- /dev/null +++ b/src/mame/chess/ave_arb.cpp @@ -0,0 +1,357 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:Berger +/******************************************************************************* + +AVE Micro Systems ARB chess computer driver, in some regions redistributed +by Chafitz, and in Germany by Sandy Electronic. + +Auto Response Board (ARB) overview: +- R6502P CPU @ 2MHz(4MHz XTAL), R6522P VIA +- 2KB RAM(4*2114), cartridge port +- magnetic chessboard, 8*8+12 leds +- PCB label AV001C01 REV A + +The electronic magnetic chessboard is the first of its kind. AVE later licensed +it to Fidelity (see fidelity/elite.cpp). + +ARB is a romless system, the program ROM is on a cartridge. + +Known chess modules: +- Grand Master Series 3 +- Grand Master Series 4.0 +- Sargon 2.5 +- Sargon 3.5 (unofficial) + +Other games: +- Avelan (checkers) + +Sandy Electronic renamed GMS 3 and GMS 4.0 to "3000 GMS" and "4,0 - 50 S". +Sargon 3.5 was an unofficial module published by them. It was also a free EPROM +upgrade for their customers who were unhappy with GMS 3. + +GMS 4.0 included button label stickers for OPTIONS, Verify, Take Back, Clear. + +Around 2012, Steve Braid(aka Trilobyte/Steve UK) started manufacturing ARB V2 +boards without a module slot. CPU and VIA were replaced with new WDC 14MHz-rated +chips, running at 16MHz. + +TODO: +- avelan, gms3, gms4, sargon35 rom labels + +*******************************************************************************/ + +#include "emu.h" + +#include "bus/generic/carts.h" +#include "bus/generic/slot.h" +#include "cpu/m6502/m6502.h" +#include "cpu/m6502/w65c02s.h" +#include "video/pwm.h" +#include "machine/6522via.h" +#include "machine/nvram.h" +#include "machine/sensorboard.h" +#include "sound/dac.h" + +#include "speaker.h" +#include "softlist_dev.h" + +// internal artwork +#include "ave_arb.lh" + + +namespace { + +class arb_state : public driver_device +{ +public: + arb_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_board(*this, "board"), + m_via(*this, "via"), + m_extram(*this, "extram", 0x800, ENDIANNESS_LITTLE), + m_dac(*this, "dac"), + m_cart(*this, "cartslot"), + m_inputs(*this, "IN.%u", 0) + { } + + // halt button is tied to NMI, reset button to RESET(but only if halt button is held) + DECLARE_INPUT_CHANGED_MEMBER(reset_button) { update_reset(); } + DECLARE_INPUT_CHANGED_MEMBER(halt_button) { m_maincpu->set_input_line(M6502_NMI_LINE, newval ? ASSERT_LINE : CLEAR_LINE); update_reset(); } + void update_reset(); + + void arb(machine_config &config); + void v2(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device<pwm_display_device> m_display; + required_device<sensorboard_device> m_board; + required_device<via6522_device> m_via; + memory_share_creator<u8> m_extram; + required_device<dac_1bit_device> m_dac; + optional_device<generic_slot_device> m_cart; + required_ioport_array<2> m_inputs; + + u16 m_inp_mux = 0; + u16 m_led_select = 0; + u8 m_led_group = 0; + u8 m_led_latch = 0; + u16 m_led_data = 0; + + bool m_altboard = false; + + void main_map(address_map &map) ATTR_COLD; + void v2_map(address_map &map) ATTR_COLD; + + void init_board(u8 data); + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); + + void update_display(); + void leds_w(u8 data); + void control_w(u8 data); + u8 input_r(); +}; + +void arb_state::machine_start() +{ + // register for savestates + save_item(NAME(m_inp_mux)); + save_item(NAME(m_led_select)); + save_item(NAME(m_led_group)); + save_item(NAME(m_led_latch)); + save_item(NAME(m_led_data)); +} + +void arb_state::update_reset() +{ + bool state = m_inputs[1]->read() == 3; + + // RESET goes to 6502+6522 + m_maincpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE); + if (state) + m_via->reset(); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +// sensorboard + +void arb_state::init_board(u8 data) +{ + // different board setup for checkers + if (m_altboard) + { + for (int i = 0; i < 12; i++) + { + m_board->write_piece((i % 4) * 2 + ((i / 4) & 1), i / 4, 13); // white + m_board->write_piece((i % 4) * 2 + (~(i / 4) & 1), i / 4 + 5, 14); // black + } + } + else + m_board->preset_chess(data); +} + + +// cartridge + +DEVICE_IMAGE_LOAD_MEMBER(arb_state::cart_load) +{ + u32 size = m_cart->common_get_size("rom"); + m_cart->rom_alloc(size, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE); + m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom"); + + // extra ram (optional) + if (image.get_feature("ram")) + m_maincpu->space(AS_PROGRAM).install_ram(0x0800, 0x0fff, 0x1000, m_extram); + + m_altboard = bool(image.get_feature("altboard")); + + return std::make_pair(std::error_condition(), std::string()); +} + + +// R6522 ports + +void arb_state::update_display() +{ + // 12 led column data lines via 3 7475 + u16 mask = 0; + mask |= (m_led_group & 1) ? 0xf00 : 0; + mask |= (m_led_group & 2) ? 0x0ff : 0; + + m_led_data = (m_led_data & ~mask) | ((m_led_latch << 8 | m_led_latch) & mask); + m_display->matrix(m_led_select | 0x200, m_led_data); +} + +void arb_state::leds_w(u8 data) +{ + // PA0-PA7: led latch input + m_led_latch = ~data & 0xff; + update_display(); +} + +void arb_state::control_w(u8 data) +{ + // PB0-PB3: 74145 A-D + // 74145 0-8: input mux, led row select + m_inp_mux = data & 0xf; + m_led_select = 1 << (data & 0xf) & 0x1ff; + + // PB4,PB5: led group select + m_led_group = data >> 4 & 3; + update_display(); + + // PB7: speaker out + m_dac->write(BIT(data, 7)); +} + +u8 arb_state::input_r() +{ + u8 data = 0; + + // PA0-PA7: multiplexed inputs + if (m_inp_mux < 8) + data = m_board->read_file(m_inp_mux); + else if (m_inp_mux < 9) + data = m_inputs[m_inp_mux - 8]->read(); + + return ~data; +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void arb_state::main_map(address_map &map) +{ + // external slot is A0-A14, potential bus conflict with RAM/VIA + map(0x0000, 0x7fff).mirror(0x8000).r(m_cart, FUNC(generic_slot_device::read_rom)); + map(0x0000, 0x07ff).mirror(0x1000).ram().share("nvram"); + map(0x8000, 0x800f).mirror(0x1ff0).m(m_via, FUNC(via6522_device::map)); +} + +void arb_state::v2_map(address_map &map) +{ + map(0x0000, 0x7fff).ram().share("nvram"); // BS62LV256 + map(0x8000, 0x800f).mirror(0x1ff0).m(m_via, FUNC(via6522_device::map)); + map(0xa000, 0xffff).rom(); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( arb ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_7) PORT_NAME("Hint / Black") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_V) PORT_CODE(KEYCODE_6) PORT_NAME("Variable / Clear / White / 6") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M) PORT_CODE(KEYCODE_5) PORT_NAME("Monitor / Take Back / King / 5") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) PORT_CODE(KEYCODE_4) PORT_NAME("Self Play / Verify / Queen / 4") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_CODE(KEYCODE_3) PORT_NAME("Change Board / Rook / 3") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_CODE(KEYCODE_2) PORT_NAME("Change Color / Bishop / 2") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_CODE(KEYCODE_1) PORT_NAME("Change Level / Knight / 1") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_N) PORT_CODE(KEYCODE_0) PORT_NAME("New Game / Options / Pawn / 0") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_CODE(KEYCODE_F1) PORT_NAME("Reset") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(arb_state::reset_button), 0) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_CODE(KEYCODE_F1) PORT_NAME("Halt") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(arb_state::halt_button), 0) +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void arb_state::v2(machine_config &config) +{ + // basic machine hardware + W65C02S(config, m_maincpu, 16_MHz_XTAL); // W65C02S6TPG-14 + m_maincpu->set_addrmap(AS_PROGRAM, &arb_state::v2_map); + + W65C22S(config, m_via, 16_MHz_XTAL); // W65C22S6TPG-14 + m_via->writepa_handler().set(FUNC(arb_state::leds_w)); + m_via->writepb_handler().set(FUNC(arb_state::control_w)); + m_via->readpa_handler().set(FUNC(arb_state::input_r)); + m_via->irq_handler().set_inputline(m_maincpu, M6502_IRQ_LINE); + + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); + m_board->init_cb().set(FUNC(arb_state::init_board)); + m_board->set_spawnpoints(12+2); // +2 checkers pieces + m_board->set_delay(attotime::from_msec(100)); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(9+1, 12); + config.set_default_layout(layout_ave_arb); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); +} + +void arb_state::arb(machine_config &config) +{ + v2(config); + + // basic machine hardware + M6502(config.replace(), m_maincpu, 4_MHz_XTAL/2); // R6502P + m_maincpu->set_addrmap(AS_PROGRAM, &arb_state::main_map); + + MOS6522(config.replace(), m_via, 4_MHz_XTAL/4); // R6522P + m_via->writepa_handler().set(FUNC(arb_state::leds_w)); + m_via->writepb_handler().set(FUNC(arb_state::control_w)); + m_via->readpa_handler().set(FUNC(arb_state::input_r)); + m_via->irq_handler().set_inputline(m_maincpu, M6502_IRQ_LINE); + + // cartridge + GENERIC_CARTSLOT(config, m_cart, generic_linear_slot, "arb"); + m_cart->set_device_load(FUNC(arb_state::cart_load)); + m_cart->set_must_be_loaded(true); + + SOFTWARE_LIST(config, "cart_list").set_original("arb"); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( arb ) + ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) + // none here, it's in the module slot +ROM_END + +ROM_START( arbv2 ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD( "sargon_4.0", 0x0000, 0x10000, CRC(c519c9e8) SHA1(d7597d50c0f4f9aa6d990c8d3b485e39cb44ff06) ) // AT27C512R +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1980, arb, 0, 0, arb, arb, arb_state, empty_init, "AVE Micro Systems", "Auto Response Board", MACHINE_SUPPORTS_SAVE ) +SYST( 2012, arbv2, arb, 0, v2, arb, arb_state, empty_init, "hack (Steve Braid)", "ARB V2 Sargon 4.0", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/compuchess.cpp b/src/mame/chess/compuchess.cpp new file mode 100644 index 00000000000..882924eaf5c --- /dev/null +++ b/src/mame/chess/compuchess.cpp @@ -0,0 +1,510 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner, Wilbert Pol, hap +// thanks-to:Sean Riddle, Berger +/******************************************************************************* + +DCS CompuChess / Novag Chess Champion MK I +Initial driver version by PeT mess@utanet.at 2000,2001. +Driver largely rewritten over the years. + +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. + +TODO: +- cncchess sound is wrong, it should be a long dual-tone alarm sound + +BTANB: +- cmpchess/cmpchess2 accepts illegal moves (Conic fixed that) +- digits may flash briefly after entering a command, eg. the "b" or "P" digit + after setting board preset, this happens on the real device + +================================================================================ + +DataCash Systems's CompuChess released mid-1977. One of the first chess +computers, the first one being Fidelity Chess Challenger (fidelity/cc1.cpp) + +Hardware notes: +- PCB label: CompuChess 1, STAID INC, REV A, 7-77 +- Fairchild 3850PK, 2MHz XTAL +- Fairchild 3853PK +- 2KB ROM, 256 bytes RAM(2*D2101AL-4) +- 4-digit 7seg led display, no sound + +CompuChess 2nd edition is on the same PCB, but with a 3.57MHz XTAL(!), a 3850PC, +and Mostek MK3853N. The MCU speed was also confirmed with move calculation time. + +2nd edition added 3 new game modes: E for "Game of Knights", F for "Amazon Queen", +and G for "Survival". + +================================================================================ + +The game underneath CompuChess is better known as Novag's MK I, it was an +unlicensed clone. The ROM is identical. DCS sued JS&A / Novag Industries for +copyright infringement and somehow didn't manage to win the case. +see: https://law.justia.com/cases/federal/district-courts/FSupp/480/1063/1531498/ + +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 housing as MK I. + +MCU frequency is with an LC circuit. The first version was around 5% faster than +CompuChess, the JS&A version was measured 2.18MHz on average. The 2nd version was +much faster, judging from move calculation time: around 3.5MHz(give or take 0.2). + +1st (slow) version: +- Novag MK I with Boris Spassky photo on the box +- JS&A Computer Chess + +2nd (fast) version: +- Novag MK I with Karpov photo on the box, later advertised with message + "Neu: Mit Quick-Electronic für Schnelle Gegenzüge" +- Waddingtons Videomaster Chess Champion + +MK I hardware description: +- An F8 3850 CPU accompanied by a 3853 memory interface + Variations seen: + - 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 + Variations seen: + - Signetics 7916E C48091 82S210-1 COPYRIGHT + - RO-3-8316A 8316A-4480 7904 TAIWAN +- 2 x 2111 256x4 SRAM to provide 256 bytes of RAM + Variations seen: + - AM9111 BPC / P2111A-4 7851 +- 16 keys placed in a 4 x 4 matrix +- Power on switch +- L/S switch. This switch is directly tied to the RESET pin of the F8 CPU. + This allows the user to reset the CPU without destroying the RAM contents. +- A 4 character 11 segment digit display using a 15 pin interface. Of the 15 + pins 3 pins are not connected, so three segments are never used and this + leaves a standard 7 segments display with a dot in the lower right. +- The digit display is driven by two other components: + - SN75492N MALAYSIA 7840B + - ULN2033A 7847 +- Hardware addressing is controlled by a HBF4001AE. +- No speaker. + +================================================================================ + +Conic Computer Chess (aka Master I in Germany) is also based on DCS CompuChess, +this time the 2nd edition. Conic have done a few changes, not enough to hide that +they 'borrowed' code. They also added a piezo circuit. + +Hardware notes: +- Fairchild 3850PK CPU @ 2MHz (LC circuit), 3853PK +- 2KB ROM (3216), 256 bytes RAM (2*2111A) +- discrete sound + +"bP" buttons are F, G, H (instead of A, B, C) + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/f8/f8.h" +#include "machine/f3853.h" +#include "machine/timer.h" +#include "sound/beep.h" +#include "video/pwm.h" +#include "speaker.h" + +// internal artwork +#include "cmpchess.lh" +#include "novag_mk1.lh" +#include "conic_cchess.lh" + + +namespace { + +class cmpchess_state : public driver_device +{ +public: + cmpchess_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_beeper_off(*this, "beeper_off"), + m_beeper(*this, "beeper"), + m_inputs(*this, "IN.%u", 0) + { } + + DECLARE_INPUT_CHANGED_MEMBER(reset_switch) { update_reset(newval); } + DECLARE_INPUT_CHANGED_MEMBER(change_cpu_freq); + + // machine configs + void cmpchess(machine_config &config); + void cmpchess2(machine_config &config); + void mk1(machine_config &config); + void cncchess(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device<pwm_display_device> m_display; + optional_device<timer_device> m_beeper_off; + optional_device<beep_device> m_beeper; + required_ioport_array<4> m_inputs; + + u8 m_inp_mux = 0; + u8 m_digit_select = 0; + u8 m_digit_data = 0; + bool m_blink = false; + + // address maps + void main_map(address_map &map) ATTR_COLD; + void main_io(address_map &map) ATTR_COLD; + void cncchess_map(address_map &map) ATTR_COLD; + void cncchess_io(address_map &map) ATTR_COLD; + + TIMER_DEVICE_CALLBACK_MEMBER(beeper_off) { m_beeper->set_state(0); } + TIMER_DEVICE_CALLBACK_MEMBER(blink) { m_blink = !m_blink; update_display(); } + void update_display(); + void update_reset(ioport_value state); + + // I/O handlers + void input_w(u8 data); + u8 input_r(); + void digit_select_w(u8 data); + void digit_data_w(u8 data); + u8 digit_data_r(); + u8 beeper_r(offs_t offset); + + void input_digit_select_w(u8 data) { input_w(data); digit_select_w(data); } + void input_digit_data_w(u8 data) { input_w(data); digit_data_w(data); } +}; + + + +/******************************************************************************* + Initialization +*******************************************************************************/ + +void cmpchess_state::machine_start() +{ + // register for savestates + save_item(NAME(m_inp_mux)); + save_item(NAME(m_digit_select)); + save_item(NAME(m_digit_data)); + save_item(NAME(m_blink)); +} + +void cmpchess_state::machine_reset() +{ + update_reset(ioport("RESET")->read()); +} + +void cmpchess_state::update_reset(ioport_value state) +{ + // reset switch is tied to F3850 RESET pin + m_maincpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE); + + // clear display + if (state) + m_display->clear(); +} + +INPUT_CHANGED_MEMBER(cmpchess_state::change_cpu_freq) +{ + // 2 MK I versions, 2nd one was a lot faster + const u32 freq = (newval & 1) ? 3'500'000 : 2'250'000; + m_maincpu->set_unscaled_clock(freq); + subdevice<f3853_device>("smi")->set_unscaled_clock(freq); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +void cmpchess_state::update_display() +{ + // display panel goes into automated blink mode if DP segment is held high, + // and DP segment itself by default only appears to be active if no other segments are + u8 dmask = (m_digit_data == 1) ? 0x80 : 0x7f; + u8 bmask = (m_blink && m_digit_data & 1) ? 0 : 0xff; + u8 bstate = m_digit_data & bmask & 1; // DP state for ignoring dmask + + u8 digit_data = bitswap<8>(m_digit_data,0,2,1,3,4,5,6,7) & dmask & bmask; + m_display->matrix(m_digit_select, bstate << 8 | digit_data); +} + +void cmpchess_state::digit_data_w(u8 data) +{ + // digit segment data + m_digit_data = data; + update_display(); +} + +u8 cmpchess_state::digit_data_r() +{ + return m_digit_data; +} + +void cmpchess_state::digit_select_w(u8 data) +{ + // d0-d3: digit select (active low) + m_digit_select = ~data & 0xf; + update_display(); +} + +void cmpchess_state::input_w(u8 data) +{ + // input matrix is shared with either digit_data_w, or digit_select_w + m_inp_mux = data; +} + +u8 cmpchess_state::input_r() +{ + u8 data = m_inp_mux; + + // d0-d3: multiplexed inputs from d4-d7 + for (int i = 0; i < 4; i++) + if (m_inp_mux & m_inputs[i]->read() << 4) + data |= 1 << i; + + // d4-d7: multiplexed inputs from d0-d3 + for (int i = 0; i < 4; i++) + if (BIT(m_inp_mux, i)) + data |= m_inputs[i]->read() << 4; + + return data; +} + +u8 cmpchess_state::beeper_r(offs_t offset) +{ + // cncchess: trigger beeper + if (!machine().side_effects_disabled()) + { + m_beeper->set_state(1); + m_beeper_off->adjust(attotime::from_msec(50)); // wrong, see TODO + } + + return m_maincpu->space(AS_PROGRAM).read_byte(offset); +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void cmpchess_state::main_map(address_map &map) +{ + map.global_mask(0x0fff); + map(0x0000, 0x07ff).rom(); + map(0x0800, 0x08ff).mirror(0x0700).ram(); +} + +void cmpchess_state::main_io(address_map &map) +{ + map(0x00, 0x00).rw(FUNC(cmpchess_state::input_r), FUNC(cmpchess_state::input_digit_data_w)); + map(0x01, 0x01).w(FUNC(cmpchess_state::digit_select_w)); + map(0x0c, 0x0f).rw("smi", FUNC(f3853_device::read), FUNC(f3853_device::write)); +} + +void cmpchess_state::cncchess_map(address_map &map) +{ + map(0x0000, 0x07ff).rom(); + map(0x1800, 0x18ff).ram(); + map(0x8000, 0xffff).r(FUNC(cmpchess_state::beeper_r)); +} + +void cmpchess_state::cncchess_io(address_map &map) +{ + map(0x00, 0x00).rw(FUNC(cmpchess_state::digit_data_r), FUNC(cmpchess_state::digit_data_w)); + map(0x01, 0x01).rw(FUNC(cmpchess_state::input_r), FUNC(cmpchess_state::input_digit_select_w)); + map(0x0c, 0x0f).rw("smi", FUNC(f3853_device::read), FUNC(f3853_device::write)); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( cmpchess ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_D) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("D / Play") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("C / White Bishop") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("B / White Queen") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_A) PORT_NAME("A / White King") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_M) PORT_NAME("H / md") // more data + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) PORT_NAME("G / White Pawn") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F) PORT_NAME("F / White Rook") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("E / White Knight") + + PORT_START("IN.2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4 / fp") // find piece(position) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3 / Black Bishop") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2 / Black Queen") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1 / Black King") + + PORT_START("IN.3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("8 / ep") // enter piece(position) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("7 / Black Pawn") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6 / Black Rook") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5 / Black Knight") + + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CODE(KEYCODE_F1) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(cmpchess_state::reset_switch), 0) PORT_NAME("Reset Switch") +INPUT_PORTS_END + +static INPUT_PORTS_START( mk1 ) + PORT_INCLUDE( cmpchess ) + + PORT_MODIFY("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CODE(KEYCODE_F1) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(cmpchess_state::reset_switch), 0) PORT_NAME("L.S. Switch") + + PORT_START("CPU") + PORT_CONFNAME( 0x01, 0x00, "CPU Frequency" ) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(cmpchess_state::change_cpu_freq), 0) // factory set + PORT_CONFSETTING( 0x00, "2.25MHz (Spassky packaging)" ) + PORT_CONFSETTING( 0x01, "3.5MHz (Karpov packaging)" ) +INPUT_PORTS_END + +static INPUT_PORTS_START( cncchess ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4 / Black Bishop") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3 / Black Knight") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2 / Black Rook") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1 / Black Pawn") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_I) PORT_NAME("8 / IP") // insert piece (same as ep) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_S) PORT_NAME("7 / SP") // search piece (same as fp) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6 / Black King") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5 / Black Queen") + + PORT_START("IN.2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_D) PORT_NAME("D / White Bishop") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("C / White Knight") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("B / White Rook") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_A) PORT_NAME("A / White Pawn") + + PORT_START("IN.3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("H / GO") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) PORT_CODE(KEYCODE_M) PORT_NAME("G / MD") // more data + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F) PORT_NAME("F / White King") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("E / White Queen") + + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(cmpchess_state::reset_switch), 0) PORT_NAME("Reset") +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void cmpchess_state::cmpchess(machine_config &config) +{ + // basic machine hardware + F8(config, m_maincpu, 2_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &cmpchess_state::main_map); + m_maincpu->set_addrmap(AS_IO, &cmpchess_state::main_io); + m_maincpu->set_irq_acknowledge_callback("smi", FUNC(f3853_device::int_acknowledge)); + + f3853_device &smi(F3853(config, "smi", 2_MHz_XTAL)); + smi.int_req_callback().set_inputline("maincpu", F8_INPUT_LINE_INT_REQ); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(4, 8+1); + m_display->set_segmask(0xf, 0xff); + config.set_default_layout(layout_cmpchess); + + const attotime blink_period = attotime::from_msec(200); // approximation + TIMER(config, "blink_display").configure_periodic(FUNC(cmpchess_state::blink), blink_period); +} + +void cmpchess_state::cmpchess2(machine_config &config) +{ + cmpchess(config); + + // basic machine hardware + m_maincpu->set_clock(3.579545_MHz_XTAL); + subdevice<f3853_device>("smi")->set_clock(3.579545_MHz_XTAL); +} + +void cmpchess_state::mk1(machine_config &config) +{ + cmpchess(config); + + // basic machine hardware + m_maincpu->set_clock(2'250'000); // see notes + subdevice<f3853_device>("smi")->set_clock(2'250'000); + + config.set_default_layout(layout_novag_mk1); +} + +void cmpchess_state::cncchess(machine_config &config) +{ + cmpchess2(config); + + // basic machine hardware + m_maincpu->set_clock(2'000'000); // LC circuit, measured 2MHz + m_maincpu->set_addrmap(AS_PROGRAM, &cmpchess_state::cncchess_map); + m_maincpu->set_addrmap(AS_IO, &cmpchess_state::cncchess_io); + + subdevice<f3853_device>("smi")->set_clock(2'000'000); + + config.set_default_layout(layout_conic_cchess); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + BEEP(config, m_beeper, 2000); // wrong, see TODO + m_beeper->add_route(ALL_OUTPUTS, "speaker", 0.25); + TIMER(config, "beeper_off").configure_generic(FUNC(cmpchess_state::beeper_off)); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( cmpchess ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("32014-4950_cmcsi_staid.u3", 0x0000, 0x0800, CRC(278f7bf3) SHA1(b384c95ba691d52dfdddd35987a71e9746a46170) ) +ROM_END + +ROM_START( cmpchess2 ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("8316a-4952_cmc2_staid.u3", 0x0000, 0x0800, CRC(aee49c5f) SHA1(8a10f74207f2646164cc0deed81bd082143ac38a) ) +ROM_END + + +ROM_START( ccmk1 ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("82c210-1", 0x0000, 0x0800, CRC(278f7bf3) SHA1(b384c95ba691d52dfdddd35987a71e9746a46170) ) +ROM_END + + +ROM_START( cncchess ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD("c48170.u1", 0x0000, 0x0800, CRC(5beace32) SHA1(9df924037614831a86b73eb3a16bbc80c63257a2) ) // 2316B +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1977, cmpchess, 0, 0, cmpchess, cmpchess, cmpchess_state, empty_init, "DataCash Systems / Staid", "CompuChess", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) // aka CompuChess I +SYST( 1978, cmpchess2, 0, 0, cmpchess2, cmpchess, cmpchess_state, empty_init, "DataCash Systems / Staid", "CompuChess: The Second Edition", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) + +SYST( 1978, ccmk1, cmpchess, 0, mk1, mk1, cmpchess_state, empty_init, "bootleg (Novag Industries)", "Chess Champion: MK I", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) + +SYST( 1979, cncchess, 0, 0, cncchess, cncchess, cmpchess_state, empty_init, "Conic", "Computer Chess (Conic, model 7011)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/conchess.cpp b/src/mame/chess/conchess.cpp new file mode 100644 index 00000000000..05f858a33ca --- /dev/null +++ b/src/mame/chess/conchess.cpp @@ -0,0 +1,389 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:Berger, Mr. Lars +/******************************************************************************* + +Conchess, a series of modular chess computers by Consumenta Computer. + +Hardware development by Loproc (Germany), manufactured at Wallharn Electronics +(Ireland). The core people involved were Ulf Rathsman for the chess engine, +and Johan Enroth. After Consumenta went under in 1983, the Conchess brand was +continued by Systemhuset. + +TODO: +- concglap/concglapa rom labels +- dump/add concvicp library module (L/L16 don't work, manual says it has its own add-on) +- concvicp unmapped reads/writes +- verify irq/beeper for concvicp, though it is probably correct + +================================================================================ + +Hardware notes: + +Chess boards released were Escorter, Ambassador, and Monarch, each should be the +same hardware, they just differ in size and material. +- TTL, 2 module slots +- 16+64 leds, 16 buttons, reed sensors for magnet chesspieces + +All chess modules appear to be on similar PCBs, with room a 6502/65C02, +and 8 ROM/RAM chips. + +For the newer programs, higher clocked versions were also available, the CPU speed +was labeled on a sticker on the module (eg. A2/5.5MHz). A German redistributor +named them "S"(speed) or "T"(top speed). + +A0 (untitled standard pack-in module): +- SY6502A @ 2MHz (4MHz XTAL) +- 3*8KB ROM, 4KB RAM(2*TMM2016P) +- TTL, beeper + +note: XTAL goes to 4020, 4020 /2 goes to CPU clock, and other dividers to +IRQ and beeper. On A0, IRQ is active for ~31.2us. + +A1(P) + A0(M) (Princhess, aka Glasgow) +- dual-module, 2nd module has no CPU (according to the manual, A0 is modified and + won't work stand-alone) +- dual-module Amsterdam version also exists + +A2(C) (Plymate, aka Amsterdam) +- R65C02P4 @ 5.5MHz (11MHz XTAL) (5.5MHz version) +- 32KB ROM, rest similar to A0 + +A3 (Plymate Victoria) +- W65C02S8P-14(14? probably replaced chip from a repair) @ 6.144MHz (12.288MHz XTAL) +- 32KB ROM, rest similar to A0 + +Library modules: +- L: small PCB, PCB label: CCL L-2, 8KB EPROM no label +- L16: 2*8KB EPROM (have no photo of PCB) + +There are also modern bootleg boards from SteveUK in circulation. The library ROM +is integrated. + +*******************************************************************************/ + +#include "emu.h" + +#include "bus/generic/carts.h" +#include "bus/generic/slot.h" +#include "cpu/m6502/m6502.h" +#include "cpu/m6502/r65c02.h" +#include "cpu/m6502/w65c02.h" +#include "machine/sensorboard.h" +#include "sound/beep.h" +#include "video/pwm.h" + +#include "softlist_dev.h" +#include "speaker.h" + +// internal artwork +#include "conchess.lh" + + +namespace { + +class conchess_state : public driver_device +{ +public: + conchess_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_board(*this, "board"), + m_beeper(*this, "beeper"), + m_inputs(*this, "IN.%u", 0) + { } + + // machine configs + void conc(machine_config &config); + void concgla(machine_config &config); + void concams(machine_config &config); + void concams5(machine_config &config); + void concvicp(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device<pwm_display_device> m_display; + required_device<sensorboard_device> m_board; + required_device<beep_device> m_beeper; + required_ioport_array<2> m_inputs; + + u8 m_inp_mux = 0; + + // address maps + void main_map(address_map &map) ATTR_COLD; + + // I/O handlers + void clear_irq(); + u8 input_r(); + void leds_w(offs_t offset, u8 data); + void sound_w(u8 data); +}; + +void conchess_state::machine_start() +{ + save_item(NAME(m_inp_mux)); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +void conchess_state::clear_irq() +{ + m_maincpu->set_input_line(0, CLEAR_LINE); +} + +u8 conchess_state::input_r() +{ + if (!machine().side_effects_disabled()) + clear_irq(); + + u8 data = 0; + + // read side panel buttons + if (m_inp_mux == 0 || m_inp_mux == 9) + data = m_inputs[m_inp_mux & 1]->read(); + + // read chessboard sensors + else + data = m_board->read_file((m_inp_mux - 1) ^ 7); + + return ~data; +} + +void conchess_state::leds_w(offs_t offset, u8 data) +{ + clear_irq(); + + // a0-a3: CD4028B to led select/input mux + m_inp_mux = offset; + if (m_inp_mux & 8) + m_inp_mux &= 9; + + // d0-d7: led data + m_display->matrix(1 << m_inp_mux, data); +} + +void conchess_state::sound_w(u8 data) +{ + // d7: enable beeper + m_beeper->set_state(BIT(data, 7)); +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void conchess_state::main_map(address_map &map) +{ + map(0x0000, 0x0fff).ram(); + map(0x1000, 0x1000).mirror(0x07ff).r(FUNC(conchess_state::input_r)); + map(0x1000, 0x100f).mirror(0x07f0).w(FUNC(conchess_state::leds_w)); + map(0x1800, 0x1800).mirror(0x07ff).w(FUNC(conchess_state::sound_w)); + map(0x4000, 0x7fff).r("cartslot", FUNC(generic_slot_device::read_rom)); + map(0x8000, 0xffff).rom(); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( conchess ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Q) PORT_NAME("O. (Clear)") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("Stop") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("Dice Symbol (Alternate)") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("?-Sign (Analyze)") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("Section Sign (Referee)") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Y) PORT_NAME("4-Way Arrow (Piece)") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) PORT_NAME("2-Way Arrow (Level)") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) PORT_NAME(". (Continue)") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Pawn") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Knight") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Bishop") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Rook") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Queen") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("King") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("White") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Black") +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void conchess_state::conc(machine_config &config) +{ + // basic machine hardware + M6502(config, m_maincpu, 4_MHz_XTAL/2); + m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); + + const attotime irq_period = attotime::from_hz(4_MHz_XTAL / 0x2000); + m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); + m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); + m_board->set_delay(attotime::from_msec(150)); + + GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "conchess_cart"); + SOFTWARE_LIST(config, "cart_list").set_original("conchess").set_filter("l"); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(10, 8); + config.set_default_layout(layout_conchess); + + // sound hardware + SPEAKER(config, "mono").front_center(); + BEEP(config, m_beeper, 4_MHz_XTAL / 0x400); + m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); +} + +void conchess_state::concgla(machine_config &config) +{ + conc(config); + + // basic machine hardware + R65C02(config.replace(), m_maincpu, 4_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); + + const attotime irq_period = attotime::from_hz(4_MHz_XTAL / 0x2000); + m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); + + subdevice<software_list_device>("cart_list")->set_filter("none"); + + // sound hardware + BEEP(config.replace(), m_beeper, 4_MHz_XTAL / 0x400); + m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); +} + +void conchess_state::concams(machine_config &config) +{ + concgla(config); + + // basic machine hardware + subdevice<software_list_device>("cart_list")->set_filter("l16"); +} + +void conchess_state::concams5(machine_config &config) +{ + concams(config); + + // basic machine hardware + m_maincpu->set_clock(11_MHz_XTAL/2); + + const attotime irq_period = attotime::from_hz(11_MHz_XTAL / 0x4000); + m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); + + // sound hardware + BEEP(config.replace(), m_beeper, 11_MHz_XTAL / 0x800); + m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); +} + +void conchess_state::concvicp(machine_config &config) +{ + concams5(config); + + // basic machine hardware + W65C02(config.replace(), m_maincpu, 12.288_MHz_XTAL/2); + m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); + + const attotime irq_period = attotime::from_hz(12.288_MHz_XTAL / 0x4000); + m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); + + subdevice<software_list_device>("cart_list")->set_filter("l1024"); + + // sound hardware + BEEP(config.replace(), m_beeper, 12.288_MHz_XTAL / 0x1000); + m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( conc ) // 2 bytes different (bookrom fix) + ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD("ccp2.a", 0xa000, 0x1000, CRC(fddd155b) SHA1(ccb67543f4d680b47d2956b284d5c6b7a8d21520) ) // MBM2732A-30 + ROM_LOAD("ccp2.b", 0xb000, 0x1000, CRC(81cf6b20) SHA1(7f6e30e50c6f9b633767a04b7d7a9c291d301614) ) // " + ROM_LOAD("ccp2.c", 0xc000, 0x1000, CRC(151eca1a) SHA1(40b97bce2ff0cae528efa3a9bab5767d5d15d369) ) // " + ROM_LOAD("ccp2.d", 0xd000, 0x1000, CRC(ed5dafeb) SHA1(3f0cea45bf26d9a1d120963480fc883a00185224) ) // " + ROM_LOAD("ccp2.e", 0xe000, 0x1000, CRC(f07bf0e2) SHA1(e4f2f415144ed5e43f4940c7c9618e89707d19e9) ) // " + ROM_LOAD("ccp2.f", 0xf000, 0x1000, CRC(7a04b000) SHA1(72d702b91adc643201ac6cea7aeb9394a3afc8be) ) // " +ROM_END + +ROM_START( conca ) // 6 EPROMs version also exists, same ROM contents + ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD("c87011_ccp2ab.b3", 0xa000, 0x2000, CRC(915e414c) SHA1(80c94712d1c79fa469576c37b80ab66f77c77cc4) ) // C2C076 serial also seen, same ROM contents + ROM_LOAD("c87010_ccp2cd.b2", 0xc000, 0x2000, CRC(088c8737) SHA1(9f841b3c47de9ef1da8ce98c0a33a919cba873c6) ) + ROM_LOAD("c87009_ccp2ef.b1", 0xe000, 0x2000, CRC(e1c648e2) SHA1(725a6ac1c69f788a7bba0573e5609b55b12899ac) ) +ROM_END + +ROM_START( concgla ) // 8 EPROMs version also exists, same ROM contents + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("9128c-0133", 0x8000, 0x4000, CRC(a6ac88eb) SHA1(d1fcd990e5196c00210d380e0e04155a5ea19824) ) // GI 9128C + ROM_LOAD("9128c-0134", 0xc000, 0x4000, CRC(b694a275) SHA1(e4e49379b4eb45402ca8bb82c20d0169db62ed7a) ) // " +ROM_END + +ROM_START( concglap ) // 2 bytes different + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("ccplus", 0x8000, 0x8000, CRC(c62e522b) SHA1(28ea9af35f9f4e96e52c19597d62e0af135c7672) ) +ROM_END + +ROM_START( concglapa ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("ccplus", 0x8000, 0x8000, CRC(0bf4d2d0) SHA1(0ce670d3be1ae4da5467be6b062cfe73dcfbf229) ) +ROM_END + +ROM_START( concams ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("8b_4.0_133", 0x8000, 0x4000, CRC(e021e3d8) SHA1(7a2c079664ed5cbaa7e5c55d4d2e8936b7be4219) ) // SEEQ DQ5143-250 + ROM_LOAD("cf_4.0_134", 0xc000, 0x4000, CRC(fc827c7f) SHA1(51acd881c4d5fe29f2a83d35a48ba323344122db) ) // " +ROM_END + +ROM_START( concams5 ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("s5.a1", 0x8000, 0x8000, CRC(9a9d1ec1) SHA1(75dbd1f96502775ed304f6b085d958f1b07d08f9) ) // AT27C256 +ROM_END + +ROM_START( concvicp ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("cc8-f.a2", 0x8000, 0x8000, CRC(5b0a1d09) SHA1(07cbc970a8dfbca386396ce5d5cc8ce77ad4ee1b) ) +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1982, conc, 0, 0, conc, conchess, conchess_state, empty_init, "Consumenta Computer / Loproc", "Conchess (standard, set 1)", MACHINE_SUPPORTS_SAVE ) +SYST( 1982, conca, conc, 0, conc, conchess, conchess_state, empty_init, "Consumenta Computer / Loproc", "Conchess (standard, set 2)", MACHINE_SUPPORTS_SAVE ) + +SYST( 1984, concgla, 0, 0, concgla, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Princhess Glasgow", MACHINE_SUPPORTS_SAVE ) +SYST( 1984, concglap, 0, 0, concgla, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Plymate Glasgow Plus (set 1)", MACHINE_SUPPORTS_SAVE ) +SYST( 1984, concglapa, concglap, 0, concgla, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Plymate Glasgow Plus (set 2)", MACHINE_SUPPORTS_SAVE ) + +SYST( 1985, concams, 0, 0, concams, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Plymate Amsterdam", MACHINE_SUPPORTS_SAVE ) +SYST( 1985, concams5, concams, 0, concams5, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Plymate Amsterdam 5.5MHz", MACHINE_SUPPORTS_SAVE ) + +SYST( 1990, concvicp, 0, 0, concvicp, conchess, conchess_state, empty_init, "Systemhuset / Loproc", "Conchess Plymate Victoria (prototype)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/conic_cchess2.cpp b/src/mame/chess/conic_cchess2.cpp new file mode 100644 index 00000000000..5ceefadad1b --- /dev/null +++ b/src/mame/chess/conic_cchess2.cpp @@ -0,0 +1,285 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:bataais +/******************************************************************************* + +Conic Computer Chess (model 07012), also sold under the same name by +Hanimex (model HMG 1200) and Westrak (model CC 1). It's also known as +Tracer Chess, this title is from an advertisement flyer, the actual chess +computer was simply named Computer Chess. + +The chessboard sensors aren't buttons or magnets, but 64 jacks. There is +a metal plug under each chesspiece. From MAME's perspective, it works the +same as a magnet sensorboard. + +After the player's move, the user needs to press Enter. This does not apply +to the computer's move. + +Hardware notes: +- Synertek 6504 @ ~1MHz +- 2*Motorola MC6821P PIA +- 4KB ROM(AMI), 1KB RAM(2*Synertek 1024x4) +- beeper, 8*8 leds, plug board + +BTANB: +- Learn button still works when in modify-mode + +*******************************************************************************/ + +#include "emu.h" + +#include "cpu/m6502/m6504.h" +#include "machine/6821pia.h" +#include "machine/sensorboard.h" +#include "sound/dac.h" +#include "video/pwm.h" + +#include "speaker.h" + +// internal artwork +#include "conic_cchess2.lh" + + +namespace { + +class cchess2_state : public driver_device +{ +public: + cchess2_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_pia(*this, "pia%u", 0), + m_board(*this, "board"), + m_display(*this, "display"), + m_dac(*this, "dac"), + m_inputs(*this, "IN.%u", 0) + { } + + // machine configs + void cncchess2(machine_config &config); + + // assume that RESET button is tied to 6504 reset pin + DECLARE_INPUT_CHANGED_MEMBER(reset_button) { m_maincpu->set_input_line(INPUT_LINE_RESET, newval ? ASSERT_LINE : CLEAR_LINE); } + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device_array<pia6821_device, 2> m_pia; + required_device<sensorboard_device> m_board; + required_device<pwm_display_device> m_display; + required_device<dac_1bit_device> m_dac; + required_ioport_array<8> m_inputs; + + u8 m_inp_mux = 0; + u8 m_led_data = 0; + u8 m_dac_on = 0; + + // address maps + void main_map(address_map &map) ATTR_COLD; + + // I/O handlers + void update_display(); + void update_dac(); + void pia0_pa_w(u8 data); + void pia0_pb_w(u8 data); + u8 pia1_pa_r(); + u8 pia1_pb_r(); + void pia1_pb_w(u8 data); +}; + +void cchess2_state::machine_start() +{ + save_item(NAME(m_inp_mux)); + save_item(NAME(m_led_data)); + save_item(NAME(m_dac_on)); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +void cchess2_state::update_display() +{ + m_display->matrix(m_inp_mux, m_led_data); +} + +void cchess2_state::update_dac() +{ + m_dac->write(m_dac_on & BIT(m_inp_mux, 1)); +} + +void cchess2_state::pia0_pa_w(u8 data) +{ + // d0-d7: input mux/led select + // d1: dac data + m_inp_mux = data; + update_display(); + update_dac(); +} + +void cchess2_state::pia0_pb_w(u8 data) +{ + // d0-d7: led data + m_led_data = data; + update_display(); +} + +u8 cchess2_state::pia1_pa_r() +{ + u8 data = 0; + + // d0-d7: chessboard sensors + for (int i = 0; i < 8; i++) + if (BIT(m_inp_mux, i)) + data |= m_board->read_rank(i); + + return ~data; +} + +u8 cchess2_state::pia1_pb_r() +{ + u8 data = 0; + + // d0-d3: multiplexed inputs + for (int i = 0; i < 8; i++) + if (BIT(m_inp_mux, i)) + data |= m_inputs[i]->read(); + + return data; +} + +void cchess2_state::pia1_pb_w(u8 data) +{ + // d7: dac on + m_dac_on = BIT(data, 7); + update_dac(); +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void cchess2_state::main_map(address_map &map) +{ + map.global_mask(0x1fff); + map(0x0000, 0x03ff).ram(); + map(0x0a00, 0x0a03).mirror(0x00fc).rw(m_pia[0], FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0x0c00, 0x0c03).mirror(0x00fc).rw(m_pia[1], FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0x1000, 0x1fff).rom(); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( cncchess2 ) + PORT_START("IN.0") + PORT_BIT(0x03, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_CONFNAME( 0x0c, 0x08, "Mode" ) + PORT_CONFSETTING( 0x04, "Modify" ) + PORT_CONFSETTING( 0x08, "Play" ) + + PORT_START("IN.1") + PORT_CONFNAME( 0x03, 0x02, "Color" ) + PORT_CONFSETTING( 0x01, "Black" ) // from the bottom + PORT_CONFSETTING( 0x02, "White" ) + PORT_BIT(0x0c, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.2") + PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.3") + PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.4") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("Enter") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_N) PORT_NAME("Learn") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Level") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_NAME("6 / White King") + + PORT_START("IN.5") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_NAME("5 / White Queen") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_NAME("4 / White Rook") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_NAME("3 / White Bishop") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_NAME("2 / White Knight") + + PORT_START("IN.6") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_NAME("1 / White Pawn") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_DEL) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Clear") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_NAME("7 / Black Pawn") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_NAME("8 / Black Knight") + + PORT_START("IN.7") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_9) PORT_NAME("9 / Black Bishop") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_0) PORT_NAME("10 / Black Rook") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_MINUS) PORT_NAME("11 / Black Queen") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("12 / Black King") + + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(cchess2_state::reset_button), 0) PORT_NAME("Reset") +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void cchess2_state::cncchess2(machine_config &config) +{ + // basic machine hardware + M6504(config, m_maincpu, 1'000'000); // approximation, no XTAL + m_maincpu->set_addrmap(AS_PROGRAM, &cchess2_state::main_map); + + PIA6821(config, m_pia[0]); + m_pia[0]->writepa_handler().set(FUNC(cchess2_state::pia0_pa_w)); + m_pia[0]->writepb_handler().set(FUNC(cchess2_state::pia0_pb_w)); + + PIA6821(config, m_pia[1]); + m_pia[1]->readpa_handler().set(FUNC(cchess2_state::pia1_pa_r)); + m_pia[1]->readpb_handler().set(FUNC(cchess2_state::pia1_pb_r)); + m_pia[1]->writepb_handler().set(FUNC(cchess2_state::pia1_pb_w)); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); + m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); + m_board->set_delay(attotime::from_msec(150)); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(8, 8); + config.set_default_layout(layout_conic_cchess2); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( cncchess2 ) + ROM_REGION( 0x2000, "maincpu", 0 ) + ROM_LOAD("c11485.u2", 0x1000, 0x1000, CRC(b179d536) SHA1(0b1f9c247a4a3e2ccbf8d3ae5efa62b8938f572f) ) // AMI 2332 +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1980, cncchess2, 0, 0, cncchess2, cncchess2, cchess2_state, empty_init, "Conic", "Computer Chess (Conic, model 7012)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/conic_cchess3.cpp b/src/mame/chess/conic_cchess3.cpp new file mode 100644 index 00000000000..3f9de4aa4ad --- /dev/null +++ b/src/mame/chess/conic_cchess3.cpp @@ -0,0 +1,161 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:Berger +/******************************************************************************* + +Conic Computer Chess (model 07013), more commonly known as Conic "Korchnoi". + +The interface is similar to the previous model (07012), where the user needs +to press Enter after their move. + +Hardware notes: +- Synertek 6502A @ 2MHz +- OKI MSM5840H-41RS @ 3.57MHz (2KB internal ROM) +- 2*4KB ROM(AMI), 1KB RAM(2*2114) +- beeper, 8*8+4 leds, magnets chessboard + +TODO: +- It does not work, MSM5840 is unemulated, and the internal ROM is not dumped. + MCU handles inputs, leds, sound, and it communicates with maincpu after + triggering an IRQ. + +*******************************************************************************/ + +#include "emu.h" + +#include "cpu/m6502/m6502.h" +#include "machine/sensorboard.h" +#include "sound/dac.h" +#include "video/pwm.h" + +#include "speaker.h" + +// internal artwork +//#include "conic_cchess3.lh" + + +namespace { + +class cchess3_state : public driver_device +{ +public: + cchess3_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_board(*this, "board"), + m_display(*this, "display"), + m_dac(*this, "dac") + { } + + // machine configs + void cncchess3(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device<sensorboard_device> m_board; + required_device<pwm_display_device> m_display; + required_device<dac_1bit_device> m_dac; + + void main_map(address_map &map) ATTR_COLD; + + // I/O handlers + void main_comm_w(u8 data); + u8 main_comm_r(); +}; + +void cchess3_state::machine_start() +{ +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +void cchess3_state::main_comm_w(u8 data) +{ +} + +u8 cchess3_state::main_comm_r() +{ + return 0; +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void cchess3_state::main_map(address_map &map) +{ + map.global_mask(0x3fff); + map(0x0000, 0x03ff).ram(); + map(0x1000, 0x1000).rw(FUNC(cchess3_state::main_comm_r), FUNC(cchess3_state::main_comm_w)); + map(0x2000, 0x3fff).rom(); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( cncchess3 ) +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void cchess3_state::cncchess3(machine_config &config) +{ + // basic machine hardware + M6502(config, m_maincpu, 2_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &cchess3_state::main_map); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); + m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); + m_board->set_delay(attotime::from_msec(150)); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(8+1, 8); + //config.set_default_layout(layout_conic_cchess3); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( cncchess3 ) + ROM_REGION( 0x4000, "maincpu", 0 ) + ROM_LOAD("ci07013-1", 0x2000, 0x1000, CRC(3251a529) SHA1(729b22d7653761ff0951ce1da58fdfcd474a700d) ) // AMI 2332 + ROM_LOAD("ci07013-2", 0x3000, 0x1000, CRC(0f38dcef) SHA1(f8fb7e12b41753fe52dd2eb2edb843211b5ca7c1) ) // " + + ROM_REGION( 0x0800, "mcu", 0 ) + ROM_LOAD("msm5840h-41rs", 0x0000, 0x0800, NO_DUMP ) +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1981, cncchess3, 0, 0, cncchess3, cncchess3, cchess3_state, empty_init, "Conic", "Computer Chess (Conic, model 7013)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) diff --git a/src/mame/chess/krypton_regency.cpp b/src/mame/chess/krypton_regency.cpp new file mode 100644 index 00000000000..c1453f8b5ef --- /dev/null +++ b/src/mame/chess/krypton_regency.cpp @@ -0,0 +1,350 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:Berger +/******************************************************************************* + +Krypton Regency (model 933) + +It was manufactured by Timorite, Ltd. (Eric White's company), the chess engine is +by Gyula Horváth, similar to the one in CXG Sphinx Legend. + +To start a new game, keep holding the NEW GAME button until the display says HELLO. + +Hardware notes (Systema Challenge fitted with Regency MCU): +- PCB label: LCD CHESS 938, JAN.1994, REV.1, EB-093801-01 +- Hitachi H8/3256 MCU, 20MHz XTAL +- LCD with 5 7segs and custom segments +- piezo, 16 LEDs (optional), button sensors chessboard + +A26 MCU was used in: +- Krypton Regency (with or without LEDs) +- Excalibur Avenger (suspected, Excalibur brand Comet, with newer MCU) +- Excalibur Legend III (suspected, Excalibur brand Regency) +- Systema Challenge (1996 version) + +TODO: +- CXG Sphinx Legend may be on the same hardware? if so, move driver to cxg folder +- is Krypton a product brand, or a company alias for the Chinese factory behind it? +- 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 + +*******************************************************************************/ + +#include "emu.h" + +#include "cpu/h8/h8325.h" +#include "machine/sensorboard.h" +#include "sound/dac.h" +#include "video/pwm.h" + +#include "screen.h" +#include "speaker.h" + +// internal artwork +#include "krypton_regency.lh" + + +namespace { + +class regency_state : public driver_device +{ +public: + regency_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_board(*this, "board"), + m_led_pwm(*this, "led_pwm"), + 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) + { } + + void regency(machine_config &config); + + DECLARE_INPUT_CHANGED_MEMBER(in1_changed) { update_irq2(); } + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + // devices/pointers + required_device<h83256_device> m_maincpu; + required_device<sensorboard_device> m_board; + required_device<pwm_display_device> m_led_pwm; + 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; + + u16 m_inp_mux = 0; + u8 m_inp_mux2 = 0; + u32 m_lcd_segs = 0; + u8 m_lcd_com = 0; + + // I/O handlers + void lcd_pwm_w(offs_t offset, u8 data); + void update_lcd(); + template <int N> void lcd_segs_w(u8 data); + + void standby(int state); + int update_irq2(); + + void p2_w(u8 data); + void p5_w(offs_t offset, u8 data, u8 mem_mask); + u8 p6_r(); + void p6_w(offs_t offset, u8 data, u8 mem_mask); + u8 p7_r(); + void p7_w(u8 data); +}; + +void regency_state::machine_start() +{ + m_out_lcd.resolve(); + + // register for savestates + save_item(NAME(m_inp_mux)); + save_item(NAME(m_inp_mux2)); + save_item(NAME(m_lcd_segs)); + save_item(NAME(m_lcd_com)); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +// power + +void regency_state::standby(int state) +{ + // clear display + if (state) + { + m_lcd_pwm->clear(); + m_led_pwm->clear(); + } +} + +int regency_state::update_irq2() +{ + // 2nd button row is tied to IRQ2 (used for on/off button) + int state = (m_inp_mux2 & m_inputs[1]->read()) ? ASSERT_LINE : CLEAR_LINE; + m_maincpu->set_input_line(INPUT_LINE_IRQ2, state); + + return state; +} + + +// LCD + +void regency_state::lcd_pwm_w(offs_t offset, u8 data) +{ + m_out_lcd[offset & 0x3f][offset >> 6] = data; +} + +void regency_state::update_lcd() +{ + u32 lcd_segs = bitswap<24>(m_lcd_segs,1,0, 15,14,13,12,11,10,9,8, 16,17,23,22,21,20,19,18, 25,26,27,28,29,31); + + for (int i = 0; i < 2; i++) + { + // LCD common is 0/1/Hi-Z + const u32 data = BIT(m_lcd_com, i + 2) ? (BIT(m_lcd_com, i) ? ~lcd_segs : lcd_segs) : 0; + m_lcd_pwm->write_row(i, data); + } +} + +template <int N> +void regency_state::lcd_segs_w(u8 data) +{ + // P1x, P3x, P4x, P6x: LCD segments + const u8 shift = 8 * N; + m_lcd_segs = (m_lcd_segs & ~(0xff << shift)) | (data << shift); + update_lcd(); +} + + +// misc + +void regency_state::p2_w(u8 data) +{ + // P20-P27: input mux (chessboard), LED data + m_inp_mux = (m_inp_mux & 0x300) | (data ^ 0xff); + m_led_pwm->write_mx(~data); +} + +void regency_state::p5_w(offs_t offset, u8 data, u8 mem_mask) +{ + // P50: LCD common 2 + m_lcd_com = (m_lcd_com & 5) | (data << 1 & 2) | (mem_mask << 3 & 8); + update_lcd(); + + // P51: speaker out + m_dac->write(BIT(~data, 1)); + + // P52: input mux part + m_inp_mux = (m_inp_mux & 0x2ff) | (BIT(~data, 2) << 8); + + // P54,P55: LED select + m_led_pwm->write_my(~data >> 4 & 3); +} + +u8 regency_state::p6_r() +{ + // P65: battery status + u8 data = m_inputs[2]->read() << 5 & 0x20; + + // P66: IRQ2 pin + if (!machine().side_effects_disabled() && update_irq2()) + data |= 0x40; + + return ~data; +} + +void regency_state::p6_w(offs_t offset, u8 data, u8 mem_mask) +{ + // P60,P61: LCD segs + lcd_segs_w<0>(data & 3); + + // P62: LCD common 1 + m_lcd_com = (m_lcd_com & 0xa) | (BIT(data, 2)) | (mem_mask & 4); + update_lcd(); + + // P66: input mux part + m_inp_mux = (m_inp_mux & 0x1ff) | (BIT(~data, 6) << 9); +} + +u8 regency_state::p7_r() +{ + // P70-P77: multiplexed inputs + u8 data = 0; + + // read buttons + for (int i = 0; i < 2; i++) + if (BIT(m_inp_mux, i + 8)) + data |= m_inputs[i]->read(); + + // read chessboard + for (int i = 0; i < 8; i++) + if (BIT(m_inp_mux, i)) + data |= m_board->read_file(i ^ 7); + + return ~data; +} + +void regency_state::p7_w(u8 data) +{ + // P70-P77: input mux (other way around) + m_inp_mux2 = ~data; + update_irq2(); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +#define PORT_CHANGED_IN1() \ + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(regency_state::in1_changed), 0) + +static INPUT_PORTS_START( regency ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Knight / Lose") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Queen") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) PORT_NAME("Set-Up / Features") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Level") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F) PORT_NAME("Step Forward") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) PORT_NAME("Multi-Move / Analysis") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Rook / Win") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Pawn / Rating") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_F1) PORT_NAME("On / Off") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("King") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_M) PORT_NAME("Move / Swap Board") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_O) PORT_NAME("Sound / Style") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_T) PORT_NAME("Take Back") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_H) PORT_NAME("Hint / Info") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Bishop / Draw") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CHANGED_IN1() PORT_CODE(KEYCODE_N) PORT_NAME("New Game / Clear Board") + + PORT_START("IN.2") + PORT_CONFNAME( 0x01, 0x01, "Battery Status" ) + PORT_CONFSETTING( 0x00, "Low" ) + PORT_CONFSETTING( 0x01, DEF_STR( Normal ) ) +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void regency_state::regency(machine_config &config) +{ + // basic machine hardware + H83256(config, m_maincpu, 20_MHz_XTAL); + m_maincpu->nvram_enable_backup(true); + m_maincpu->standby_cb().set(m_maincpu, FUNC(h83256_device::nvram_set_battery)); + m_maincpu->standby_cb().append(FUNC(regency_state::standby)); + m_maincpu->write_port1().set(FUNC(regency_state::lcd_segs_w<2>)); + m_maincpu->read_port2().set_constant(0xef); // hardware config? + m_maincpu->write_port2().set(FUNC(regency_state::p2_w)); + m_maincpu->write_port3().set(FUNC(regency_state::lcd_segs_w<1>)); + m_maincpu->write_port4().set(FUNC(regency_state::lcd_segs_w<3>)); + m_maincpu->read_port5().set_constant(0xff); + m_maincpu->write_port5().set(FUNC(regency_state::p5_w)); + m_maincpu->read_port6().set(FUNC(regency_state::p6_r)); + m_maincpu->write_port6().set(FUNC(regency_state::p6_w)); + m_maincpu->read_port7().set(FUNC(regency_state::p7_r)); + m_maincpu->write_port7().set(FUNC(regency_state::p7_w)); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS); + m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); + m_board->set_delay(attotime::from_msec(150)); + //m_board->set_nvram_enable(true); + + // video hardware + PWM_DISPLAY(config, m_lcd_pwm).set_size(2, 24); + m_lcd_pwm->output_x().set(FUNC(regency_state::lcd_pwm_w)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_SVG)); + screen.set_refresh_hz(60); + screen.set_size(1920/5, 697/5); + screen.set_visarea_full(); + + PWM_DISPLAY(config, m_led_pwm).set_size(2, 8); + config.set_default_layout(layout_krypton_regency); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( regency ) + ROM_REGION16_BE( 0xc000, "maincpu", 0 ) + ROM_LOAD("1996_933_timorite_hd6433256a26p.ic1", 0x0000, 0xc000, CRC(72eb3f2b) SHA1(30e4166e351210475cf9709b0feb717d9d3ac747) ) + + ROM_REGION( 109652, "screen", 0 ) + ROM_LOAD("regency.svg", 0, 109652, CRC(6840c49e) SHA1(a9c91143c5bea5ab41fe323e719da4a46ab9d631) ) +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1996, regency, 0, 0, regency, regency, regency_state, empty_init, "Krypton / Timorite", "Regency", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/regence.cpp b/src/mame/chess/regence.cpp new file mode 100644 index 00000000000..851cc980bb2 --- /dev/null +++ b/src/mame/chess/regence.cpp @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/******************************************************************************* + +La Régence + +NOTE: The hardware triggers an NMI on power-off (or power-failure). If this isn't +done, NVRAM fails at next power-on. + +French chess computer by "France Double R". German distribution by Sandy Electronic, +who sub-titled it TSB 4 (Turniersensorbrett), the EPROM contents is the same. +There is no English version. + +the chess engine is Richard Lang's Cyrus. This was from when he was working for +Intelligent Software, before he got hired by Hegener + Glaser. + +Hardware notes: +- PCB label: FRANCE DOUBLE R, MADE IN FRANCE +- Sharp LH0080A Z80A @ 4 MHz (8MHz XTAL) +- 3*4KB ROM, sockets support up to 48KB ROM +- 2KB battery-backed RAM (MSM5128-15RS), 3 sockets, only middle one used +- TTL, piezo, 8*8+4 LEDs, magnetic sensors + +TODO: +- if/when MAME supports an exit callback, hook up power-off switch to that + +*******************************************************************************/ + +#include "emu.h" + +#include "cpu/z80/z80.h" +#include "machine/nvram.h" +#include "machine/sensorboard.h" +#include "sound/dac.h" +#include "video/pwm.h" + +#include "speaker.h" + +// internal artwork +#include "regence.lh" + + +namespace { + +class regence_state : public driver_device +{ +public: + regence_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_board(*this, "board"), + m_dac(*this, "dac"), + m_inputs(*this, "IN.%u", 0) + { } + + DECLARE_INPUT_CHANGED_MEMBER(power_off); + + void regence(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD { m_power = true; } + +private: + // devices/pointers + required_device<cpu_device> m_maincpu; + required_device<pwm_display_device> m_display; + required_device<sensorboard_device> m_board; + required_device<dac_1bit_device> m_dac; + required_ioport_array<2> m_inputs; + + bool m_power = false; + u8 m_inp_mux = 0; + u8 m_led_data = 0; + + void main_map(address_map &map) ATTR_COLD; + + // I/O handlers + void update_display(); + void control_w(u8 data); + void leds_w(u8 data); + u8 input_r(); +}; + +void regence_state::machine_start() +{ + // register for savestates + save_item(NAME(m_power)); + save_item(NAME(m_inp_mux)); + save_item(NAME(m_led_data)); +} + +INPUT_CHANGED_MEMBER(regence_state::power_off) +{ + // NMI at power-off (it prepares nvram for next power-on) + if (newval && m_power) + { + m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero); + m_power = false; + } +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +void regence_state::update_display() +{ + m_display->matrix(1 << m_inp_mux, m_led_data); +} + +void regence_state::control_w(u8 data) +{ + // d0-d3: input mux/led select + m_inp_mux = data & 0xf; + update_display(); + + // d7: speaker out + m_dac->write(BIT(data, 7)); + + // other: ? +} + +void regence_state::leds_w(u8 data) +{ + // d0-d7: led data + m_led_data = data; + update_display(); +} + +u8 regence_state::input_r() +{ + u8 data = 0; + + // d0-d7: multiplexed inputs + // read chessboard sensors + if (m_inp_mux < 8) + data = m_board->read_file(m_inp_mux, true); + + // read other buttons + else if (m_inp_mux < 10) + data = m_inputs[m_inp_mux - 8]->read(); + + return data; +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void regence_state::main_map(address_map &map) +{ + map(0x0000, 0x0fff).rom(); + map(0x4000, 0x4fff).rom(); + map(0x8000, 0x8fff).rom(); + map(0xd000, 0xd7ff).ram().share("nvram"); + map(0xf000, 0xf000).rw(FUNC(regence_state::input_r), FUNC(regence_state::control_w)); + map(0xf800, 0xf800).w(FUNC(regence_state::leds_w)); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( regence ) // see comments for German version labels + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) PORT_NAME("Changement de Position (Set Up)") // Veränderung + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME(u8"Retour en Arrière (Take Back)") // Zug Zurück + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_N) PORT_NAME("Nouvelle Partie (New Game)") // Neues Spiel (press after setup) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("King") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Queen") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Rook") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Bishop") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_O) PORT_NAME("Son (Sound)") // Ton + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Niveau (Level)") // Stufe + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M) PORT_CODE(KEYCODE_H) PORT_NAME("Marche/Arret (Move/Halt)") // Zug-Halt + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("Noir (Black)") // Schwarz + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("Blanc (White)") // Weiss + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Pawn") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Knight") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("POWER") // needs to be triggered for nvram to work + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_POWER_OFF) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(regence_state::power_off), 0) +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void regence_state::regence(machine_config &config) +{ + // basic machine hardware + Z80(config, m_maincpu, 8_MHz_XTAL/2); + m_maincpu->set_addrmap(AS_PROGRAM, ®ence_state::main_map); + + m_maincpu->set_periodic_int(FUNC(regence_state::irq0_line_hold), attotime::from_hz(448)); // from 555, measured + + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); + + SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); + m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); + m_board->set_delay(attotime::from_msec(150)); + m_board->set_nvram_enable(true); + + // video hardware + PWM_DISPLAY(config, m_display).set_size(10, 8); + config.set_default_layout(layout_regence); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( regence ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD("arc0.ic13", 0x0000, 0x1000, CRC(ac6a0a67) SHA1(52b115c7cd372dfbad14b00854aa4f6f75a937d3) ) // M5L2732K + ROM_LOAD("arc1.ic12", 0x4000, 0x1000, CRC(5c2fb0c7) SHA1(811ab3d7cefcf872741eb2265115080aaf913f0f) ) // " + ROM_LOAD("arc2.ic11", 0x8000, 0x1000, CRC(e4c39dbd) SHA1(b6a6d1d39f73a2ff1ade6205bdf180be13e84df3) ) // " +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1982, regence, 0, 0, regence, regence, regence_state, empty_init, "France Double R / Intelligent Software", u8"La Régence", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/chess/tasc.cpp b/src/mame/chess/tasc.cpp new file mode 100644 index 00000000000..876a57da608 --- /dev/null +++ b/src/mame/chess/tasc.cpp @@ -0,0 +1,369 @@ +// license:BSD-3-Clause +// copyright-holders:hap, Sandro Ronco +/******************************************************************************* + +Tasc ChessSystem + +Commonly known as Tasc R30, it's basically a dedicated ChessMachine. +The King chess engines are also compatible with Tasc's The ChessMachine software +on PC, however the prototype Gideon 3.1(internally: 2.1, Rebel 2.01) is not. + +The King 2.23 version was not sold to consumers. It has an opening book meant +for chesscomputer competitions. +For more information, see: http://chesseval.com/ChessEvalJournal/R30v223.htm + +Gideon only uses 128KB program RAM, no matter the RAM configuration. + +R30 hardware notes: +- ARM6 CPU(P60ARM/CG) @ 30MHz +- 256KB system ROM (2*27C010) +- 512KB program RAM (4*MT5C1008), 128KB permanent RAM (KM681000ALP-7L) +- Toshiba LCD drivers (3*T7778A, T7900, T6963C), TC5565AFL-15 +- SB20 or SB30 "SmartBoard" chessboard with piece recognition + +R40 hardware notes: +- ARM6 CPU(VY86C061PSTC) @ 40MHz +- +512KB extra RAM piggybacked +- rest same as R30 + +Documentation for the Toshiba chips is hard to find, but similar chips exist: +T7778 is equivalent to T6A39, T7900 is equivalent to T6A40. + +EPROMs are interchangeable between R30 and R40. + +references: +- https://www.schach-computer.info/wiki/index.php?title=Tasc_R30 +- https://www.schach-computer.info/wiki/index.php?title=Tasc_R40 +- https://www.schach-computer.info/wiki/index.php?title=Tasc_SmartBoard +- https://www.miclangschach.de/index.php?n=Main.TascR30 + +notes: +- holding LEFT+RIGHT on boot load the QC TestMode +- holding UP+DOWN on boot load the TestMode + +TODO: +- bootrom disable timer shouldn't be needed, real ARM has already fetched the next opcode +- more accurate dynamic cpu clock divider (same problem as in saitek/risc2500.cpp), + sound pitch is correct now though +- does the R40 version have the same clock divider value? + +BTANB: +- R40 calls itself "R30" on the system information screen (there is a photo of + an R40 that does say "R40", but it appears to be a modified ROM) + +*******************************************************************************/ + +#include "emu.h" + +#include "cpu/arm/arm.h" +#include "machine/nvram.h" +#include "machine/ram.h" +#include "machine/smartboard.h" +#include "sound/dac.h" +#include "video/t6963c.h" + +#include "speaker.h" + +// internal artwork +#include "tascr30.lh" + + +namespace { + +class tasc_state : public driver_device +{ +public: + tasc_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_boot_view(*this, "boot_view"), + m_rom(*this, "maincpu"), + m_ram(*this, "ram"), + m_nvram(*this, "nvram", 0x20000, ENDIANNESS_LITTLE), + m_lcd(*this, "lcd"), + m_smartboard(*this, "smartboard"), + m_dac(*this, "dac"), + m_inputs(*this, "IN.%u", 0U), + m_out_leds(*this, "pled%u", 0U) + { } + + void tasc(machine_config &config); + + DECLARE_INPUT_CHANGED_MEMBER(change_cpu_freq); + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + +private: + // devices/pointers + required_device<arm_cpu_device> m_maincpu; + memory_view m_boot_view; + required_region_ptr<u32> m_rom; + required_device<ram_device> m_ram; + memory_share_creator<u8> m_nvram; + required_device<lm24014h_device> m_lcd; + required_device<tasc_sb30_device> m_smartboard; + required_device<dac_2bit_ones_complement_device> m_dac; + required_ioport_array<4> m_inputs; + output_finder<2> m_out_leds; + + emu_timer *m_boot_timer; + + u32 m_control = 0; + u32 m_prev_pc = 0; + u64 m_prev_cycle = 0; + + void main_map(address_map &map) ATTR_COLD; + + // I/O handlers + u32 input_r(); + u32 rom_r(offs_t offset); + void control_w(offs_t offset, u32 data, u32 mem_mask = ~0); + + u8 nvram_r(offs_t offset) { return m_nvram[offset]; } + void nvram_w(offs_t offset, u8 data) { m_nvram[offset] = data; } + + TIMER_CALLBACK_MEMBER(disable_bootrom) { m_boot_view.select(1); } +}; + + + +/******************************************************************************* + Initialization +*******************************************************************************/ + +void tasc_state::machine_start() +{ + m_out_leds.resolve(); + + m_boot_timer = timer_alloc(FUNC(tasc_state::disable_bootrom), this); + m_boot_view[1].install_ram(0, m_ram->size() - 1, m_ram->pointer()); + + // register for savestates + save_item(NAME(m_control)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_prev_cycle)); +} + +void tasc_state::machine_reset() +{ + m_boot_view.select(0); + m_boot_timer->adjust(attotime::never); + + m_prev_pc = m_maincpu->pc(); + m_prev_cycle = m_maincpu->total_cycles(); +} + +INPUT_CHANGED_MEMBER(tasc_state::change_cpu_freq) +{ + // R30 is 30MHz, R40 is 40MHz + m_maincpu->set_unscaled_clock((newval & 1) ? 40_MHz_XTAL : 30_MHz_XTAL); +} + + + +/******************************************************************************* + I/O +*******************************************************************************/ + +u32 tasc_state::input_r() +{ + if (!machine().side_effects_disabled()) + { + // disconnect bootrom from the bus after next opcode + if (m_boot_timer->remaining().is_never()) + m_boot_timer->adjust(m_maincpu->cycles_to_attotime(10)); + + m_maincpu->set_input_line(ARM_FIRQ_LINE, CLEAR_LINE); + } + + // read chessboard + u32 data = m_smartboard->data_r(); + + // read keypad + for (int i = 0; i < 4; i++) + { + if (BIT(m_control, i)) + data |= (m_inputs[i]->read() << 24); + } + + return data; +} + +void tasc_state::control_w(offs_t offset, u32 data, u32 mem_mask) +{ + if (ACCESSING_BITS_24_31) + { + if (BIT(data, 27)) + m_lcd->write(BIT(data, 26), data & 0xff); + + m_smartboard->data0_w(BIT(data, 30)); + m_smartboard->data1_w(BIT(data, 31)); + } + else + { + m_out_leds[0] = BIT(data, 0); + m_out_leds[1] = BIT(data, 1); + m_dac->write((data >> 2) & 3); + } + + COMBINE_DATA(&m_control); +} + +u32 tasc_state::rom_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + // handle dynamic cpu clock divider when accessing rom + s64 diff = m_maincpu->total_cycles() - m_prev_cycle; + u32 pc = m_maincpu->pc(); + + if (diff > 0) + { + static constexpr int arm_branch_cycles = 3; + static constexpr int arm_max_cycles = 17; // datablock transfer + static constexpr int divider = -7 + 1; + + // this takes care of almost all cases, otherwise, total cycles taken can't be determined + if (diff <= arm_branch_cycles || (diff <= arm_max_cycles && (pc - m_prev_pc) == 4 && (pc & ~0x02000000) == (offset * 4))) + m_maincpu->adjust_icount(divider * (int)diff); + else + m_maincpu->adjust_icount(divider); + } + + m_prev_cycle = m_maincpu->total_cycles(); + m_prev_pc = pc; + } + + return m_rom[offset]; +} + + + +/******************************************************************************* + Address Maps +*******************************************************************************/ + +void tasc_state::main_map(address_map &map) +{ + map(0x00000000, 0x007fffff).view(m_boot_view); + m_boot_view[0](0x00000000, 0x0003ffff).r(FUNC(tasc_state::rom_r)); + + map(0x01000000, 0x01000003).rw(FUNC(tasc_state::input_r), FUNC(tasc_state::control_w)); + map(0x02000000, 0x0203ffff).r(FUNC(tasc_state::rom_r)); + map(0x03000000, 0x0307ffff).rw(FUNC(tasc_state::nvram_r), FUNC(tasc_state::nvram_w)).umask32(0x000000ff); +} + + + +/******************************************************************************* + Input Ports +*******************************************************************************/ + +static INPUT_PORTS_START( tasc ) + PORT_START("IN.0") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_P) PORT_NAME("Play") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.1") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Back") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("IN.2") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M) PORT_NAME("Menu") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Left Clock") + + PORT_START("IN.3") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("Enter") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("Right Clock") + + PORT_START("CPU") + PORT_CONFNAME( 0x01, 0x00, "CPU Frequency" ) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(tasc_state::change_cpu_freq), 0) + PORT_CONFSETTING( 0x00, "30MHz (R30)" ) + PORT_CONFSETTING( 0x01, "40MHz (R40)" ) +INPUT_PORTS_END + + + +/******************************************************************************* + Machine Configs +*******************************************************************************/ + +void tasc_state::tasc(machine_config &config) +{ + // basic machine hardware + ARM(config, m_maincpu, 30_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &tasc_state::main_map); + m_maincpu->set_copro_type(arm_cpu_device::copro_type::VL86C020); + + const attotime irq_period = attotime::from_hz(32.768_kHz_XTAL / 128); // 256Hz + m_maincpu->set_periodic_int(FUNC(tasc_state::irq1_line_assert), irq_period); + + RAM(config, m_ram).set_extra_options("512K, 1M, 2M, 4M, 8M"); // see driver notes + m_ram->set_default_size("512K"); + m_ram->set_default_value(0); + + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); + + TASC_SB30(config, m_smartboard); + subdevice<sensorboard_device>("smartboard:board")->set_nvram_enable(true); + + // video hardware + LM24014H(config, m_lcd, 0); + m_lcd->set_fs(1); // font size 6x8 + + config.set_default_layout(layout_tascr30); + + // sound hardware + SPEAKER(config, "speaker").front_center(); + DAC_2BIT_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.125); +} + + + +/******************************************************************************* + ROM Definitions +*******************************************************************************/ + +ROM_START( tascr30 ) // system version V1.01 (17-Mar-95), program version 2.50 (26-Feb-95) + ROM_REGION32_LE( 0x40000, "maincpu", 0 ) + ROM_LOAD32_WORD("r30_lo_1.01_king_2.5", 0x00000, 0x20000, CRC(9711c158) SHA1(87c60d2097cb437482df11916543f6ef7f18b0d3) ) + ROM_LOAD32_WORD_SWAP("r30_hi_1.01_king_2.5", 0x00002, 0x20000, CRC(df913abf) SHA1(1bc2ea4b6514bf9fec18f52c264f1440ba7c8c01) ) +ROM_END + +ROM_START( tascr30a ) // system version V0.31 (3-May-93), program version 2.20 (23-Apr-93) + ROM_REGION32_LE( 0x40000, "maincpu", 0 ) + ROM_LOAD32_WORD("0.31_l", 0x00000, 0x20000, CRC(d30f81fe) SHA1(81957c7266bedec66b2c14b97008c4261bd67828) ) + ROM_LOAD32_WORD_SWAP("0.31_h", 0x00002, 0x20000, CRC(aeac3b46) SHA1(a757e0086636dfd3bf78e61cee46c7d92b39d3b9) ) +ROM_END + +ROM_START( tascr30b ) // system version V0.31 (3-May-93), program version 2.23 (16-May-93) + ROM_REGION32_LE( 0x40000, "maincpu", 0 ) + ROM_LOAD32_WORD("r30_v2.23_lo", 0x00000, 0x20000, CRC(37251b1a) SHA1(4be768e861002b20ba59a18329f488dba0a0c9bf) ) + ROM_LOAD32_WORD_SWAP("r30_v2.23_hi", 0x00002, 0x20000, CRC(e546be93) SHA1(943ae65cf97ec4389b9730c6006e805935333072) ) +ROM_END + +ROM_START( tascr30g ) // system version V0.31 (3-May-93), program version 2.1 (3-Feb-93) + ROM_REGION32_LE( 0x40000, "maincpu", 0 ) + ROM_LOAD32_WORD("r30_gideon_l", 0x00000, 0x20000, CRC(7041d051) SHA1(266843f375a8621320fc2cd1300775fb7a505c6e) ) + ROM_LOAD32_WORD_SWAP("r30_gideon_h", 0x00002, 0x20000, CRC(7345ee08) SHA1(9cad608bd32d804468b23196151be0a5f8cee214) ) +ROM_END + +} // anonymous namespace + + + +/******************************************************************************* + Drivers +*******************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +SYST( 1995, tascr30, 0, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.50)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING ) +SYST( 1993, tascr30a, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.20)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING ) +SYST( 1993, tascr30b, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.23, TM version)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING ) // competed in several chesscomputer tournaments +SYST( 1993, tascr30g, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (Gideon 3.1, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING ) // made in 1993, later released in 2012 |