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