// 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 "sound/volt_reg.h"
#include "video/pwm.h"
#include "speaker.h"
// internal artwork
#include "conic_cchess2.lh" // clickable
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;
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_bit_interface> m_dac;
required_ioport_array<8> m_inputs;
// address maps
void main_map(address_map &map);
// 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);
u8 m_inp_mux = 0;
u8 m_led_data = 0;
int m_dac_on = 0;
};
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, 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, 1000000); // approximation, no XTAL
m_maincpu->set_addrmap(AS_PROGRAM, &cchess2_state::main_map);
PIA6821(config, m_pia[0], 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], 0);
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);
VOLTAGE_REGULATOR(config, "vref").add_route(0, "dac", 1.0, DAC_VREF_POS_INPUT);
}
/******************************************************************************
ROM Definitions
******************************************************************************/
ROM_START( cncchess2 )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD("c11485.u2", 0x1000, 0x1000, CRC(b179d536) SHA1(0b1f9c247a4a3e2ccbf8d3ae5efa62b8938f572f) ) // AMI 2332
ROM_END
} // anonymous namespace
/******************************************************************************
Drivers
******************************************************************************/
// YEAR NAME PARENT CMP MACHINE INPUT STATE INIT COMPANY, FULLNAME, FLAGS
CONS( 1980, cncchess2, 0, 0, cncchess2, cncchess2, cchess2_state, empty_init, "Conic", "Computer Chess (Conic, model 7012)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK )