1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /*************************************************************************
4
5 ldplayer.c
6
7 Laserdisc player driver.
8
9 **************************************************************************/
10
11 #include "emu.h"
12
13 #include "cpu/mcs48/mcs48.h"
14 #include "machine/ldpr8210.h"
15 #include "machine/ldv1000.h"
16
17 #include "ui/uimain.h"
18
19 #include "emuopts.h"
20 #include "romload.h"
21 #include "speaker.h"
22 #include "screen.h"
23
24 #include "chd.h"
25
26 #include "pr8210.lh"
27
28 #include <cctype>
29
30
31 class ldplayer_state : public driver_device
32 {
33 public:
34 // construction/destruction
ldplayer_state(const machine_config & mconfig,device_type type,const char * tag)35 ldplayer_state(const machine_config &mconfig, device_type type, const char *tag)
36 : driver_device(mconfig, type, tag)
37 , m_screen(*this, "screen")
38 , m_last_controls(0)
39 , m_playing(false) { }
40
41 void ldplayer_ntsc(machine_config &config);
42
43 protected:
44 // device overrides
45 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
46 virtual void machine_start() override;
47 virtual void machine_reset() override;
48
49 // callback hook
50 chd_file *get_disc();
51
52 // internal helpers
53 void process_commands();
54
55 // derived classes
execute_command(int command)56 virtual void execute_command(int command) { assert(false); }
57
58 // timer IDs
59 enum
60 {
61 TIMER_ID_AUTOPLAY,
62 TIMER_ID_VSYNC_UPDATE
63 };
64
65 // commands
66 enum
67 {
68 CMD_SCAN_REVERSE,
69 CMD_STEP_REVERSE,
70 CMD_SLOW_REVERSE,
71 CMD_FAST_REVERSE,
72 CMD_SCAN_FORWARD,
73 CMD_STEP_FORWARD,
74 CMD_SLOW_FORWARD,
75 CMD_FAST_FORWARD,
76 CMD_PLAY,
77 CMD_PAUSE,
78 CMD_FRAME_TOGGLE,
79 CMD_CHAPTER_TOGGLE,
80 CMD_CH1_TOGGLE,
81 CMD_CH2_TOGGLE,
82 CMD_0,
83 CMD_1,
84 CMD_2,
85 CMD_3,
86 CMD_4,
87 CMD_5,
88 CMD_6,
89 CMD_7,
90 CMD_8,
91 CMD_9,
92 CMD_SEARCH
93 };
94
95 // internal state
96 required_device<screen_device> m_screen;
97 std::string m_filename;
98 ioport_value m_last_controls;
99 bool m_playing;
100 };
101
102
103 class pr8210_state : public ldplayer_state
104 {
105 public:
106 // construction/destruction
pr8210_state(const machine_config & mconfig,device_type type,const char * tag)107 pr8210_state(const machine_config &mconfig, device_type type, const char *tag)
108 : ldplayer_state(mconfig, type, tag),
109 m_laserdisc(*this, "laserdisc"),
110 m_command_buffer_in(0),
111 m_command_buffer_out(0) { }
112
113 void pr8210(machine_config &config);
114 protected:
115 // device overrides
116 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
117 virtual void machine_start() override;
118 virtual void machine_reset() override;
119
120 // command execution hook
121 virtual void execute_command(int command) override;
122
123 // internal helpers
124 inline void add_command(uint8_t command);
125
126 // timer IDs
127 enum
128 {
129 TIMER_ID_BIT = 100,
130 TIMER_ID_BIT_OFF
131 };
132
133 required_device<pioneer_pr8210_device> m_laserdisc;
134
135 // internal state
136 emu_timer *m_bit_timer;
137 uint32_t m_command_buffer_in;
138 uint32_t m_command_buffer_out;
139 uint8_t m_command_buffer[10];
140 };
141
142
143 class ldv1000_state : public ldplayer_state
144 {
145 public:
146 // construction/destruction
ldv1000_state(const machine_config & mconfig,device_type type,const char * tag)147 ldv1000_state(const machine_config &mconfig, device_type type, const char *tag)
148 : ldplayer_state(mconfig, type, tag),
149 m_laserdisc(*this, "laserdisc") { }
150
151 void ldv1000(machine_config &config);
152 protected:
153 required_device<pioneer_ldv1000_device> m_laserdisc;
154
155 // command execution hook
156 virtual void execute_command(int command) override;
157 };
158
159
160
161 /*************************************
162 *
163 * Disc location
164 *
165 *************************************/
166
get_disc()167 chd_file *ldplayer_state::get_disc()
168 {
169 bool found = false;
170 // open a path to the ROMs and find the first CHD file
171 file_enumerator path(machine().options().media_path());
172
173 // iterate while we get new objects
174 const osd::directory::entry *dir;
175 while ((dir = path.next()) != NULL)
176 {
177 int length = strlen(dir->name);
178
179 // look for files ending in .chd
180 if (length > 4 &&
181 dir->name[length - 4] == '.' &&
182 tolower(dir->name[length - 3]) == 'c' &&
183 tolower(dir->name[length - 2]) == 'h' &&
184 tolower(dir->name[length - 1]) == 'd')
185 {
186 // open the file itself via our search path
187 emu_file image_file(machine().options().media_path(), OPEN_FLAG_READ);
188 osd_file::error filerr = image_file.open(dir->name);
189 if (filerr == osd_file::error::NONE)
190 {
191 std::string fullpath(image_file.fullpath());
192 image_file.close();
193
194 // try to open the CHD
195
196 if (machine().rom_load().set_disk_handle("laserdisc", fullpath.c_str()) == CHDERR_NONE)
197 {
198 m_filename.assign(dir->name);
199 found = true;
200 break;
201 }
202 }
203 }
204 }
205
206 // if we failed, pop a message and exit
207 if (found == false) {
208 machine().ui().popup_time(10, "No valid image file found!\n");
209 return nullptr;
210 }
211
212 return machine().rom_load().get_disk_handle("laserdisc");
213 }
214
215
216
217 /*************************************
218 *
219 * Timers and sync
220 *
221 *************************************/
222
process_commands()223 void ldplayer_state::process_commands()
224 {
225 ioport_value controls = ioport("controls")->read();
226 int number;
227
228 // step backwards
229 if (!(m_last_controls & 0x01) && (controls & 0x01))
230 execute_command(CMD_STEP_REVERSE);
231
232 // step forwards
233 if (!(m_last_controls & 0x02) && (controls & 0x02))
234 execute_command(CMD_STEP_FORWARD);
235
236 // scan backwards
237 if (controls & 0x04)
238 execute_command(CMD_SCAN_REVERSE);
239
240 // scan forwards
241 if (controls & 0x08)
242 execute_command(CMD_SCAN_FORWARD);
243
244 // slow backwards
245 if (!(m_last_controls & 0x10) && (controls & 0x10))
246 execute_command(CMD_SLOW_REVERSE);
247
248 // slow forwards
249 if (!(m_last_controls & 0x20) && (controls & 0x20))
250 execute_command(CMD_SLOW_FORWARD);
251
252 // fast backwards
253 if (controls & 0x40)
254 execute_command(CMD_FAST_REVERSE);
255
256 // fast forwards
257 if (controls & 0x80)
258 execute_command(CMD_FAST_FORWARD);
259
260 // play/pause
261 if (!(m_last_controls & 0x100) && (controls & 0x100))
262 {
263 m_playing = !m_playing;
264 execute_command(m_playing ? CMD_PLAY : CMD_PAUSE);
265 }
266
267 // toggle frame display
268 if (!(m_last_controls & 0x200) && (controls & 0x200))
269 execute_command(CMD_FRAME_TOGGLE);
270
271 // toggle chapter display
272 if (!(m_last_controls & 0x400) && (controls & 0x400))
273 execute_command(CMD_CHAPTER_TOGGLE);
274
275 // toggle left channel
276 if (!(m_last_controls & 0x800) && (controls & 0x800))
277 execute_command(CMD_CH1_TOGGLE);
278
279 // toggle right channel
280 if (!(m_last_controls & 0x1000) && (controls & 0x1000))
281 execute_command(CMD_CH2_TOGGLE);
282
283 // numbers
284 for (number = 0; number < 10; number++)
285 if (!(m_last_controls & (0x10000 << number)) && (controls & (0x10000 << number)))
286 execute_command(CMD_0 + number);
287
288 // enter
289 if (!(m_last_controls & 0x4000000) && (controls & 0x4000000))
290 execute_command(CMD_SEARCH);
291
292 m_last_controls = controls;
293 }
294
295
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)296 void ldplayer_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
297 {
298 switch (id)
299 {
300 case TIMER_ID_VSYNC_UPDATE:
301 {
302 // handle commands
303 if (param == 0)
304 process_commands();
305
306 // set a timer to go off on the next VBLANK
307 int vblank_scanline = m_screen->visible_area().max_y + 1;
308 attotime target = m_screen->time_until_pos(vblank_scanline);
309 timer_set(target, TIMER_ID_VSYNC_UPDATE);
310 break;
311 }
312
313 case TIMER_ID_AUTOPLAY:
314 // start playing
315 execute_command(CMD_PLAY);
316 m_playing = true;
317 break;
318 }
319 }
320
321
machine_start()322 void ldplayer_state::machine_start()
323 {
324 // start the vsync timer going
325 timer_set(attotime::zero, TIMER_ID_VSYNC_UPDATE, 1);
326 }
327
328
machine_reset()329 void ldplayer_state::machine_reset()
330 {
331 // set up a timer to start playing immediately
332 timer_set(attotime::zero, TIMER_ID_AUTOPLAY);
333
334 // indicate the name of the file we opened
335 popmessage("Opened %s\n", m_filename);
336 }
337
338
339
340 /*************************************
341 *
342 * PR-8210 implementation
343 *
344 *************************************/
345
add_command(uint8_t command)346 void pr8210_state::add_command(uint8_t command)
347 {
348 m_command_buffer[m_command_buffer_in++ % ARRAY_LENGTH(m_command_buffer)] = (command & 0x1f) | 0x20;
349 m_command_buffer[m_command_buffer_in++ % ARRAY_LENGTH(m_command_buffer)] = 0x00 | 0x20;
350 }
351
352
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)353 void pr8210_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
354 {
355 switch (id)
356 {
357 case TIMER_ID_BIT:
358 {
359 attotime duration = attotime::from_msec(30);
360 uint8_t bitsleft = param >> 16;
361 uint8_t data = param;
362
363 // if we have bits, process
364 if (bitsleft != 0)
365 {
366 // assert the line and set a timer for deassertion
367 m_laserdisc->control_w(ASSERT_LINE);
368 timer_set(attotime::from_usec(250), TIMER_ID_BIT_OFF);
369
370 // space 0 bits apart by 1msec, and 1 bits by 2msec
371 duration = attotime::from_msec((data & 0x80) ? 2 : 1);
372 data <<= 1;
373 bitsleft--;
374 }
375
376 // if we're out of bits, queue up the next command
377 else if (bitsleft == 0 && m_command_buffer_in != m_command_buffer_out)
378 {
379 data = m_command_buffer[m_command_buffer_out++ % ARRAY_LENGTH(m_command_buffer)];
380 bitsleft = 12;
381 }
382 m_bit_timer->adjust(duration, (bitsleft << 16) | data);
383 break;
384 }
385
386 // deassert the control line
387 case TIMER_ID_BIT_OFF:
388 m_laserdisc->control_w(CLEAR_LINE);
389 break;
390
391 // others to the parent class
392 default:
393 ldplayer_state::device_timer(timer, id, param, ptr);
394 break;
395 }
396 }
397
machine_start()398 void pr8210_state::machine_start()
399 {
400 ldplayer_state::machine_start();
401 m_bit_timer = timer_alloc(TIMER_ID_BIT);
402 }
403
machine_reset()404 void pr8210_state::machine_reset()
405 {
406 ldplayer_state::machine_reset();
407 m_bit_timer->adjust(attotime::zero);
408 }
409
410
execute_command(int command)411 void pr8210_state::execute_command(int command)
412 {
413 static const uint8_t digits[10] = { 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 0x03, 0x13 };
414
415 switch (command)
416 {
417 case CMD_SCAN_REVERSE:
418 if (m_command_buffer_in == m_command_buffer_out ||
419 m_command_buffer_in == (m_command_buffer_out + 1) % ARRAY_LENGTH(m_command_buffer))
420 {
421 add_command(0x1c);
422 m_playing = true;
423 }
424 break;
425
426 case CMD_STEP_REVERSE:
427 add_command(0x12);
428 m_playing = false;
429 break;
430
431 case CMD_SLOW_REVERSE:
432 add_command(0x02);
433 m_playing = true;
434 break;
435
436 case CMD_FAST_REVERSE:
437 if (m_command_buffer_in == m_command_buffer_out ||
438 m_command_buffer_in == (m_command_buffer_out + 1) % ARRAY_LENGTH(m_command_buffer))
439 {
440 add_command(0x0c);
441 m_playing = true;
442 }
443 break;
444
445 case CMD_SCAN_FORWARD:
446 if (m_command_buffer_in == m_command_buffer_out ||
447 m_command_buffer_in == (m_command_buffer_out + 1) % ARRAY_LENGTH(m_command_buffer))
448 {
449 add_command(0x08);
450 m_playing = true;
451 }
452 break;
453
454 case CMD_STEP_FORWARD:
455 add_command(0x04);
456 m_playing = false;
457 break;
458
459 case CMD_SLOW_FORWARD:
460 add_command(0x18);
461 m_playing = true;
462 break;
463
464 case CMD_FAST_FORWARD:
465 if (m_command_buffer_in == m_command_buffer_out ||
466 m_command_buffer_in == (m_command_buffer_out + 1) % ARRAY_LENGTH(m_command_buffer))
467 {
468 add_command(0x10);
469 m_playing = true;
470 }
471 break;
472
473 case CMD_PLAY:
474 add_command(0x14);
475 m_playing = true;
476 break;
477
478 case CMD_PAUSE:
479 add_command(0x0a);
480 m_playing = false;
481 break;
482
483 case CMD_FRAME_TOGGLE:
484 add_command(0x0b);
485 break;
486
487 case CMD_CHAPTER_TOGGLE:
488 add_command(0x06);
489 break;
490
491 case CMD_CH1_TOGGLE:
492 add_command(0x0e);
493 break;
494
495 case CMD_CH2_TOGGLE:
496 add_command(0x16);
497 break;
498
499 case CMD_0:
500 case CMD_1:
501 case CMD_2:
502 case CMD_3:
503 case CMD_4:
504 case CMD_5:
505 case CMD_6:
506 case CMD_7:
507 case CMD_8:
508 case CMD_9:
509 add_command(digits[command - CMD_0]);
510 break;
511
512 case CMD_SEARCH:
513 add_command(0x1a);
514 m_playing = false;
515 break;
516 }
517 }
518
519
520
521 /*************************************
522 *
523 * LD-V1000 implementation
524 *
525 *************************************/
526
execute_command(int command)527 void ldv1000_state::execute_command(int command)
528 {
529 static const uint8_t digits[10] = { 0x3f, 0x0f, 0x8f, 0x4f, 0x2f, 0xaf, 0x6f, 0x1f, 0x9f, 0x5f };
530 switch (command)
531 {
532 case CMD_SCAN_REVERSE:
533 m_laserdisc->data_w(0xf8);
534 m_playing = true;
535 break;
536
537 case CMD_STEP_REVERSE:
538 m_laserdisc->data_w(0xfe);
539 m_playing = false;
540 break;
541
542 case CMD_SCAN_FORWARD:
543 m_laserdisc->data_w(0xf0);
544 m_playing = true;
545 break;
546
547 case CMD_STEP_FORWARD:
548 m_laserdisc->data_w(0xf6);
549 m_playing = false;
550 break;
551
552 case CMD_PLAY:
553 m_laserdisc->data_w(0xfd);
554 m_playing = true;
555 break;
556
557 case CMD_PAUSE:
558 m_laserdisc->data_w(0xa0);
559 m_playing = false;
560 break;
561
562 case CMD_FRAME_TOGGLE:
563 m_laserdisc->data_w(0xf1);
564 break;
565
566 case CMD_0:
567 case CMD_1:
568 case CMD_2:
569 case CMD_3:
570 case CMD_4:
571 case CMD_5:
572 case CMD_6:
573 case CMD_7:
574 case CMD_8:
575 case CMD_9:
576 m_laserdisc->data_w(digits[command - CMD_0]);
577 break;
578
579 case CMD_SEARCH:
580 m_laserdisc->data_w(0xf7);
581 m_playing = false;
582 break;
583 }
584 }
585
586
587
588 /*************************************
589 *
590 * Port definitions
591 *
592 *************************************/
593
594 static INPUT_PORTS_START( ldplayer )
595 PORT_START("controls")
PORT_CODE(KEYCODE_LEFT)596 PORT_BIT( 0x0000001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Step reverse") PORT_CODE(KEYCODE_LEFT)
597 PORT_BIT( 0x0000002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Step forward") PORT_CODE(KEYCODE_RIGHT)
598 PORT_BIT( 0x0000004, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Scan reverse") PORT_CODE(KEYCODE_UP)
599 PORT_BIT( 0x0000008, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Scan forward") PORT_CODE(KEYCODE_DOWN)
600 PORT_BIT( 0x0000010, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Slow reverse") PORT_CODE(KEYCODE_OPENBRACE)
601 PORT_BIT( 0x0000020, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Slow forward") PORT_CODE(KEYCODE_CLOSEBRACE)
602 PORT_BIT( 0x0000040, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Fast reverse") PORT_CODE(KEYCODE_COMMA)
603 PORT_BIT( 0x0000080, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Fast forward") PORT_CODE(KEYCODE_STOP)
604 PORT_BIT( 0x0000100, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Play/Pause") PORT_CODE(KEYCODE_SPACE)
605 PORT_BIT( 0x0000200, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Toggle frame display") PORT_CODE(KEYCODE_F)
606 PORT_BIT( 0x0000400, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle chapter display") PORT_CODE(KEYCODE_C)
607 PORT_BIT( 0x0000800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle left channel") PORT_CODE(KEYCODE_L)
608 PORT_BIT( 0x0001000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle right channel") PORT_CODE(KEYCODE_R)
609 PORT_BIT( 0x0010000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("0") PORT_PLAYER(2) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_0)
610 PORT_BIT( 0x0020000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("1") PORT_PLAYER(2) PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_1)
611 PORT_BIT( 0x0040000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("2") PORT_PLAYER(2) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_2)
612 PORT_BIT( 0x0080000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("3") PORT_PLAYER(2) PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_3)
613 PORT_BIT( 0x0100000, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("4") PORT_PLAYER(2) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_4)
614 PORT_BIT( 0x0200000, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("5") PORT_PLAYER(2) PORT_CODE(KEYCODE_5_PAD) PORT_CODE(KEYCODE_5)
615 PORT_BIT( 0x0400000, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("6") PORT_PLAYER(2) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_6)
616 PORT_BIT( 0x0800000, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_NAME("7") PORT_PLAYER(2) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_7)
617 PORT_BIT( 0x1000000, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_NAME("8") PORT_PLAYER(2) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_8)
618 PORT_BIT( 0x2000000, IP_ACTIVE_HIGH, IPT_BUTTON10 ) PORT_NAME("9") PORT_PLAYER(2) PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_9)
619 PORT_BIT( 0x4000000, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_NAME("Enter") PORT_PLAYER(2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CODE(KEYCODE_ENTER)
620 INPUT_PORTS_END
621
622
623
624 /*************************************
625 *
626 * Machine drivers
627 *
628 *************************************/
629
630 void ldplayer_state::ldplayer_ntsc(machine_config &config)
631 {
632 }
633
634
ldv1000(machine_config & config)635 void ldv1000_state::ldv1000(machine_config &config)
636 {
637 ldplayer_ntsc(config);
638 pioneer_ldv1000_device &laserdisc(PIONEER_LDV1000(config, "laserdisc"));
639 laserdisc.set_get_disc(FUNC(ldv1000_state::get_disc));
640 laserdisc.add_ntsc_screen(config, "screen");
641
642 SPEAKER(config, "lspeaker").front_left();
643 SPEAKER(config, "rspeaker").front_right();
644 laserdisc.add_route(0, "lspeaker", 1.0);
645 laserdisc.add_route(1, "rspeaker", 1.0);
646 }
647
648
pr8210(machine_config & config)649 void pr8210_state::pr8210(machine_config &config)
650 {
651 ldplayer_ntsc(config);
652 pioneer_pr8210_device &laserdisc(PIONEER_PR8210(config, "laserdisc"));
653 laserdisc.set_get_disc(FUNC(pr8210_state::get_disc));
654 laserdisc.add_ntsc_screen(config, "screen");
655
656 SPEAKER(config, "lspeaker").front_left();
657 SPEAKER(config, "rspeaker").front_right();
658 laserdisc.add_route(0, "lspeaker", 1.0);
659 laserdisc.add_route(1, "rspeaker", 1.0);
660 }
661
662
663
664 /*************************************
665 *
666 * ROM definitions
667 *
668 *************************************/
669
670 ROM_START( simldv1000 )
671 DISK_REGION( "laserdisc" )
672 ROM_END
673
674
675 ROM_START( simpr8210 )
676 DISK_REGION( "laserdisc" )
677 ROM_END
678
679
680
681 /*************************************
682 *
683 * Game drivers
684 *
685 *************************************/
686
687 GAME( 2008, simldv1000, 0, ldv1000, ldplayer, ldv1000_state, empty_init, ROT0, "MAME", "Pioneer LDV-1000 Simulator", 0 )
688 GAMEL(2008, simpr8210, 0, pr8210, ldplayer, pr8210_state, empty_init, ROT0, "MAME", "Pioneer PR-8210 Simulator", 0, layout_pr8210 )
689