1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 // thanks-to:Berger
4 /******************************************************************************
5 
6 SciSys President Chess (model 231)
7 (not to be confused with Saitek Kasparov President)
8 
9 The ROMs are inside a module, at the top-right. No known upgrades were released.
10 Apparently the chessboard was not that reliable. The manual even says to flip the
11 computer and shake it when one of the sensors is malfunctioning.
12 
13 Hardware notes:
14 - 6502A @ 2MHz
15 - 16KB ROM(2*HN482764G), 2KB RAM(HM6116P-4)
16 - buzzer, 64+12 leds, magnet sensors chessboard
17 
18 TODO:
19 - verify CPU speed / XTAL
20 - measure interrupt frequency
21 - the manual claims that it does a self-test at boot, but on MAME that only
22   happens if you hold down one of the buttons
23 
24 ******************************************************************************/
25 
26 #include "emu.h"
27 #include "cpu/m6502/m6502.h"
28 #include "machine/sensorboard.h"
29 #include "sound/dac.h"
30 #include "video/pwm.h"
31 #include "speaker.h"
32 
33 // internal artwork
34 #include "saitek_prschess.lh" // clickable
35 
36 
37 namespace {
38 
39 class prschess_state : public driver_device
40 {
41 public:
prschess_state(const machine_config & mconfig,device_type type,const char * tag)42 	prschess_state(const machine_config &mconfig, device_type type, const char *tag) :
43 		driver_device(mconfig, type, tag),
44 		m_maincpu(*this, "maincpu"),
45 		m_board(*this, "board"),
46 		m_display(*this, "display"),
47 		m_dac(*this, "dac"),
48 		m_inputs(*this, "IN.%u", 0)
49 	{ }
50 
51 	// machine configs
52 	void prschess(machine_config &config);
53 
54 protected:
55 	virtual void machine_start() override;
56 
57 private:
58 	// devices/pointers
59 	required_device<cpu_device> m_maincpu;
60 	required_device<sensorboard_device> m_board;
61 	required_device<pwm_display_device> m_display;
62 	required_device<dac_bit_interface> m_dac;
63 	required_ioport_array<3> m_inputs;
64 
65 	// address maps
66 	void main_map(address_map &map);
67 
68 	// I/O handlers
69 	void update_display();
70 	void leds_w(offs_t offset, u8 data);
71 	void control_w(u8 data);
72 	u8 input_r();
73 
74 	u8 m_inp_mux = 0;
75 	u8 m_led_data[2] = { 0, 0 };
76 };
77 
machine_start()78 void prschess_state::machine_start()
79 {
80 	save_item(NAME(m_inp_mux));
81 	save_item(NAME(m_led_data));
82 }
83 
84 
85 
86 /******************************************************************************
87     I/O
88 ******************************************************************************/
89 
update_display()90 void prschess_state::update_display()
91 {
92 	u16 led_data = m_led_data[1] << 8 | m_led_data[0];
93 	led_data = bitswap<16>(led_data,15,14,5,4,3,2,1,0, 7,6,13,12,11,10,9,8);
94 	m_display->matrix(1 << m_inp_mux, led_data);
95 }
96 
leds_w(offs_t offset,u8 data)97 void prschess_state::leds_w(offs_t offset, u8 data)
98 {
99 	m_led_data[offset >> 8] = ~data;
100 	update_display();
101 }
102 
control_w(u8 data)103 void prschess_state::control_w(u8 data)
104 {
105 	// d0-d3: input mux, led select
106 	m_inp_mux = data & 0xf;
107 	update_display();
108 
109 	// d5: speaker out
110 	m_dac->write(BIT(data, 5));
111 
112 	// other: ?
113 }
114 
input_r()115 u8 prschess_state::input_r()
116 {
117 	u8 data = 0;
118 
119 	// read chessboard sensors
120 	if (m_inp_mux < 8)
121 		data = m_board->read_file(m_inp_mux);
122 
123 	// read other buttons
124 	else if (m_inp_mux < 11)
125 		data = m_inputs[m_inp_mux - 8]->read();
126 
127 	return data;
128 }
129 
130 
131 
132 /******************************************************************************
133     Address Maps
134 ******************************************************************************/
135 
main_map(address_map & map)136 void prschess_state::main_map(address_map &map)
137 {
138 	map(0x0000, 0x07ff).ram();
139 	map(0x4000, 0x4000).select(0x0100).w(FUNC(prschess_state::leds_w));
140 	map(0x4200, 0x4200).w(FUNC(prschess_state::control_w));
141 	map(0x4300, 0x4300).r(FUNC(prschess_state::input_r));
142 	map(0xc000, 0xffff).rom();
143 }
144 
145 
146 
147 /******************************************************************************
148     Input Ports
149 ******************************************************************************/
150 
151 static INPUT_PORTS_START( prschess )
152 	PORT_START("IN.0")
153 	PORT_BIT(0x03, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_CODE(KEYCODE_I)154 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) PORT_NAME("Interrupt")
155 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M) PORT_NAME("Move")
156 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("Take Back")
157 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_NAME("Hint")
158 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) PORT_NAME("Legal")
159 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Level")
160 
161 	PORT_START("IN.1")
162 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
163 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("Reset")
164 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Z) PORT_NAME("Player V Computer")
165 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_X) PORT_NAME("Player V Player")
166 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) PORT_NAME("Change Sides")
167 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("Clear Board")
168 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_V) PORT_NAME("Verify / Set Up")
169 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("White")
170 
171 	PORT_START("IN.2")
172 	PORT_BIT(0x03, IP_ACTIVE_HIGH, IPT_UNUSED)
173 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Pawn")
174 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Knight")
175 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Bishop")
176 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Rook")
177 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Queen")
178 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("King")
179 INPUT_PORTS_END
180 
181 
182 
183 /******************************************************************************
184     Machine Configs
185 ******************************************************************************/
186 
187 void prschess_state::prschess(machine_config &config)
188 {
189 	/* basic machine hardware */
190 	M6502(config, m_maincpu, 2000000);
191 	m_maincpu->set_addrmap(AS_PROGRAM, &prschess_state::main_map);
192 	m_maincpu->set_periodic_int(FUNC(prschess_state::nmi_line_pulse), attotime::from_hz(100)); // guessed
193 
194 	SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS);
195 	m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess));
196 	m_board->set_delay(attotime::from_msec(150));
197 
198 	/* video hardware */
199 	PWM_DISPLAY(config, m_display).set_size(8+1, 16);
200 	config.set_default_layout(layout_saitek_prschess);
201 
202 	/* sound hardware */
203 	SPEAKER(config, "speaker").front_center();
204 	DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25);
205 }
206 
207 
208 
209 /******************************************************************************
210     ROM Definitions
211 ******************************************************************************/
212 
213 ROM_START( prschess )
214 	ROM_REGION( 0x10000, "maincpu", 0 )
215 	ROM_LOAD("y03_rl", 0xc000, 0x2000, CRC(862c3f42) SHA1(e2d2f1d7a0382b0774e86ca83e270dab1df700c2) ) // HN482764G
216 	ROM_LOAD("y03_rh", 0xe000, 0x2000, CRC(ef95cb9f) SHA1(02f763cf9cab1b4be8964ddb5d93efb05a898123) ) // "
217 ROM_END
218 
219 } // anonymous namespace
220 
221 
222 
223 /******************************************************************************
224     Drivers
225 ******************************************************************************/
226 
227 //    YEAR  NAME      PARENT CMP MACHINE   INPUT     STATE           INIT        COMPANY, FULLNAME, FLAGS
228 CONS( 1982, prschess, 0,      0, prschess, prschess, prschess_state, empty_init, "SciSys", "President Chess", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK )
229