1 /***************************************************************************
2
3 Midway MCR system
4
5 ***************************************************************************/
6
7 #include <stdio.h>
8
9 #include "driver.h"
10 #include "machine/z80fmly.h"
11 #include "sndhrdw/mcr.h"
12 #include "cpu/m6800/m6800.h"
13 #include "cpu/m6809/m6809.h"
14 #include "cpu/z80/z80.h"
15 #include "mcr.h"
16
17
18 #define LOG(x)
19
20
21 /*************************************
22 *
23 * Global variables
24 *
25 *************************************/
26
27 double mcr68_timing_factor;
28
29 UINT8 mcr_cocktail_flip;
30
31
32
33 /*************************************
34 *
35 * Statics
36 *
37 *************************************/
38
39 static UINT8 m6840_status;
40 static UINT8 m6840_status_read_since_int;
41 static UINT8 m6840_msb_buffer;
42 static UINT8 m6840_lsb_buffer;
43 static struct counter_state
44 {
45 UINT8 control;
46 UINT16 latch;
47 UINT16 count;
48 void * timer;
49 UINT8 timer_active;
50 double period;
51 } m6840_state[3];
52
53 /* MCR/68k interrupt states */
54 static UINT8 m6840_irq_state;
55 static UINT8 m6840_irq_vector;
56 static UINT8 v493_irq_state;
57 static UINT8 v493_irq_vector;
58
59 static void (*v493_callback)(int param);
60
61 static UINT8 zwackery_sound_data;
62
63 static const double m6840_counter_periods[3] = { 1.0 / 30.0, 1000000.0, 1.0 / (512.0 * 30.0) };
64 static double m6840_internal_counter_period; /* 68000 CLK / 10 */
65
66
67
68 /*************************************
69 *
70 * Function prototypes
71 *
72 *************************************/
73
74 static void subtract_from_counter(int counter, int count);
75
76 static void mcr68_493_callback(int param);
77 static void zwackery_493_callback(int param);
78
79 static WRITE_HANDLER( zwackery_pia_2_w );
80 static WRITE_HANDLER( zwackery_pia_3_w );
81 static WRITE_HANDLER( zwackery_ca2_w );
82 static void zwackery_pia_irq(int state);
83
84 static void reload_count(int counter);
85 static void counter_fired_callback(int counter);
86
87
88
89 /*************************************
90 *
91 * Graphics declarations
92 *
93 *************************************/
94
95 struct GfxLayout mcr_bg_layout =
96 {
97 16,16,
98 RGN_FRAC(1,2),
99 4,
100 { RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+1, 0, 1 },
101 { 0, 0, 2, 2, 4, 4, 6, 6,
102 8, 8, 10, 10, 12, 12, 14, 14 },
103 { 0*8, 0*8, 2*8, 2*8,
104 4*8, 4*8, 6*8, 6*8,
105 8*8, 8*8, 10*8, 10*8,
106 12*8, 12*8, 14*8, 14*8 },
107 16*8
108 };
109
110
111 struct GfxLayout mcr_sprite_layout =
112 {
113 32,32,
114 RGN_FRAC(1,4),
115 4,
116 { 0, 1, 2, 3 },
117 { 0, 4,
118 RGN_FRAC(1,4)+0, RGN_FRAC(1,4)+4,
119 RGN_FRAC(2,4)+0, RGN_FRAC(2,4)+4,
120 RGN_FRAC(3,4)+0, RGN_FRAC(3,4)+4,
121 8, 12,
122 RGN_FRAC(1,4)+8, RGN_FRAC(1,4)+12,
123 RGN_FRAC(2,4)+8, RGN_FRAC(2,4)+12,
124 RGN_FRAC(3,4)+8, RGN_FRAC(3,4)+12,
125 16, 20,
126 RGN_FRAC(1,4)+16, RGN_FRAC(1,4)+20,
127 RGN_FRAC(2,4)+16, RGN_FRAC(2,4)+20,
128 RGN_FRAC(3,4)+16, RGN_FRAC(3,4)+20,
129 24, 28,
130 RGN_FRAC(1,4)+24, RGN_FRAC(1,4)+28,
131 RGN_FRAC(2,4)+24, RGN_FRAC(2,4)+28,
132 RGN_FRAC(3,4)+24, RGN_FRAC(3,4)+28 },
133 { 32*0, 32*1, 32*2, 32*3,
134 32*4, 32*5, 32*6, 32*7,
135 32*8, 32*9, 32*10, 32*11,
136 32*12, 32*13, 32*14, 32*15,
137 32*16, 32*17, 32*18, 32*19,
138 32*20, 32*21, 32*22, 32*23,
139 32*24, 32*25, 32*26, 32*27,
140 32*28, 32*29, 32*30, 32*31 },
141 32*32
142 };
143
144
145
146 /*************************************
147 *
148 * 6821 PIA declarations
149 *
150 *************************************/
151
152 READ_HANDLER( zwackery_port_2_r );
153
154 static struct pia6821_interface zwackery_pia_2_intf =
155 {
156 /*inputs : A/B,CA/B1,CA/B2 */ 0, input_port_0_r, 0, 0, 0, 0,
157 /*outputs: A/B,CA/B2 */ zwackery_pia_2_w, 0, 0, 0,
158 /*irqs : A/B */ zwackery_pia_irq, zwackery_pia_irq
159 };
160
161 static struct pia6821_interface zwackery_pia_3_intf =
162 {
163 /*inputs : A/B,CA/B1,CA/B2 */ input_port_1_r, zwackery_port_2_r, 0, 0, 0, 0,
164 /*outputs: A/B,CA/B2 */ zwackery_pia_3_w, 0, zwackery_ca2_w, 0,
165 /*irqs : A/B */ 0, 0
166 };
167
168 static struct pia6821_interface zwackery_pia_4_intf =
169 {
170 /*inputs : A/B,CA/B1,CA/B2 */ input_port_3_r, input_port_4_r, 0, 0, 0, 0,
171 /*outputs: A/B,CA/B2 */ 0, 0, 0, 0,
172 /*irqs : A/B */ 0, 0
173 };
174
175
176
177 /*************************************
178 *
179 * Generic MCR CTC interface
180 *
181 *************************************/
182
ctc_interrupt(int state)183 static void ctc_interrupt(int state)
184 {
185 cpu_set_irq_line_and_vector(0, 0, HOLD_LINE, Z80_VECTOR(0, state));
186 }
187
188
189 Z80_DaisyChain mcr_daisy_chain[] =
190 {
191 { z80ctc_reset, z80ctc_interrupt, z80ctc_reti, 0 }, /* CTC number 0 */
192 { 0, 0, 0, -1 } /* end mark */
193 };
194
195
196 static z80ctc_interface ctc_intf =
197 {
198 1, /* 1 chip */
199 { 0 }, /* clock (filled in from the CPU 0 clock) */
200 { 0 }, /* timer disables */
201 { ctc_interrupt }, /* interrupt handler */
202 { z80ctc_0_trg1_w },/* ZC/TO0 callback */
203 { 0 }, /* ZC/TO1 callback */
204 { 0 } /* ZC/TO2 callback */
205 };
206
207
208
209 /*************************************
210 *
211 * Generic MCR machine initialization
212 *
213 *************************************/
214
MACHINE_INIT(mcr)215 MACHINE_INIT( mcr )
216 {
217 /* initialize the CTC */
218 ctc_intf.baseclock[0] = Machine->drv->cpu[0].cpu_clock;
219 z80ctc_init(&ctc_intf);
220
221 /* reset cocktail flip */
222 mcr_cocktail_flip = 0;
223
224 /* initialize the sound */
225 mcr_sound_init();
226 }
227
228
229
230 /*************************************
231 *
232 * Generic MCR/68k machine initialization
233 *
234 *************************************/
235
mcr68_common_init(void)236 static void mcr68_common_init(void)
237 {
238 int i;
239
240 /* reset the 6840's */
241 m6840_status = 0x00;
242 m6840_status_read_since_int = 0x00;
243 m6840_msb_buffer = m6840_lsb_buffer = 0;
244 for (i = 0; i < 3; i++)
245 {
246 m6840_state[i].control = 0x00;
247 m6840_state[i].latch = 0xffff;
248 m6840_state[i].count = 0xffff;
249 m6840_state[i].timer = timer_alloc(counter_fired_callback);
250 m6840_state[i].timer_active = 0;
251 m6840_state[i].period = m6840_counter_periods[i];
252 }
253
254 /* initialize the clock */
255 m6840_internal_counter_period = TIME_IN_HZ(Machine->drv->cpu[0].cpu_clock / 10);
256
257 /* reset cocktail flip */
258 mcr_cocktail_flip = 0;
259
260 /* initialize the sound */
261 pia_unconfig();
262 mcr_sound_init();
263 }
264
265
MACHINE_INIT(mcr68)266 MACHINE_INIT( mcr68 )
267 {
268 /* for the most part all MCR/68k games are the same */
269 mcr68_common_init();
270 v493_callback = mcr68_493_callback;
271
272 /* vectors are 1 and 2 */
273 v493_irq_vector = 1;
274 m6840_irq_vector = 2;
275 }
276
277
MACHINE_INIT(zwackery)278 MACHINE_INIT( zwackery )
279 {
280 /* for the most part all MCR/68k games are the same */
281 mcr68_common_init();
282 v493_callback = zwackery_493_callback;
283
284 /* append our PIA state onto the existing one and reinit */
285 pia_config(2, PIA_STANDARD_ORDERING, &zwackery_pia_2_intf);
286 pia_config(3, PIA_STANDARD_ORDERING, &zwackery_pia_3_intf);
287 pia_config(4, PIA_STANDARD_ORDERING, &zwackery_pia_4_intf);
288 pia_reset();
289
290 /* vectors are 5 and 6 */
291 v493_irq_vector = 5;
292 m6840_irq_vector = 6;
293 }
294
295
296
297 /*************************************
298 *
299 * Generic MCR interrupt handler
300 *
301 *************************************/
302
INTERRUPT_GEN(mcr_interrupt)303 INTERRUPT_GEN( mcr_interrupt )
304 {
305 /* CTC line 2 is connected to VBLANK, which is once every 1/2 frame */
306 /* for the 30Hz interlaced display */
307 z80ctc_0_trg2_w(0, 1);
308 z80ctc_0_trg2_w(0, 0);
309
310 /* CTC line 3 is connected to 493, which is signalled once every */
311 /* frame at 30Hz */
312 if (cpu_getiloops() == 0)
313 {
314 z80ctc_0_trg3_w(0, 1);
315 z80ctc_0_trg3_w(0, 0);
316 }
317 }
318
319
INTERRUPT_GEN(mcr68_interrupt)320 INTERRUPT_GEN( mcr68_interrupt )
321 {
322 /* update the 6840 VBLANK clock */
323 if (!m6840_state[0].timer_active)
324 subtract_from_counter(0, 1);
325
326 log_cb(RETRO_LOG_DEBUG, LOGPRE "--- VBLANK ---\n");
327
328 /* also set a timer to generate the 493 signal at a specific time before the next VBLANK */
329 /* the timing of this is crucial for Blasted and Tri-Sports, which check the timing of */
330 /* VBLANK and 493 using counter 2 */
331 timer_set(TIME_IN_HZ(30) - mcr68_timing_factor, 0, v493_callback);
332 }
333
334
335
336 /*************************************
337 *
338 * MCR/68k interrupt central
339 *
340 *************************************/
341
update_mcr68_interrupts(void)342 static void update_mcr68_interrupts(void)
343 {
344 int newstate = 0;
345
346 /* all interrupts go through an LS148, which gives priority to the highest */
347 if (v493_irq_state)
348 newstate = v493_irq_vector;
349 if (m6840_irq_state)
350 newstate = m6840_irq_vector;
351
352 /* set the new state of the IRQ lines */
353 if (newstate)
354 cpu_set_irq_line(0, newstate, ASSERT_LINE);
355 else
356 cpu_set_irq_line(0, 7, CLEAR_LINE);
357 }
358
359
mcr68_493_off_callback(int param)360 static void mcr68_493_off_callback(int param)
361 {
362 v493_irq_state = 0;
363 update_mcr68_interrupts();
364 }
365
366
mcr68_493_callback(int param)367 static void mcr68_493_callback(int param)
368 {
369 v493_irq_state = 1;
370 update_mcr68_interrupts();
371 timer_set(cpu_getscanlineperiod(), 0, mcr68_493_off_callback);
372 log_cb(RETRO_LOG_DEBUG, LOGPRE "--- (INT1) ---\n");
373 }
374
375
376
377 /*************************************
378 *
379 * Generic MCR port write handlers
380 *
381 *************************************/
382
WRITE_HANDLER(mcr_control_port_w)383 WRITE_HANDLER( mcr_control_port_w )
384 {
385 /*
386 Bit layout is as follows:
387 D7 = n/c
388 D6 = cocktail flip
389 D5 = red LED
390 D4 = green LED
391 D3 = n/c
392 D2 = coin meter 3
393 D1 = coin meter 2
394 D0 = coin meter 1
395 */
396
397 coin_counter_w(0, (data >> 0) & 1);
398 coin_counter_w(1, (data >> 1) & 1);
399 coin_counter_w(2, (data >> 2) & 1);
400 mcr_cocktail_flip = (data >> 6) & 1;
401 }
402
403
WRITE_HANDLER(mcrmono_control_port_w)404 WRITE_HANDLER( mcrmono_control_port_w )
405 {
406 /*
407 Bit layout is as follows:
408 D7 = n/c
409 D6 = cocktail flip
410 D5 = n/c
411 D4 = n/c
412 D3 = n/c
413 D2 = n/c
414 D1 = n/c
415 D0 = coin meter 1
416 */
417
418 coin_counter_w(0, (data >> 0) & 1);
419 mcr_cocktail_flip = (data >> 6) & 1;
420 }
421
422
WRITE_HANDLER(mcr_scroll_value_w)423 WRITE_HANDLER( mcr_scroll_value_w )
424 {
425 switch (offset)
426 {
427 case 0:
428 /* low 8 bits of horizontal scroll */
429 spyhunt_scrollx = (spyhunt_scrollx & ~0xff) | data;
430 break;
431
432 case 1:
433 /* upper 3 bits of horizontal scroll and upper 1 bit of vertical scroll */
434 spyhunt_scrollx = (spyhunt_scrollx & 0xff) | ((data & 0x07) << 8);
435 spyhunt_scrolly = (spyhunt_scrolly & 0xff) | ((data & 0x80) << 1);
436 break;
437
438 case 2:
439 /* low 8 bits of vertical scroll */
440 spyhunt_scrolly = (spyhunt_scrolly & ~0xff) | data;
441 break;
442 }
443 }
444
445
446
447 /*************************************
448 *
449 * Zwackery-specific interfaces
450 *
451 *************************************/
452
WRITE_HANDLER(zwackery_pia_2_w)453 WRITE_HANDLER( zwackery_pia_2_w )
454 {
455 /* bit 7 is the watchdog */
456 if (!(data & 0x80)) watchdog_reset_w(offset, data);
457
458 /* bits 5 and 6 control hflip/vflip */
459 /* bits 3 and 4 control coin counters? */
460 /* bits 0, 1 and 2 control meters? */
461 }
462
463
WRITE_HANDLER(zwackery_pia_3_w)464 WRITE_HANDLER( zwackery_pia_3_w )
465 {
466 zwackery_sound_data = (data >> 4) & 0x0f;
467 }
468
469
WRITE_HANDLER(zwackery_ca2_w)470 WRITE_HANDLER( zwackery_ca2_w )
471 {
472 csdeluxe_data_w(offset, (data << 4) | zwackery_sound_data);
473 }
474
475
zwackery_pia_irq(int state)476 void zwackery_pia_irq(int state)
477 {
478 v493_irq_state = state;
479 update_mcr68_interrupts();
480 }
481
482
zwackery_493_off_callback(int param)483 static void zwackery_493_off_callback(int param)
484 {
485 pia_2_ca1_w(0, 0);
486 }
487
488
zwackery_493_callback(int param)489 static void zwackery_493_callback(int param)
490 {
491 pia_2_ca1_w(0, 1);
492 timer_set(cpu_getscanlineperiod(), 0, zwackery_493_off_callback);
493 }
494
495
496
497 /*************************************
498 *
499 * M6840 timer utilities
500 *
501 *************************************/
502
update_interrupts(void)503 static INLINE void update_interrupts(void)
504 {
505 m6840_status &= ~0x80;
506
507 if ((m6840_status & 0x01) && (m6840_state[0].control & 0x40)) m6840_status |= 0x80;
508 if ((m6840_status & 0x02) && (m6840_state[1].control & 0x40)) m6840_status |= 0x80;
509 if ((m6840_status & 0x04) && (m6840_state[2].control & 0x40)) m6840_status |= 0x80;
510
511 m6840_irq_state = m6840_status >> 7;
512 update_mcr68_interrupts();
513 }
514
515
subtract_from_counter(int counter,int count)516 static void subtract_from_counter(int counter, int count)
517 {
518 /* dual-byte mode */
519 if (m6840_state[counter].control & 0x04)
520 {
521 int lsb = m6840_state[counter].count & 0xff;
522 int msb = m6840_state[counter].count >> 8;
523
524 /* count the clocks */
525 lsb -= count;
526
527 /* loop while we're less than zero */
528 while (lsb < 0)
529 {
530 /* borrow from the MSB */
531 lsb += (m6840_state[counter].latch & 0xff) + 1;
532 msb--;
533
534 /* if MSB goes less than zero, we've expired */
535 if (msb < 0)
536 {
537 m6840_status |= 1 << counter;
538 m6840_status_read_since_int &= ~(1 << counter);
539 update_interrupts();
540 msb = (m6840_state[counter].latch >> 8) + 1;
541 log_cb(RETRO_LOG_DEBUG, LOGPRE "** Counter %d fired\n", counter);
542 }
543 }
544
545 /* store the result */
546 m6840_state[counter].count = (msb << 8) | lsb;
547 }
548
549 /* word mode */
550 else
551 {
552 int word = m6840_state[counter].count;
553
554 /* count the clocks */
555 word -= count;
556
557 /* loop while we're less than zero */
558 while (word < 0)
559 {
560 /* borrow from the MSB */
561 word += m6840_state[counter].latch + 1;
562
563 /* we've expired */
564 m6840_status |= 1 << counter;
565 m6840_status_read_since_int &= ~(1 << counter);
566 update_interrupts();
567 log_cb(RETRO_LOG_DEBUG, LOGPRE "** Counter %d fired\n", counter);
568 }
569
570 /* store the result */
571 m6840_state[counter].count = word;
572 }
573 }
574
575
counter_fired_callback(int counter)576 static void counter_fired_callback(int counter)
577 {
578 int count = counter >> 2;
579 counter &= 3;
580
581 /* reset the timer */
582 m6840_state[counter].timer_active = 0;
583
584 /* subtract it all from the counter; this will generate an interrupt */
585 subtract_from_counter(counter, count);
586 }
587
588
reload_count(int counter)589 static void reload_count(int counter)
590 {
591 double period;
592 int count;
593
594 /* copy the latched value in */
595 m6840_state[counter].count = m6840_state[counter].latch;
596
597 /* counter 0 is self-updating if clocked externally */
598 if (counter == 0 && !(m6840_state[counter].control & 0x02))
599 {
600 timer_adjust(m6840_state[counter].timer, TIME_NEVER, 0, 0);
601 m6840_state[counter].timer_active = 0;
602 return;
603 }
604
605 /* determine the clock period for this timer */
606 if (m6840_state[counter].control & 0x02)
607 period = m6840_internal_counter_period;
608 else
609 period = m6840_counter_periods[counter];
610
611 /* determine the number of clock periods before we expire */
612 count = m6840_state[counter].count;
613 if (m6840_state[counter].control & 0x04)
614 count = ((count >> 8) + 1) * ((count & 0xff) + 1);
615 else
616 count = count + 1;
617
618 /* set the timer */
619 timer_adjust(m6840_state[counter].timer, period * (double)count, (count << 2) + counter, 0);
620 m6840_state[counter].timer_active = 1;
621 }
622
623
compute_counter(int counter)624 static UINT16 compute_counter(int counter)
625 {
626 double period;
627 int remaining;
628
629 /* if there's no timer, return the count */
630 if (!m6840_state[counter].timer_active)
631 return m6840_state[counter].count;
632
633 /* determine the clock period for this timer */
634 if (m6840_state[counter].control & 0x02)
635 period = m6840_internal_counter_period;
636 else
637 period = m6840_counter_periods[counter];
638
639 /* see how many are left */
640 remaining = (int)(timer_timeleft(m6840_state[counter].timer) / period);
641
642 /* adjust the count for dual byte mode */
643 if (m6840_state[counter].control & 0x04)
644 {
645 int divisor = (m6840_state[counter].count & 0xff) + 1;
646 int msb = remaining / divisor;
647 int lsb = remaining % divisor;
648 remaining = (msb << 8) | lsb;
649 }
650
651 return remaining;
652 }
653
654
655
656 /*************************************
657 *
658 * M6840 timer I/O
659 *
660 *************************************/
661
WRITE_HANDLER(mcr68_6840_w_common)662 static WRITE_HANDLER( mcr68_6840_w_common )
663 {
664 int i;
665
666 /* offsets 0 and 1 are control registers */
667 if (offset < 2)
668 {
669 int counter = (offset == 1) ? 1 : (m6840_state[1].control & 0x01) ? 0 : 2;
670 UINT8 diffs = data ^ m6840_state[counter].control;
671
672 m6840_state[counter].control = data;
673
674 /* reset? */
675 if (counter == 0 && (diffs & 0x01))
676 {
677 /* holding reset down */
678 if (data & 0x01)
679 {
680 for (i = 0; i < 3; i++)
681 {
682 timer_adjust(m6840_state[i].timer, TIME_NEVER, 0, 0);
683 m6840_state[i].timer_active = 0;
684 }
685 }
686
687 /* releasing reset */
688 else
689 {
690 for (i = 0; i < 3; i++)
691 reload_count(i);
692 }
693
694 m6840_status = 0;
695 update_interrupts();
696 }
697
698 /* changing the clock source? (needed for Zwackery) */
699 if (diffs & 0x02)
700 reload_count(counter);
701
702 log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Counter %d control = %02X\n", activecpu_get_previouspc(), counter, data);
703 }
704
705 /* offsets 2, 4, and 6 are MSB buffer registers */
706 else if ((offset & 1) == 0)
707 {
708 log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:MSB = %02X\n", activecpu_get_previouspc(), data);
709 m6840_msb_buffer = data;
710 }
711
712 /* offsets 3, 5, and 7 are Write Timer Latch commands */
713 else
714 {
715 int counter = (offset - 2) / 2;
716 m6840_state[counter].latch = (m6840_msb_buffer << 8) | (data & 0xff);
717
718 /* clear the interrupt */
719 m6840_status &= ~(1 << counter);
720 update_interrupts();
721
722 /* reload the count if in an appropriate mode */
723 if (!(m6840_state[counter].control & 0x10))
724 reload_count(counter);
725
726 log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Counter %d latch = %04X\n", activecpu_get_previouspc(), counter, m6840_state[counter].latch);
727 }
728 }
729
730
READ16_HANDLER(mcr68_6840_r_common)731 static READ16_HANDLER( mcr68_6840_r_common )
732 {
733 /* offset 0 is a no-op */
734 if (offset == 0)
735 return 0;
736
737 /* offset 1 is the status register */
738 else if (offset == 1)
739 {
740 log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Status read = %04X\n", activecpu_get_previouspc(), m6840_status);
741 m6840_status_read_since_int |= m6840_status & 0x07;
742 return m6840_status;
743 }
744
745 /* offsets 2, 4, and 6 are Read Timer Counter commands */
746 else if ((offset & 1) == 0)
747 {
748 int counter = (offset - 2) / 2;
749 int result = compute_counter(counter);
750
751 /* clear the interrupt if the status has been read */
752 if (m6840_status_read_since_int & (1 << counter))
753 m6840_status &= ~(1 << counter);
754 update_interrupts();
755
756 m6840_lsb_buffer = result & 0xff;
757
758 log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Counter %d read = %04X\n", activecpu_get_previouspc(), counter, result);
759 return result >> 8;
760 }
761
762 /* offsets 3, 5, and 7 are LSB buffer registers */
763 else
764 return m6840_lsb_buffer;
765 }
766
767
WRITE16_HANDLER(mcr68_6840_upper_w)768 WRITE16_HANDLER( mcr68_6840_upper_w )
769 {
770 if (ACCESSING_MSB)
771 mcr68_6840_w_common(offset, (data >> 8) & 0xff);
772 }
773
774
WRITE16_HANDLER(mcr68_6840_lower_w)775 WRITE16_HANDLER( mcr68_6840_lower_w )
776 {
777 if (ACCESSING_LSB)
778 mcr68_6840_w_common(offset, data & 0xff);
779 }
780
781
READ16_HANDLER(mcr68_6840_upper_r)782 READ16_HANDLER( mcr68_6840_upper_r )
783 {
784 return (mcr68_6840_r_common(offset,0) << 8) | 0x00ff;
785 }
786
787
READ16_HANDLER(mcr68_6840_lower_r)788 READ16_HANDLER( mcr68_6840_lower_r )
789 {
790 return mcr68_6840_r_common(offset,0) | 0xff00;
791 }
792