1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 /***************************************************************************
4 
5   Sega UFO Catcher, Z80 type hardware
6   The list underneath is not complete. A # before the name means it's not dumped yet.
7 
8   1st gen
9     * ?
10   - # UFO Catcher (1985)
11 
12   2nd gen:
13     * ?
14   - # UFO Catcher DX (1987)
15   - # UFO Catcher DX II (1987)
16 
17   3rd gen - UFO brd
18     * Z80, 2 Sega 315-5296(I/O), YM3438, NEC uPD71054C
19   - # Dream Town (1990)
20   - New UFO Catcher (1991) (2P) - probably the most popular cabinet of all UFO Catcher series
21   - UFO Catcher Mini (1991) (1P)
22   - # UFO Catcher Sega Sonic (1991)
23   - # School Kids (1993)
24 
25   4th gen - EX brd
26     * Z80, 2 Sega 315-5296(I/O), 315-5338A, YM3438, NEC uPD71054C, optional NEC uPD7759C
27   - # Dream Palace (1992)
28   - # Dream Kitchen (1994)
29   - # UFO Catcher Excellent (1994)
30   - # UFO A La Carte (1996)
31   - UFO Catcher 21 (1996) (2P)
32   - UFO Catcher 800 (1998) (1P)
33   - # Baby UFO (1998)
34   - # Prize Sensor (1998)
35 
36   More games were released after 2000, assumed to be on more modern hardware.
37 
38   TODO:
39   - add dipswitches
40   - prize sensor for ufo21/ufo800
41 
42 ***************************************************************************/
43 
44 #include "emu.h"
45 #include "cpu/z80/z80.h"
46 #include "machine/pit8253.h"
47 #include "machine/315_5296.h"
48 #include "machine/315_5338a.h"
49 #include "machine/timer.h"
50 #include "sound/2612intf.h"
51 #include "sound/upd7759.h"
52 #include "speaker.h"
53 
54 // the layouts are very similar to eachother
55 #include "newufo.lh"
56 #include "ufomini.lh"
57 #include "ufo21.lh"
58 #include "ufo800.lh"
59 
60 
61 /* simulation parameters */
62 // x/y/z cabinet dimensions per player (motor range)
63 #define CABINET_WIDTH   400
64 #define CABINET_DEPTH   400
65 #define CABINET_HEIGHT  300
66 
67 // x/y/z motor speed in hertz
68 #define MOTOR_SPEED     100
69 
70 // crane size (stepper motor range)
71 // note: UFO board/EX board expects this to be around 350 steps per quarter rotation
72 #define CRANE_SIZE      350
73 
74 
75 
76 class ufo_state : public driver_device
77 {
78 public:
ufo_state(const machine_config & mconfig,device_type type,const char * tag)79 	ufo_state(const machine_config &mconfig, device_type type, const char *tag) :
80 		driver_device(mconfig, type, tag),
81 		m_maincpu(*this, "maincpu"),
82 		m_io1(*this, "io1"),
83 		m_io2(*this, "io2"),
84 		m_upd(*this, "upd"),
85 		m_counters(*this, "counter%u", 0U),
86 		m_digits(*this, "digit%u", 0U),
87 		m_lamps(*this, "lamp%u", 0U)
88 	{ }
89 
90 	void ufomini(machine_config &config);
91 	void ufo21(machine_config &config);
92 	void newufo(machine_config &config);
93 	void ufo800(machine_config &config);
94 
95 private:
96 	void motor_tick(int p, int m);
97 
98 	DECLARE_WRITE_LINE_MEMBER(pit_out0);
99 	DECLARE_WRITE_LINE_MEMBER(pit_out1);
100 	DECLARE_WRITE_LINE_MEMBER(pit_out2);
101 	uint8_t crane_limits_r(offs_t offset);
102 	void stepper_w(uint8_t data);
103 	void cp_lamps_w(uint8_t data);
104 	void cp_digits_w(offs_t offset, uint8_t data);
105 	void crane_xyz_w(offs_t offset, uint8_t data);
106 	void ufo_lamps_w(uint8_t data);
107 
108 	uint8_t ex_crane_limits_r(offs_t offset);
109 	uint8_t ex_crane_open_r();
110 	void ex_stepper_w(uint8_t data);
111 	void ex_cp_lamps_w(uint8_t data);
112 	void ex_crane_xyz_w(offs_t offset, uint8_t data);
113 	void ex_ufo21_lamps1_w(uint8_t data);
114 	void ex_ufo21_lamps2_w(uint8_t data);
115 	void ex_ufo800_lamps_w(uint8_t data);
116 	uint8_t ex_upd_busy_r();
117 	void ex_upd_start_w(uint8_t data);
118 
119 	virtual void machine_reset() override;
120 	virtual void machine_start() override;
121 	TIMER_DEVICE_CALLBACK_MEMBER(simulate_xyz);
122 	TIMER_DEVICE_CALLBACK_MEMBER(update_info);
123 
124 	void ufo_map(address_map &map);
125 	void ufo_portmap(address_map &map);
126 	void ex_ufo21_portmap(address_map &map);
127 	void ex_ufo800_portmap(address_map &map);
128 
129 	struct Player
130 	{
131 		struct Motor
132 		{
133 			uint8_t running;
134 			uint8_t direction;
135 			float position;
136 			float speed;
137 		} motor[4];
138 	} m_player[2];
139 
140 	uint8_t m_stepper;
141 
142 	required_device<cpu_device> m_maincpu;
143 	required_device<sega_315_5296_device> m_io1;
144 	required_device<sega_315_5296_device> m_io2;
145 	optional_device<upd7759_device> m_upd;
146 	output_finder<2 * 4> m_counters;
147 	output_finder<2> m_digits;
148 	output_finder<28> m_lamps;
149 };
150 
151 
152 
motor_tick(int p,int m)153 void ufo_state::motor_tick(int p, int m)
154 {
155 	float delta = m_player[p].motor[m].speed;
156 	if (m_player[p].motor[m].direction)
157 		delta = -delta;
158 
159 	if (m_player[p].motor[m].running)
160 		m_player[p].motor[m].position += delta;
161 
162 	if (m_player[p].motor[m].position < 0)
163 		m_player[p].motor[m].position = 0;
164 	if (m_player[p].motor[m].position > 1)
165 		m_player[p].motor[m].position = 1;
166 }
167 
TIMER_DEVICE_CALLBACK_MEMBER(ufo_state::simulate_xyz)168 TIMER_DEVICE_CALLBACK_MEMBER(ufo_state::simulate_xyz)
169 {
170 	for (int p = 0; p < 2; p++)
171 		for (int m = 0; m < 3; m++)
172 			motor_tick(p, m);
173 }
174 
175 
TIMER_DEVICE_CALLBACK_MEMBER(ufo_state::update_info)176 TIMER_DEVICE_CALLBACK_MEMBER(ufo_state::update_info)
177 {
178 	// output ufo motor positions
179 	// 0 X: 000 = right,  100 = left (player 1)
180 	// 1 Y: 000 = front,  100 = back
181 	// 2 Z: 000 = up,     100 = down
182 	// 3 C: 000 = closed, 100 = open
183 	for (int p = 0; p < 2; p++)
184 		for (int m = 0; m < 4; m++)
185 			m_counters[(p << 2) | m] = uint8_t(m_player[p].motor[m].position * 100);
186 
187 #if 0
188 	char msg1[0x100] = {0};
189 	char msg2[0x100] = {0};
190 	for (int i = 0; i < 8; i++)
191 	{
192 		sprintf(msg2, "%02X ", m_io2->debug_peek_output(i));
193 		strcat(msg1, msg2);
194 	}
195 	popmessage("%s", msg1);
196 #endif
197 }
198 
199 
200 
201 /***************************************************************************
202 
203   I/O
204 
205 ***************************************************************************/
206 
WRITE_LINE_MEMBER(ufo_state::pit_out0)207 WRITE_LINE_MEMBER(ufo_state::pit_out0)
208 {
209 	// ?
210 }
211 
WRITE_LINE_MEMBER(ufo_state::pit_out1)212 WRITE_LINE_MEMBER(ufo_state::pit_out1)
213 {
214 	// NMI?
215 	if (state)
216 		m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
217 }
218 
WRITE_LINE_MEMBER(ufo_state::pit_out2)219 WRITE_LINE_MEMBER(ufo_state::pit_out2)
220 {
221 	// ?
222 }
223 
224 
225 /* generic / UFO board handlers */
226 
227 /* io1 */
228 
crane_limits_r(offs_t offset)229 uint8_t ufo_state::crane_limits_r(offs_t offset)
230 {
231 	int p = offset & 1;
232 	uint8_t ret = 0x7f;
233 
234 	// d0: left limit sw (right for p2)
235 	// d1: right limit sw (left for p2)
236 	// d2: back limit sw
237 	// d3: front limit sw
238 	// d4: down limit sw
239 	// d5: up limit sw
240 	for (int m = 0; m < 3; m++)
241 	{
242 		ret ^= (m_player[p].motor[m].position >= 1) << (m*2 + 0);
243 		ret ^= (m_player[p].motor[m].position <= 0) << (m*2 + 1);
244 	}
245 
246 	// d6: crane open sensor (reflective sticker on the stepper motor rotation disc)
247 	if (m_player[p].motor[3].position >= 0.97f)
248 		ret ^= 0x40;
249 
250 	// d7: prize sensor (mirror?)
251 	ret |= (ioport(p ? "IN2" : "IN1")->read() & 0x80);
252 
253 	return ret;
254 }
255 
256 /* io2 */
257 
stepper_w(uint8_t data)258 void ufo_state::stepper_w(uint8_t data)
259 {
260 	for (int p = 0; p < 2; p++)
261 	{
262 		// The crane stepper motor is set up as a rotating ellipse disc under the crane,
263 		// controlled with 4 output bits connected to a Toshiba TB6560AHQ motor driver.
264 		// I don't know which bits connect to which pins specifically.
265 		// To run it, the game writes a continuous sequence of $5, $9, $a, $6, ..
266 		static const uint8_t sequence[4] =
267 			{ 0x5, 0x9, 0xa, 0x6 };
268 
269 		// d0-d3: p1, d4-d7: p2
270 		uint8_t cur = data >> (p*4) & 0xf;
271 		uint8_t prev = m_stepper >> (p*4) & 0xf;
272 
273 		for (int i = 0; i < 4; i++)
274 		{
275 			if (sequence[i] == prev && sequence[(i+1) & 3] == cur)
276 			{
277 				m_player[p].motor[3].running = 1;
278 				motor_tick(p, 3);
279 
280 				// change direction after each quarter rotate
281 				if (m_player[p].motor[3].position <= 0 || m_player[p].motor[3].position >= 1)
282 					m_player[p].motor[3].direction ^= 1;
283 
284 				break;
285 			}
286 		}
287 	}
288 
289 	m_stepper = data;
290 }
291 
cp_lamps_w(uint8_t data)292 void ufo_state::cp_lamps_w(uint8_t data)
293 {
294 	// d0-d3: p1/p2 button lamps
295 	// other bits: ?
296 	for (int i = 0; i < 4; i++)
297 		m_lamps[i] = BIT(~data, i);
298 }
299 
cp_digits_w(offs_t offset,uint8_t data)300 void ufo_state::cp_digits_w(offs_t offset, uint8_t data)
301 {
302 	static constexpr uint8_t lut_7448[0x10] =
303 			{ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x67,0x58,0x4c,0x62,0x69,0x78,0x00 };
304 
305 	// d0-d3: cpanel digit
306 	// other bits: ?
307 	m_digits[offset & 1] = lut_7448[data & 0xf];
308 }
309 
crane_xyz_w(offs_t offset,uint8_t data)310 void ufo_state::crane_xyz_w(offs_t offset, uint8_t data)
311 {
312 	int p = offset & 1;
313 
314 	// d0: x/z axis (0:x, 1:z + halt x/y)
315 	// d1: x/z direction
316 	// d2: y direction
317 	// d3: x/z running
318 	// d4: y running
319 	// other bits: ?
320 	m_player[p].motor[0].running = (data & 9) == 8;
321 	m_player[p].motor[0].direction = data & 2;
322 	m_player[p].motor[1].running = (data & 0x11) == 0x10;
323 	m_player[p].motor[1].direction = data & 4;
324 	m_player[p].motor[2].running = (data & 9) == 9;
325 	m_player[p].motor[2].direction = data & 2;
326 }
327 
ufo_lamps_w(uint8_t data)328 void ufo_state::ufo_lamps_w(uint8_t data)
329 {
330 	// d0-d3: ufo leds (2 bits per player)
331 	// 3 sets of two red/green leds, each set is wired to the same control 2 bits
332 	// 00 = off,   off
333 	// 11 = red,   red
334 	// 01 = green, red
335 	// 10 = red,   green
336 	m_lamps[10] = data & 0x03;
337 	m_lamps[11] = (data >> 2) & 0x03;
338 
339 	// d4,d5: ?
340 	// d6,d7: coincounters
341 	machine().bookkeeping().coin_counter_w(0, data & 0x40); // 100 Y
342 	machine().bookkeeping().coin_counter_w(1, data & 0x80); // 500 Y
343 }
344 
345 
346 /* EX board specific handlers */
347 
348 /* io1 */
349 
ex_crane_limits_r(offs_t offset)350 uint8_t ufo_state::ex_crane_limits_r(offs_t offset)
351 {
352 	int p = offset & 1;
353 	uint8_t ret = 0xf0;
354 
355 	// d0: left limit sw (invert)
356 	// d1: right limit sw (invert)
357 	// d2: back limit sw (invert)
358 	// d3: front limit sw (invert)
359 	// d4: ?
360 	// d5: down limit sw
361 	// d6: up limit sw
362 	// d7: ?
363 	for (int m = 0; m < 3; m++)
364 	{
365 		int shift = (m*2) + (m == 2);
366 		ret ^= (m_player[p].motor[m].position >= 1) << shift;
367 		ret ^= (m_player[p].motor[m].position <= 0) << (shift+1);
368 	}
369 
370 	return ret;
371 }
372 
ex_crane_open_r()373 uint8_t ufo_state::ex_crane_open_r()
374 {
375 	// d0-d3: p1, d4-d7: p2
376 	uint8_t ret = 0xff;
377 
378 	for (int p = 0; p < 2; p++)
379 	{
380 		// d0: crane open sensor
381 		if (m_player[p].motor[3].position >= 0.97f)
382 			ret ^= (1 << (p*4));
383 
384 		// d1: coincounter is plugged in (ufo800 gives error 14 otherwise)
385 		// d2,d3: ?
386 	}
387 
388 	return ret;
389 }
390 
391 /* io2 */
392 
ex_stepper_w(uint8_t data)393 void ufo_state::ex_stepper_w(uint8_t data)
394 {
395 	// stepper motor sequence is: 6 c 9 3 6 c 9 3..
396 	// which means d0 and d3 are swapped when compared with UFO board hardware
397 	stepper_w(bitswap<8>(data,4,6,5,7,0,2,1,3));
398 }
399 
ex_cp_lamps_w(uint8_t data)400 void ufo_state::ex_cp_lamps_w(uint8_t data)
401 {
402 	// d0,d1,d4,d5: p1/p2 button lamps
403 	for (int i = 0; i < 4; i++)
404 		m_lamps[i] = BIT(~data, ((i&1) + (i&2) * 2));
405 
406 	// d2,d3,d6,d7: p1/p2 coincounters
407 	for (int i = 0; i < 4; i++)
408 		machine().bookkeeping().coin_counter_w(i, data >> (2 + (i&1) + (i&2) * 2) & 1);
409 }
410 
ex_crane_xyz_w(offs_t offset,uint8_t data)411 void ufo_state::ex_crane_xyz_w(offs_t offset, uint8_t data)
412 {
413 	int p = offset & 1;
414 
415 	// more straightforward setup than on UFO board hardware
416 	// d0: move left
417 	// d1: move right
418 	// d2: move back
419 	// d3: move front
420 	// d4: move down
421 	// d5: move up
422 	for (int m = 0; m < 3; m++)
423 	{
424 		int bits = data >> (m*2) & 3;
425 		m_player[p].motor[m].running = (bits == 1 || bits == 2) ? 1 : 0;
426 		m_player[p].motor[m].direction = bits & 2;
427 	}
428 }
429 
ex_ufo800_lamps_w(uint8_t data)430 void ufo_state::ex_ufo800_lamps_w(uint8_t data)
431 {
432 	// d0-d4: 5 red leds on ufo
433 	// other bits: ?
434 	for (int i = 0; i < 5; i++)
435 		m_lamps[10 + i] = BIT(data, i);
436 }
437 
438 /* 315-5338A */
439 
ex_ufo21_lamps1_w(uint8_t data)440 void ufo_state::ex_ufo21_lamps1_w(uint8_t data)
441 {
442 	// d0: ? (ufo21 reads from it too, but value is discarded)
443 	// d1-d6 are the 6 red leds on each ufo
444 	// d7: ?
445 	for (int i = 1; i < 7; i++)
446 		m_lamps[10 + i] = BIT(data, i);
447 }
448 
ex_ufo21_lamps2_w(uint8_t data)449 void ufo_state::ex_ufo21_lamps2_w(uint8_t data)
450 {
451 	for (int i = 1; i < 7; i++)
452 		m_lamps[20 + i] = BIT(data, i);
453 }
454 
ex_upd_start_w(uint8_t data)455 void ufo_state::ex_upd_start_w(uint8_t data)
456 {
457 	// d0: upd7759c start sample
458 	// other bits: unused?
459 	m_upd->start_w(~data & 1);
460 }
461 
ex_upd_busy_r()462 uint8_t ufo_state::ex_upd_busy_r()
463 {
464 	// d0: upd7759c busy
465 	// other bits: unused?
466 	int d0 = m_upd->busy_r() ? 1 : 0;
467 	return 0xfe | d0;
468 }
469 
470 
471 /* Memory maps */
472 
ufo_map(address_map & map)473 void ufo_state::ufo_map(address_map &map)
474 {
475 	map(0x0000, 0xbfff).rom();
476 	map(0xe000, 0xffff).ram();
477 }
478 
ufo_portmap(address_map & map)479 void ufo_state::ufo_portmap(address_map &map)
480 {
481 	map.unmap_value_high();
482 	map.global_mask(0xff);
483 	map(0x00, 0x03).rw("pit", FUNC(pit8254_device::read), FUNC(pit8254_device::write));
484 	map(0x40, 0x43).rw("ym", FUNC(ym3438_device::read), FUNC(ym3438_device::write));
485 	map(0x80, 0xbf).rw(m_io1, FUNC(sega_315_5296_device::read), FUNC(sega_315_5296_device::write));
486 	map(0xc0, 0xff).rw(m_io2, FUNC(sega_315_5296_device::read), FUNC(sega_315_5296_device::write));
487 }
488 
ex_ufo21_portmap(address_map & map)489 void ufo_state::ex_ufo21_portmap(address_map &map)
490 {
491 	ufo_portmap(map);
492 	map(0x20, 0x20).w(m_upd, FUNC(upd7759_device::port_w));
493 	map(0x60, 0x6f).rw("io3", FUNC(sega_315_5338a_device::read), FUNC(sega_315_5338a_device::write));
494 }
495 
ex_ufo800_portmap(address_map & map)496 void ufo_state::ex_ufo800_portmap(address_map &map)
497 {
498 	ufo_portmap(map);
499 //  map(0x60, 0x67).noprw(); // unused?
500 //  map(0x68, 0x68).nopw(); // ?
501 }
502 
503 
504 
505 /***************************************************************************
506 
507   Inputs
508 
509 ***************************************************************************/
510 
511 static INPUT_PORTS_START( newufo )
512 	PORT_START("IN1")
513 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_NAME("P1 Coin 1") // 100 Y
514 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN3 ) PORT_NAME("P1 Coin 2") // 500 Y
515 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("P1 Test")
516 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("P1 Service Coin")
517 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SERVICE3 ) PORT_NAME("P1 Credit Clear")
518 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 )
519 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 )
520 	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Prize Sensor")
521 
522 	PORT_START("IN2")
523 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_NAME("P2 Coin 1") // 100 Y
524 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN4 ) PORT_NAME("P2 Coin 2") // 500 Y
PORT_CODE(KEYCODE_F1)525 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("P2 Test") PORT_CODE(KEYCODE_F1)
526 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SERVICE2 ) PORT_NAME("P2 Service Coin")
527 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SERVICE4 ) PORT_NAME("P2 Credit Clear")
528 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
529 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
530 	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 Prize Sensor")
531 
532 	PORT_START("DSW1") // coinage
533 	PORT_DIPNAME( 0x01, 0x01, "UNK1-01" )
534 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
535 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
536 	PORT_DIPNAME( 0x02, 0x02, "UNK1-02" )
537 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
538 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
539 	PORT_DIPNAME( 0x04, 0x04, "UNK1-04" )
540 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
541 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
542 	PORT_DIPNAME( 0x08, 0x08, "UNK1-08" )
543 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
544 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
545 	PORT_DIPNAME( 0x10, 0x10, "UNK1-10" )
546 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
547 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
548 	PORT_DIPNAME( 0x20, 0x20, "UNK1-20" )
549 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
550 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
551 	PORT_DIPNAME( 0x40, 0x40, "UNK1-40" )
552 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
553 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
554 	PORT_DIPNAME( 0x80, 0x80, "UNK1-80" )
555 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
556 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
557 
558 	PORT_START("DSW2")
559 	PORT_DIPNAME( 0x01, 0x01, "UNK2-01 Demo Music Off" )
560 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
561 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
562 	PORT_DIPNAME( 0x02, 0x02, "UNK2-02" )
563 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
564 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
565 	PORT_DIPNAME( 0x04, 0x04, "UNK2-04 Initial Motor Test" )
566 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
567 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
568 	PORT_DIPNAME( 0x08, 0x08, "UNK2-08" )
569 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
570 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
571 	PORT_DIPNAME( 0x10, 0x10, "UNK2-10 Disable Prize Sensor" )
572 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
573 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
574 	PORT_DIPNAME( 0x20, 0x20, "UNK2-20" )
575 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
576 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
577 	PORT_DIPNAME( 0x40, 0x40, "UNK2-40" )
578 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
579 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
580 	PORT_DIPNAME( 0x80, 0x80, "UNK2-80" )
581 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
582 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
583 INPUT_PORTS_END
584 
585 static INPUT_PORTS_START( ufomini )
586 	PORT_INCLUDE( newufo )
587 
588 	PORT_MODIFY("IN2")
589 	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
590 INPUT_PORTS_END
591 
592 
593 static INPUT_PORTS_START( ufo21 )
594 	PORT_START("IN1")
595 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Test Button")
596 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("P1 Service Coin")
597 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_NAME("P1 Coin 1")
598 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
599 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
600 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE2 ) PORT_NAME("P2 Service Coin")
601 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_NAME("P2 Coin 1")
602 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
603 
604 	PORT_START("IN2")
605 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
606 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
607 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
608 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
609 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
610 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
611 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_PLAYER(2)
612 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_PLAYER(2)
613 
614 	PORT_START("DSW1") // coinage
615 	PORT_DIPNAME( 0x01, 0x01, "UNK1-01" )
616 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
617 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
618 	PORT_DIPNAME( 0x02, 0x02, "UNK1-02" )
619 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
620 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
621 	PORT_DIPNAME( 0x04, 0x04, "UNK1-04" )
622 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
623 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
624 	PORT_DIPNAME( 0x08, 0x08, "UNK1-08" )
625 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
626 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
627 	PORT_DIPNAME( 0x10, 0x10, "UNK1-10" )
628 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
629 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
630 	PORT_DIPNAME( 0x20, 0x20, "UNK1-20" )
631 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
632 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
633 	PORT_DIPNAME( 0x40, 0x40, "UNK1-40" )
634 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
635 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
636 	PORT_DIPNAME( 0x80, 0x80, "UNK1-80" )
637 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
638 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
639 
640 	PORT_START("DSW2")
641 	PORT_DIPNAME( 0x01, 0x01, "UNK2-01" )
642 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
643 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
644 	PORT_DIPNAME( 0x02, 0x02, "UNK2-02" )
645 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
646 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
647 	PORT_DIPNAME( 0x04, 0x04, "UNK2-04" )
648 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
649 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
650 	PORT_DIPNAME( 0x08, 0x08, "UNK2-08 Demo Music On" )
651 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
652 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
653 	PORT_DIPNAME( 0x10, 0x10, "UNK2-10" )
654 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
655 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
656 	PORT_DIPNAME( 0x20, 0x20, "UNK2-20" )
657 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
658 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
659 	PORT_DIPNAME( 0x40, 0x40, "UNK2-40" )
660 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
661 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
662 	PORT_DIPNAME( 0x80, 0x80, "UNK2-80" )
663 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
664 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
665 INPUT_PORTS_END
666 
667 static INPUT_PORTS_START( ufo800 )
668 	PORT_START("IN1")
669 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Test Button")
670 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("P1 Service Coin")
671 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_NAME("P1 Coin 1")
672 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN3 ) PORT_NAME("P1 Coin 2")
673 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
674 
675 	PORT_START("IN2")
676 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
677 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
678 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
679 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
680 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
681 
682 	PORT_START("DSW1") // coinage
683 	PORT_DIPNAME( 0x01, 0x01, "UNK1-01" )
684 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
685 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
686 	PORT_DIPNAME( 0x02, 0x02, "UNK1-02" )
687 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
688 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
689 	PORT_DIPNAME( 0x04, 0x04, "UNK1-04" )
690 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
691 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
692 	PORT_DIPNAME( 0x08, 0x08, "UNK1-08" )
693 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
694 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
695 	PORT_DIPNAME( 0x10, 0x10, "UNK1-10" )
696 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
697 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
698 	PORT_DIPNAME( 0x20, 0x20, "UNK1-20" )
699 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
700 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
701 	PORT_DIPNAME( 0x40, 0x40, "UNK1-40" )
702 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
703 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
704 	PORT_DIPNAME( 0x80, 0x80, "UNK1-80" )
705 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
706 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
707 
708 	PORT_START("DSW2")
709 	PORT_DIPNAME( 0x01, 0x01, "UNK2-01 BGM Select" )
710 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
711 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
712 	PORT_DIPNAME( 0x02, 0x02, "UNK2-02 BGM Select" )
713 	PORT_DIPSETTING(    0x02, DEF_STR( Off ) )
714 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
715 	PORT_DIPNAME( 0x04, 0x04, "UNK2-04" )
716 	PORT_DIPSETTING(    0x04, DEF_STR( Off ) )
717 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
718 	PORT_DIPNAME( 0x08, 0x08, "UNK2-08" )
719 	PORT_DIPSETTING(    0x08, DEF_STR( Off ) )
720 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
721 	PORT_DIPNAME( 0x10, 0x10, "UNK2-10" )
722 	PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
723 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
724 	PORT_DIPNAME( 0x20, 0x20, "UNK2-20" )
725 	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
726 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
727 	PORT_DIPNAME( 0x40, 0x40, "UNK2-40" )
728 	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
729 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
730 	PORT_DIPNAME( 0x80, 0x80, "UNK2-80" )
731 	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
732 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
733 INPUT_PORTS_END
734 
735 
736 
737 /***************************************************************************
738 
739   Machine Config
740 
741 ***************************************************************************/
742 
743 void ufo_state::machine_reset()
744 {
745 }
746 
machine_start()747 void ufo_state::machine_start()
748 {
749 	m_counters.resolve();
750 	m_digits.resolve();
751 	m_lamps.resolve();
752 
753 	// init/zerofill/register for savestates
754 	static const float motor_speeds[4] =
755 		{ 1.0f/CABINET_WIDTH, 1.0f/CABINET_DEPTH, 1.0f/CABINET_HEIGHT, 1.0f/CRANE_SIZE };
756 
757 	for (int m = 0; m < 4; m++)
758 	{
759 		for (auto & elem : m_player)
760 		{
761 			elem.motor[m].running = 0;
762 			elem.motor[m].direction = 0;
763 			elem.motor[m].position = 0.5;
764 			elem.motor[m].speed = motor_speeds[m];
765 		}
766 
767 		save_item(NAME(m_player[0].motor[m].running), m);
768 		save_item(NAME(m_player[0].motor[m].direction), m);
769 		save_item(NAME(m_player[0].motor[m].position), m);
770 
771 		save_item(NAME(m_player[1].motor[m].running), m);
772 		save_item(NAME(m_player[1].motor[m].direction), m);
773 		save_item(NAME(m_player[1].motor[m].position), m);
774 	}
775 
776 	m_stepper = 0;
777 	save_item(NAME(m_stepper));
778 }
779 
newufo(machine_config & config)780 void ufo_state::newufo(machine_config &config)
781 {
782 	/* basic machine hardware */
783 	Z80(config, m_maincpu, XTAL(16'000'000)/2);
784 	m_maincpu->set_addrmap(AS_PROGRAM, &ufo_state::ufo_map);
785 	m_maincpu->set_addrmap(AS_IO, &ufo_state::ufo_portmap);
786 
787 	TIMER(config, "motor_timer").configure_periodic(FUNC(ufo_state::simulate_xyz), attotime::from_hz(MOTOR_SPEED));
788 	TIMER(config, "update_timer").configure_periodic(FUNC(ufo_state::update_info), attotime::from_hz(60));
789 
790 	SEGA_315_5296(config, m_io1, XTAL(16'000'000));
791 	// all ports set to input
792 	m_io1->in_pa_callback().set(FUNC(ufo_state::crane_limits_r));
793 	m_io1->in_pb_callback().set(FUNC(ufo_state::crane_limits_r));
794 	m_io1->in_pe_callback().set_ioport("IN1");
795 	m_io1->in_pf_callback().set_ioport("DSW1");
796 	m_io1->in_pg_callback().set_ioport("DSW2");
797 	m_io1->in_ph_callback().set_ioport("IN2");
798 
799 	SEGA_315_5296(config, m_io2, XTAL(16'000'000));
800 	// all ports set to output
801 	m_io2->out_pa_callback().set(FUNC(ufo_state::stepper_w));
802 	m_io2->out_pb_callback().set(FUNC(ufo_state::cp_lamps_w));
803 	m_io2->out_pc_callback().set(FUNC(ufo_state::cp_digits_w));
804 	m_io2->out_pd_callback().set(FUNC(ufo_state::cp_digits_w));
805 	m_io2->out_pe_callback().set(FUNC(ufo_state::crane_xyz_w));
806 	m_io2->out_pf_callback().set(FUNC(ufo_state::crane_xyz_w));
807 	m_io2->out_pg_callback().set(FUNC(ufo_state::ufo_lamps_w));
808 
809 	pit8254_device &pit(PIT8254(config, "pit", XTAL(16'000'000)/2)); // uPD71054C, configuration is unknown
810 	pit.set_clk<0>(XTAL(16'000'000)/2/256);
811 	pit.out_handler<0>().set(FUNC(ufo_state::pit_out0));
812 	pit.set_clk<1>(XTAL(16'000'000)/2/256);
813 	pit.out_handler<1>().set(FUNC(ufo_state::pit_out1));
814 	pit.set_clk<2>(XTAL(16'000'000)/2/256);
815 	pit.out_handler<2>().set(FUNC(ufo_state::pit_out2));
816 
817 	/* no video! */
818 
819 	/* sound hardware */
820 	SPEAKER(config, "mono").front_center();
821 
822 	ym3438_device &ym(YM3438(config, "ym", XTAL(16'000'000)/2));
823 	ym.irq_handler().set_inputline("maincpu", 0);
824 	ym.add_route(0, "mono", 0.40);
825 	ym.add_route(1, "mono", 0.40);
826 }
827 
ufomini(machine_config & config)828 void ufo_state::ufomini(machine_config &config)
829 {
830 	newufo(config);
831 
832 	/* basic machine hardware */
833 	m_io1->in_pc_callback().set_ioport("IN1");
834 	m_io1->in_pe_callback().set_constant(0);
835 	m_io1->in_ph_callback().set_constant(0);
836 }
837 
838 
ufo21(machine_config & config)839 void ufo_state::ufo21(machine_config &config)
840 {
841 	newufo(config);
842 
843 	/* basic machine hardware */
844 	m_maincpu->set_addrmap(AS_IO, &ufo_state::ex_ufo21_portmap);
845 
846 	m_io1->in_pa_callback().set(FUNC(ufo_state::ex_crane_limits_r));
847 	m_io1->in_pb_callback().set(FUNC(ufo_state::ex_crane_limits_r));
848 	m_io1->in_pc_callback().set(FUNC(ufo_state::ex_crane_open_r));
849 
850 	m_io2->out_pa_callback().set(FUNC(ufo_state::ex_stepper_w));
851 	m_io2->out_pb_callback().set(FUNC(ufo_state::ex_cp_lamps_w));
852 	m_io2->out_pe_callback().set(FUNC(ufo_state::ex_crane_xyz_w));
853 	m_io2->out_pf_callback().set(FUNC(ufo_state::ex_crane_xyz_w));
854 	m_io2->out_pg_callback().set_nop();
855 
856 	sega_315_5338a_device &io3(SEGA_315_5338A(config, "io3", 0));
857 	io3.out_pa_callback().set(FUNC(ufo_state::ex_upd_start_w));
858 	io3.in_pb_callback().set(FUNC(ufo_state::ex_upd_busy_r));
859 	io3.out_pe_callback().set(FUNC(ufo_state::ex_ufo21_lamps1_w));
860 	io3.out_pf_callback().set(FUNC(ufo_state::ex_ufo21_lamps2_w));
861 
862 	/* sound hardware */
863 	UPD7759(config, m_upd);
864 	m_upd->add_route(ALL_OUTPUTS, "mono", 0.75);
865 }
866 
ufo800(machine_config & config)867 void ufo_state::ufo800(machine_config &config)
868 {
869 	newufo(config);
870 
871 	/* basic machine hardware */
872 	m_maincpu->set_addrmap(AS_IO, &ufo_state::ex_ufo800_portmap);
873 
874 	m_io1->in_pa_callback().set(FUNC(ufo_state::ex_crane_limits_r));
875 	m_io1->in_pb_callback().set_ioport("IN2");
876 	m_io1->in_pc_callback().set(FUNC(ufo_state::ex_crane_open_r));
877 	m_io1->in_pd_callback().set_ioport("IN1");
878 	m_io1->in_pe_callback().set_constant(0);
879 	m_io1->in_ph_callback().set_constant(0);
880 
881 	m_io2->out_pa_callback().set(FUNC(ufo_state::ex_stepper_w));
882 	m_io2->out_pb_callback().set(FUNC(ufo_state::ex_cp_lamps_w));
883 	m_io2->out_pe_callback().set(FUNC(ufo_state::ex_crane_xyz_w));
884 	m_io2->out_pf_callback().set(FUNC(ufo_state::ex_ufo800_lamps_w));
885 	m_io2->out_pg_callback().set_nop();
886 }
887 
888 
889 
890 /***************************************************************************
891 
892   Game drivers
893 
894 ***************************************************************************/
895 
896 ROM_START( newufo )
897 	ROM_REGION( 0x10000, "maincpu", 0 )
898 	ROM_LOAD( "epr-13896.bin",   0x000000, 0x010000, CRC(ca94be57) SHA1(acb6a22940c5e9ce639c7c30eb3948324b223090) )
899 ROM_END
900 
901 ROM_START( newufo_sonic )
902 	ROM_REGION( 0x10000, "maincpu", 0 )
903 	ROM_LOAD( "epr-14124.bin",   0x000000, 0x010000, CRC(2bdbad89) SHA1(10de4b266471a68083ec4bc439b301b6587ccfd6) )
904 ROM_END
905 
906 ROM_START( newufo_nfl )
907 	ROM_REGION( 0x10000, "maincpu", 0 )
908 	ROM_LOAD( "epr-15261.bin",   0x000000, 0x010000, CRC(338c00d3) SHA1(03152956c6f1e4d5a1a11ee49f94a8c5eb550815) )
909 ROM_END
910 
911 ROM_START( newufo_xmas )
912 	ROM_REGION( 0x10000, "maincpu", 0 )
913 	ROM_LOAD( "epr-15340.bin",   0x000000, 0x010000, CRC(6287c9ac) SHA1(bc6bc84bb432424e1d25e01113e8e331fa64f96f) )
914 ROM_END
915 
916 
917 ROM_START( ufomini )
918 	ROM_REGION( 0x10000, "maincpu", 0 )
919 	ROM_LOAD( "epr-14355.bin",   0x000000, 0x010000, CRC(fbc969c5) SHA1(4a99dcd36bc48b6472988e0bc679fd61af17359c) )
920 ROM_END
921 
922 
923 ROM_START( ufo21 )
924 	ROM_REGION( 0x10000, "maincpu", 0 )
925 	ROM_LOAD( "epr-19063a.bin",  0x000000, 0x010000, CRC(2e13e3e9) SHA1(6908f7db79c1a1da4ebc0456afc50ff18f2e8cf3) )
926 
927 	ROM_REGION( 0x40000, "upd", 0 )
928 	ROM_LOAD( "epr-19064.bin",   0x000000, 0x040000, CRC(ab62c1f0) SHA1(8791a88546ae69e710e128ffc2ea6e9b464f0631) )
929 ROM_END
930 
931 ROM_START( ufo800 )
932 	ROM_REGION( 0x10000, "maincpu", 0 )
933 	ROM_LOAD( "epr-20413a.bin",  0x000000, 0x010000, CRC(36e9da6d) SHA1(8e1dbf8b24bc31be7de28f4d562838c291af7c7b) )
934 ROM_END
935 
936 
937 GAMEL( 1991, newufo,       0,      newufo,  newufo,  ufo_state, empty_init, ROT0, "Sega", "New UFO Catcher (standard)", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_newufo )
938 GAMEL( 1991, newufo_sonic, newufo, newufo,  newufo,  ufo_state, empty_init, ROT0, "Sega", "New UFO Catcher (Sonic The Hedgehog)", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_newufo )
939 GAMEL( 1991, newufo_nfl,   newufo, newufo,  newufo,  ufo_state, empty_init, ROT0, "Sega", "New UFO Catcher (Team NFL)", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_newufo )
940 GAMEL( 1991, newufo_xmas,  newufo, newufo,  newufo,  ufo_state, empty_init, ROT0, "Sega", "New UFO Catcher (Christmas season ROM kit)", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_newufo )
941 GAMEL( 1991, ufomini,      0,      ufomini, ufomini, ufo_state, empty_init, ROT0, "Sega", "UFO Catcher Mini", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_ufomini )
942 GAMEL( 1996, ufo21,        0,      ufo21,   ufo21,   ufo_state, empty_init, ROT0, "Sega", "UFO Catcher 21", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_ufo21 )
943 GAMEL( 1998, ufo800,       0,      ufo800,  ufo800,  ufo_state, empty_init, ROT0, "Sega", "UFO Catcher 800", MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE, layout_ufo800 )
944