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