1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 // thanks-to:Berger
4 /******************************************************************************
5 
6 SciSys Kasparov Leonardo, Saitek Kasparov Galileo.
7 
8 This is SciSys's answer to H+G Mephisto modular chesscomputers, but unlike the
9 Mephistos, these boards are actual chesscomputers and not an accessory.
10 
11 They called the expansion capability "OSA", for "Open Systems Architecture".
12 One for a link port to a PC, and one for a module slot. The expansion modules
13 are basically entire chesscomputers, making the whole thing combined a
14 'dual brain' chesscomputer. The embedded chess engine is by Julio Kaplan
15 and Craig Barnes, same as the one in SciSys Turbo S-24K.
16 
17 Hardware notes:
18 
19 Leonardo (1986):
20 - 6301Y0 MCU @ 12MHz
21 - 32KB ROM(27C256)
22 - 8KB RAM(M5M5165P-15 or compatible)
23 - magnet sensors chessboard with 16 leds
24 
25 The 6301Y0 was seen with internal maskrom serial A96 and B40. It appears to be
26 running in mode 1 (expanded mode): the internal ROM is disabled and the MCU can
27 be emulated as if it's a HD6303Y. It's not known what's on the internal ROM,
28 it could even be from another SciSys chesscomputer.
29 
30 Galileo (1988):
31 - HD6303YP MCU @ 12MHz
32 - almost same as Leonardo
33 
34 Galileo PCB is different, but essentially it's the same hardware as Leonardo.
35 The 1.4 ROM is identical to it too, even though it's a different MCU type.
36 And on the outside, the button panel was redesigned a bit.
37 
38 Expansion modules released:
39 - Maestro (65C02, Kaplan/Barnes)
40 - Analyst (65C02, Kaplan/Barnes)
41 - Brute Force (H8, Frans Morsch)
42 - Sparc (SPARClite, Spracklen's)
43 
44 TODO:
45 - OSA module support (softwarelist, devices/bus)
46 - OSA PC link (probably uses MCU serial interface)
47 - add nvram
48 - finish internal artwork
49 
50 ******************************************************************************/
51 
52 #include "emu.h"
53 
54 #include "cpu/m6800/m6801.h"
55 #include "machine/sensorboard.h"
56 #include "sound/dac.h"
57 #include "video/pwm.h"
58 
59 #include "speaker.h"
60 
61 // internal artwork
62 #include "saitek_leonardo.lh" // clickable
63 
64 
65 namespace {
66 
67 class leo_state : public driver_device
68 {
69 public:
leo_state(const machine_config & mconfig,device_type type,const char * tag)70 	leo_state(const machine_config &mconfig, device_type type, const char *tag) :
71 		driver_device(mconfig, type, tag),
72 		m_maincpu(*this, "maincpu"),
73 		m_board(*this, "board"),
74 		m_display(*this, "display"),
75 		m_dac(*this, "dac"),
76 		m_inputs(*this, "IN.%u", 0)
77 	{ }
78 
79 	void leo(machine_config &config);
80 	void leoa(machine_config &config);
81 
82 protected:
83 	virtual void machine_start() override;
84 
85 private:
86 	// devices/pointers
87 	required_device<hd6303y_cpu_device> m_maincpu;
88 	required_device<sensorboard_device> m_board;
89 	required_device<pwm_display_device> m_display;
90 	optional_device<dac_bit_interface> m_dac;
91 	required_ioport_array<9> m_inputs;
92 
93 	void main_map(address_map &map);
94 
95 	void update_display();
96 	void mux_w(u8 data);
97 	void leds_w(u8 data);
98 	u8 unk_r();
99 	void unk_w(u8 data);
100 
101 	u8 p2_r();
102 	void p2_w(u8 data);
103 	u8 p6_r();
104 	void p5_w(u8 data);
105 	u8 p5_r();
106 	void p6_w(u8 data);
107 
108 	u8 m_inp_mux = 0;
109 	u8 m_led_data[2] = { 0, 0 };
110 };
111 
machine_start()112 void leo_state::machine_start()
113 {
114 	save_item(NAME(m_inp_mux));
115 	save_item(NAME(m_led_data));
116 }
117 
118 
119 
120 /******************************************************************************
121     I/O
122 ******************************************************************************/
123 
124 // misc
125 
update_display()126 void leo_state::update_display()
127 {
128 	m_display->matrix_partial(0, 8, 1 << (m_inp_mux & 0xf), m_led_data[0], false);
129 	m_display->matrix_partial(8, 2, 1 << BIT(m_inp_mux, 5), (~m_inp_mux << 2 & 0x300) | m_led_data[1], true);
130 }
131 
mux_w(u8 data)132 void leo_state::mux_w(u8 data)
133 {
134 	// d0-d3: input/chessboard led mux
135 	// d5: button led select
136 	// d6,d7: button led data
137 	m_inp_mux = data;
138 	update_display();
139 
140 	// d4: speaker out
141 	m_dac->write(BIT(data, 4));
142 }
143 
leds_w(u8 data)144 void leo_state::leds_w(u8 data)
145 {
146 	// button led data
147 	m_led_data[1] = ~data;
148 	update_display();
149 }
150 
unk_r()151 u8 leo_state::unk_r()
152 {
153 	// ?
154 	return 0xff;
155 }
156 
unk_w(u8 data)157 void leo_state::unk_w(u8 data)
158 {
159 	// ?
160 }
161 
162 
163 // MCU ports
164 
p2_r()165 u8 leo_state::p2_r()
166 {
167 	u8 data = 0;
168 
169 	// d0-d2: multiplexed inputs
170 	u8 mux = (m_inp_mux & 8) ? 8 : (m_inp_mux & 7);
171 	data = m_inputs[mux]->read();
172 
173 	// d3: ?
174 
175 	return ~data;
176 }
177 
p2_w(u8 data)178 void leo_state::p2_w(u8 data)
179 {
180 	// d5,d6: chessboard led column data
181 	m_led_data[0] = (m_led_data[0] & ~3) | (~data >> 5 & 3);
182 	update_display();
183 
184 	// other: ?
185 }
186 
p5_r()187 u8 leo_state::p5_r()
188 {
189 	// ?
190 	return 0xff ^ 0x10;
191 }
192 
p5_w(u8 data)193 void leo_state::p5_w(u8 data)
194 {
195 	// d6,d7: chessboard led row data
196 	m_led_data[0] = (m_led_data[0] & 3) | (~data >> 4 & 0xc);
197 	update_display();
198 
199 	// d0: power-off
200 	// other: ?
201 }
202 
p6_r()203 u8 leo_state::p6_r()
204 {
205 	// read chessboard sensors
206 	return ~m_board->read_file(m_inp_mux & 0xf);
207 }
208 
p6_w(u8 data)209 void leo_state::p6_w(u8 data)
210 {
211 	// module data
212 }
213 
214 
215 
216 /******************************************************************************
217     Address Maps
218 ******************************************************************************/
219 
main_map(address_map & map)220 void leo_state::main_map(address_map &map)
221 {
222 	map(0x0000, 0x0027).m(m_maincpu, FUNC(hd6303y_cpu_device::hd6301y_io));
223 	map(0x0002, 0x0002).rw(FUNC(leo_state::unk_r), FUNC(leo_state::unk_w)); // external
224 	map(0x0040, 0x013f).ram(); // internal
225 	map(0x4000, 0x5fff).ram();
226 	map(0x6000, 0x6000).w(FUNC(leo_state::mux_w));
227 	map(0x7000, 0x7000).w(FUNC(leo_state::leds_w));
228 	map(0x8000, 0xffff).rom();
229 }
230 
231 
232 
233 /******************************************************************************
234     Input Ports
235 ******************************************************************************/
236 
237 static INPUT_PORTS_START( leo )
238 	PORT_START("IN.0")
PORT_CODE(KEYCODE_1)239 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) // king
240 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) // rook
241 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) // knight
242 
243 	PORT_START("IN.1")
244 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) // queen
245 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) // bishop
246 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) // pawn
247 
248 	PORT_START("IN.2")
249 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN)
250 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) // tab/color
251 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_9) // +
252 
253 	PORT_START("IN.3")
254 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM) // freq sel
255 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) // function?
256 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) // sound
257 
258 	PORT_START("IN.4")
259 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_CUSTOM) // freq sel
260 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) // stop?
261 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Y) // library?
262 
263 	PORT_START("IN.5")
264 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) // info
265 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) // play?
266 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_O) // level
267 
268 	PORT_START("IN.6")
269 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_A) // -
270 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) // normal?
271 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_D) // analysis?
272 
273 	PORT_START("IN.7")
274 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN)
275 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) // new game
276 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) // setup?
277 
278 	PORT_START("IN.8")
279 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN)
280 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNKNOWN)
281 	PORT_CONFNAME( 0x04, 0x04, "Battery Status" )
282 	PORT_CONFSETTING(    0x00, "Low" )
283 	PORT_CONFSETTING(    0x04, DEF_STR( Normal ) )
284 INPUT_PORTS_END
285 
286 
287 
288 /******************************************************************************
289     Machine Configs
290 ******************************************************************************/
291 
292 void leo_state::leo(machine_config &config)
293 {
294 	/* basic machine hardware */
295 	HD6303Y(config, m_maincpu, 12_MHz_XTAL);
296 	m_maincpu->set_addrmap(AS_PROGRAM, &leo_state::main_map);
297 	m_maincpu->in_p2_cb().set(FUNC(leo_state::p2_r));
298 	m_maincpu->out_p2_cb().set(FUNC(leo_state::p2_w));
299 	m_maincpu->in_p5_cb().set(FUNC(leo_state::p5_r));
300 	m_maincpu->out_p5_cb().set(FUNC(leo_state::p5_w));
301 	m_maincpu->in_p6_cb().set(FUNC(leo_state::p6_r));
302 	m_maincpu->out_p6_cb().set(FUNC(leo_state::p6_w));
303 
304 	SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS);
305 	m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess));
306 	m_board->set_delay(attotime::from_msec(150));
307 
308 	/* video hardware */
309 	PWM_DISPLAY(config, m_display).set_size(8+2, 8+2);
310 	config.set_default_layout(layout_saitek_leonardo);
311 
312 	/* sound hardware */
313 	SPEAKER(config, "speaker").front_center();
314 	DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25);
315 }
316 
leoa(machine_config & config)317 void leo_state::leoa(machine_config &config)
318 {
319 	leo(config);
320 
321 	// slower chessboard response?
322 	m_board->set_delay(attotime::from_msec(250));
323 }
324 
325 
326 
327 /******************************************************************************
328     ROM Definitions
329 ******************************************************************************/
330 
331 ROM_START( leonardo )
332 	ROM_REGION( 0x10000, "maincpu", 0 )
333 	ROM_LOAD("sw6.1_osa1.4_510.u9", 0x8000, 0x8000, CRC(e39676b2) SHA1(288c5f2608277cb4c3ca71cb2e642a6a62c01dca) ) // D27C256AD-12
334 ROM_END
335 
336 ROM_START( leonardoa )
337 	ROM_REGION( 0x10000, "maincpu", 0 )
338 	ROM_LOAD("sx6_617l_osa1.2.u9", 0x8000, 0x8000, CRC(4620f827) SHA1(4ae566646d032dd5bcca48316dd90a11e06772f1) ) // D27C256AD-12
339 ROM_END
340 
341 ROM_START( galileo )
342 	ROM_REGION( 0x10000, "maincpu", 0 )
343 	ROM_LOAD("sw6.1_osa1.4_510.u9", 0x8000, 0x8000, CRC(e39676b2) SHA1(288c5f2608277cb4c3ca71cb2e642a6a62c01dca) ) // MBM27C256H-10
344 ROM_END
345 
346 } // anonymous namespace
347 
348 
349 
350 /******************************************************************************
351     Drivers
352 ******************************************************************************/
353 
354 //    YEAR  NAME       PARENT    CMP MACHINE INPUT CLASS      INIT        COMPANY, FULLNAME, FLAGS
355 CONS( 1986, leonardo,  0,        0,  leo,    leo,  leo_state, empty_init, "SciSys", "Kasparov Leonardo (set 1)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_NOT_WORKING )
356 CONS( 1986, leonardoa, leonardo, 0,  leoa,   leo,  leo_state, empty_init, "SciSys", "Kasparov Leonardo (set 2)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_NOT_WORKING )
357 
358 CONS( 1988, galileo,   0,        0,  leo,    leo,  leo_state, empty_init, "Saitek", "Kasparov Galileo", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_NOT_WORKING )
359