1 /***************************************************************************
2 
3 	Atari CAGE Audio Board
4 
5 ****************************************************************************/
6 
7 
8 #define LOG_COMM			(0)
9 #define LOG_WAVE			(0)
10 
11 
12 #include "driver.h"
13 #include "cpu/tms32031/tms32031.h"
14 #include "cage.h"
15 
16 #if (LOG_WAVE)
17 #include "sound/wavwrite.h"
18 #endif
19 
20 
21 
22 /*************************************
23  *
24  *	Constants/macros
25  *
26  *************************************/
27 
28 #define DAC_BUFFER_CHANNELS		4
29 #define DAC_BUFFER_FRAMES		4096
30 #define DAC_BUFFER_SAMPLES		(DAC_BUFFER_FRAMES * DAC_BUFFER_CHANNELS)
31 #define DAC_BUFFER_FRAMES_MASK	(DAC_BUFFER_FRAMES - 1)
32 #define DAC_BUFFER_SAMPLES_MASK	(DAC_BUFFER_SAMPLES - 1)
33 
34 #define ADDR_RANGE(s,e) ((s)*4), ((e)*4+3)
35 
36 
37 
38 /*************************************
39  *
40  *	Statics
41  *
42  *************************************/
43 
44 static int sound_stream;
45 static int cage_cpu;
46 static double cage_cpu_clock_period;
47 static double cage_cpu_h1_clock;
48 
49 static UINT8 cpu_to_cage_ready;
50 static UINT8 cage_to_cpu_ready;
51 
52 static void (*cage_irqhandler)(int);
53 
54 static INT16 *sound_buffer;
55 static UINT32 buffer_in, buffer_out, buffer_out_step;
56 
57 static double serial_time_per_word;
58 
59 static UINT8 dma_enabled;
60 static void *dma_timer;
61 
62 static UINT8 timer_enabled[2];
63 static void *timer[2];
64 
65 static data32_t *tms32031_io_regs;
66 
67 static UINT16 cage_from_main;
68 static UINT16 cage_control;
69 
70 static data32_t *speedup_ram;
71 
72 #if (LOG_WAVE)
73 static void *wavfile;
74 #endif
75 
76 
77 
78 /*************************************
79  *
80  *	I/O port definitions
81  *
82  *************************************/
83 
84 #define DMA_GLOBAL_CTL			0x00
85 #define DMA_SOURCE_ADDR			0x04
86 #define DMA_DEST_ADDR			0x06
87 #define DMA_TRANSFER_COUNT		0x08
88 
89 #define TIMER0_GLOBAL_CTL		0x20
90 #define TIMER0_COUNTER			0x24
91 #define TIMER0_PERIOD			0x28
92 
93 #define TIMER1_GLOBAL_CTL		0x30
94 #define TIMER1_COUNTER			0x34
95 #define TIMER1_PERIOD			0x38
96 
97 #define SPORT_GLOBAL_CTL		0x40
98 #define SPORT_TX_CTL			0x42
99 #define SPORT_RX_CTL			0x43
100 #define SPORT_TIMER_CTL			0x44
101 #define SPORT_TIMER_COUNTER		0x45
102 #define SPORT_TIMER_PERIOD		0x46
103 #define SPORT_DATA_TX			0x48
104 #define SPORT_DATA_RX			0x4c
105 
106 static const char *register_names[] =
107 {
108 	"TMS32031-DMA global control", NULL, NULL, NULL,
109 	"TMS32031-DMA source address", NULL, "TMS32031-DMA destination address", NULL,
110 	"TMS32031-DMA transfer counter", NULL, NULL, NULL,
111 	NULL, NULL, NULL, NULL,
112 
113 	NULL, NULL, NULL, NULL,
114 	NULL, NULL, NULL, NULL,
115 	NULL, NULL, NULL, NULL,
116 	NULL, NULL, NULL, NULL,
117 
118 	"TMS32031-Timer 0 global control", NULL, NULL, NULL,
119 	"TMS32031-Timer 0 counter", NULL, NULL, NULL,
120 	"TMS32031-Timer 0 period", NULL, NULL, NULL,
121 	NULL, NULL, NULL, NULL,
122 
123 	"TMS32031-Timer 1 global control", NULL, NULL, NULL,
124 	"TMS32031-Timer 1 counter", NULL, NULL, NULL,
125 	"TMS32031-Timer 1 period", NULL, NULL, NULL,
126 	NULL, NULL, NULL, NULL,
127 
128 	"TMS32031-Serial port global control", NULL, "TMS32031-Serial port TX control", "TMS32031-Serial port RX control",
129 	"TMS32031-Serial port timer control", "TMS32031-Serial port timer counter", "TMS32031-Serial port timer period", NULL,
130 	"TMS32031-Serial port data TX", NULL, NULL, NULL,
131 	"TMS32031-Serial port data RX", NULL, NULL, NULL,
132 
133 	NULL, NULL, NULL, NULL,
134 	NULL, NULL, NULL, NULL,
135 	NULL, NULL, NULL, NULL,
136 	NULL, NULL, NULL, NULL,
137 
138 	NULL, NULL, NULL, NULL,
139 	"TMS32031-Primary bus control", NULL, NULL, NULL,
140 	NULL, NULL, NULL, NULL,
141 	NULL, NULL, NULL, NULL,
142 
143 	NULL, NULL, NULL, NULL,
144 	NULL, NULL, NULL, NULL,
145 	NULL, NULL, NULL, NULL,
146 	NULL, NULL, NULL, NULL
147 };
148 
149 
150 
151 /*************************************
152  *
153  *	Prototypes
154  *
155  *************************************/
156 
157 static void dma_timer_callback(int param);
158 static void timer_callback(int param);
159 static void update_timer(int which);
160 static WRITE32_HANDLER( speedup_w );
161 
162 
163 
164 /*************************************
165  *
166  *	Initialization
167  *
168  *************************************/
169 
cage_init(int boot_region,offs_t speedup)170 void cage_init(int boot_region, offs_t speedup)
171 {
172 	cage_irqhandler = NULL;
173 
174 	cpu_setbank(10, memory_region(boot_region));
175 	cpu_setbank(11, memory_region(boot_region + 1));
176 
177 	cage_cpu = mame_find_cpu_index("cage");
178 	cage_cpu_clock_period = 1.0 / (double)Machine->drv->cpu[cage_cpu].cpu_clock;
179 	cage_cpu_h1_clock = cage_cpu_clock_period * 2.0;
180 
181 	dma_timer = timer_alloc(dma_timer_callback);
182 	timer[0] = timer_alloc(timer_callback);
183 	timer[1] = timer_alloc(timer_callback);
184 
185 	buffer_in = buffer_out = 0;
186 
187 	if (speedup)
188 		speedup_ram = install_mem_write32_handler(cage_cpu, ADDR_RANGE(speedup, speedup), speedup_w);
189 }
190 
191 
cage_set_irq_handler(void (* irqhandler)(int))192 void cage_set_irq_handler(void (*irqhandler)(int))
193 {
194 	cage_irqhandler = irqhandler;
195 }
196 
197 
cage_reset_w(int state)198 void cage_reset_w(int state)
199 {
200 	if (state)
201 		cage_control_w(0);
202 	cpunum_set_reset_line(cage_cpu, state ? ASSERT_LINE : CLEAR_LINE);
203 }
204 
205 
206 
207 /*************************************
208  *
209  *	DAC update routine
210  *
211  *************************************/
212 
dac_update(int num,INT16 ** buffer,int length)213 static void dac_update(int num, INT16 **buffer, int length)
214 {
215 	INT16 *dest[DAC_BUFFER_CHANNELS];
216 	UINT32 current = buffer_out;
217 	UINT32 step = buffer_out_step;
218 	int i, j;
219 
220 	for (j = 0; j < DAC_BUFFER_CHANNELS; j++)
221 		dest[j] = buffer[j];
222 
223 	/* fill in with samples until we hit the end or run out */
224 	for (i = 0; i < length; i++)
225 	{
226 		UINT32 indx = (current >> 16) * DAC_BUFFER_CHANNELS;
227 		if (indx + DAC_BUFFER_CHANNELS - 1 >= buffer_in)
228 			break;
229 		current += step;
230 		for (j = 0; j < DAC_BUFFER_CHANNELS; j++)
231 			*dest[j]++ = sound_buffer[(indx + j) & DAC_BUFFER_SAMPLES_MASK];
232 	}
233 
234 	/* fill the rest with the last sample */
235 	for ( ; i < length; i++)
236 	{
237 		UINT32 indx = ((buffer_in - 1) / DAC_BUFFER_CHANNELS) * DAC_BUFFER_CHANNELS;
238 		for (j = 0; j < DAC_BUFFER_CHANNELS; j++)
239 			*dest[j]++ = sound_buffer[(indx + j) & DAC_BUFFER_SAMPLES_MASK];
240 	}
241 
242 	/* mask off extra bits */
243 	while (current >= (DAC_BUFFER_FRAMES << 16))
244 	{
245 		current -= DAC_BUFFER_FRAMES << 16;
246 		buffer_in -= DAC_BUFFER_SAMPLES;
247 	}
248 
249 	/* update the final values */
250 	buffer_out = current;
251 
252 #if (LOG_WAVE)
253 #if (DAC_BUFFER_CHANNELS == 4)
254 	wav_add_data_16lr(wavfile, buffer[0], buffer[1], length);
255 #else
256 	wav_add_data_16lr(wavfile, (buffer[0] + buffer[2]) / 2, (buffer[1] + buffer[3]) / 2, length);
257 #endif
258 #endif
259 }
260 
261 
262 
263 /*************************************
264  *
265  *	Custom sound start/stop
266  *
267  *************************************/
268 
custom_start(const struct MachineSound * msound)269 static int custom_start(const struct MachineSound *msound)
270 {
271 #if (DAC_BUFFER_CHANNELS == 4)
272 	const char *names[] = { "Forward R", "Back L", "Forward L", "Back R" };
273 	int mixing_levels[] = { MIXER(50, MIXER_PAN_RIGHT), MIXER(50, MIXER_PAN_LEFT), MIXER(50, MIXER_PAN_LEFT), MIXER(50, MIXER_PAN_RIGHT) };
274 #else
275 	const char *names[] = { "DAC L", "DAC R" };
276 	int mixing_levels[] = { MIXER(100, MIXER_PAN_LEFT), MIXER(100, MIXER_PAN_RIGHT)) };
277 #endif
278 
279 	/* allocate a DAC stream */
280 	sound_stream = stream_init_multi(DAC_BUFFER_CHANNELS, names, mixing_levels, Machine->sample_rate, 0, dac_update);
281 
282 	/* allocate memory for our buffers */
283 	sound_buffer = auto_malloc(DAC_BUFFER_SAMPLES * sizeof(INT16));
284 	if (!sound_buffer)
285 		return 1;
286 
287 #if (LOG_WAVE)
288 	wavfile = wav_open("cage.wav", Machine->sample_rate, 2);
289 #endif
290 
291 	return 0;
292 }
293 
294 
custom_stop(void)295 static void custom_stop(void)
296 {
297 #if (LOG_WAVE)
298 	wav_close(wavfile);
299 #endif
300 }
301 
302 
303 
304 /*************************************
305  *
306  *	DMA timers
307  *
308  *************************************/
309 
dma_timer_callback(int param)310 static void dma_timer_callback(int param)
311 {
312 	/* set the final count to 0 and the source address to the final address */
313 	tms32031_io_regs[DMA_TRANSFER_COUNT] = 0;
314 	tms32031_io_regs[DMA_SOURCE_ADDR] = param;
315 
316 	/* set the interrupt */
317 	cpu_set_irq_line(cage_cpu, TMS32031_DINT, ASSERT_LINE);
318 	dma_enabled = 0;
319 }
320 
321 
update_dma_state(void)322 static void update_dma_state(void)
323 {
324 	/* determine the new enabled state */
325 	int enabled = ((tms32031_io_regs[DMA_GLOBAL_CTL] & 3) == 3) && (tms32031_io_regs[DMA_TRANSFER_COUNT] != 0);
326 
327 	/* see if we turned on */
328 	if (enabled && !dma_enabled)
329 	{
330 		UINT32 addr, inc;
331 		int i;
332 
333 		/* make sure our assumptions are correct */
334 		if (tms32031_io_regs[DMA_DEST_ADDR] != 0x808048)
335 			log_cb(RETRO_LOG_DEBUG, LOGPRE "CAGE DMA: unexpected dest address %08X!\n", tms32031_io_regs[DMA_DEST_ADDR]);
336 		if ((tms32031_io_regs[DMA_GLOBAL_CTL] & 0xfef) != 0xe03)
337 			log_cb(RETRO_LOG_DEBUG, LOGPRE "CAGE DMA: unexpected transfer params %08X!\n", tms32031_io_regs[DMA_GLOBAL_CTL]);
338 
339 		/* do the DMA up front */
340 		addr = tms32031_io_regs[DMA_SOURCE_ADDR];
341 		inc = (tms32031_io_regs[DMA_GLOBAL_CTL] >> 4) & 1;
342 		for (i = 0; i < tms32031_io_regs[DMA_TRANSFER_COUNT]; i++)
343 		{
344 			sound_buffer[(buffer_in + i) & DAC_BUFFER_SAMPLES_MASK] = cpu_readmem26ledw_dword(addr * 4);
345 			addr += inc;
346 		}
347 		buffer_in += tms32031_io_regs[DMA_TRANSFER_COUNT];
348 
349 		/* compute the time of the interrupt and set the timer */
350 		timer_adjust(dma_timer, serial_time_per_word * tms32031_io_regs[DMA_TRANSFER_COUNT], addr, TIME_NEVER);
351 	}
352 
353 	/* see if we turned off */
354 	else if (!enabled && dma_enabled)
355 	{
356 		timer_adjust(dma_timer, TIME_NEVER, 0, TIME_NEVER);
357 	}
358 
359 	/* set the new state */
360 	dma_enabled = enabled;
361 }
362 
363 
364 
365 /*************************************
366  *
367  *	Internal timers
368  *
369  *************************************/
370 
timer_callback(int which)371 static void timer_callback(int which)
372 {
373 	/* set the interrupt */
374 	cpu_set_irq_line(cage_cpu, TMS32031_TINT0 + which, ASSERT_LINE);
375 	timer_enabled[which] = 0;
376 	update_timer(which);
377 }
378 
379 
update_timer(int which)380 static void update_timer(int which)
381 {
382 	/* determine the new enabled state */
383 	int base = 0x10 * which;
384 	int enabled = ((tms32031_io_regs[base + TIMER0_GLOBAL_CTL] & 0xc0) == 0xc0);
385 
386 	/* see if we turned on */
387 	if (enabled && !timer_enabled[which])
388 	{
389 		double period = cage_cpu_h1_clock * 2. * (double)tms32031_io_regs[base + TIMER0_PERIOD];
390 
391 		/* make sure our assumptions are correct */
392 		if (tms32031_io_regs[base + TIMER0_GLOBAL_CTL] != 0x2c1)
393 			log_cb(RETRO_LOG_DEBUG, LOGPRE "CAGE TIMER%d: unexpected timer config %08X!\n", which, tms32031_io_regs[base + TIMER0_GLOBAL_CTL]);
394 
395 		timer_adjust(timer[which], period, which, TIME_NEVER);
396 	}
397 
398 	/* see if we turned off */
399 	else if (!enabled && timer_enabled[which])
400 	{
401 		timer_adjust(timer[which], TIME_NEVER, which, TIME_NEVER);
402 	}
403 
404 	/* set the new state */
405 	timer_enabled[which] = enabled;
406 }
407 
408 
409 
410 /*************************************
411  *
412  *	Serial port I/O
413  *
414  *************************************/
415 
update_serial(void)416 static void update_serial(void)
417 {
418 	double serial_clock, bit_clock;
419 
420 	/* we start out at half the H1 frequency (or 2x the H1 period) */
421 	serial_clock = cage_cpu_h1_clock * 2.0;
422 
423 	/* if we're in clock mode, muliply by another factor of 2 */
424 	if (tms32031_io_regs[SPORT_GLOBAL_CTL] & 4)
425 		serial_clock *= 2.0;
426 
427 	/* now multiply by the timer period */
428 	bit_clock = serial_clock * (double)(tms32031_io_regs[SPORT_TIMER_PERIOD] & 0xffff);
429 
430 	/* and times the number of bits per sample */
431 	serial_time_per_word = bit_clock * 8.0 * (double)(((tms32031_io_regs[SPORT_GLOBAL_CTL] >> 18) & 3) + 1);
432 
433 	/* compute the step value to stretch this to the Machine->sample_rate */
434 	buffer_out_step = (UINT32)(65536.0 / (serial_time_per_word * DAC_BUFFER_CHANNELS * (double)Machine->sample_rate));
435 }
436 
437 
438 
439 /*************************************
440  *
441  *	Master read/write
442  *
443  *************************************/
444 
READ32_HANDLER(tms32031_io_r)445 static READ32_HANDLER( tms32031_io_r )
446 {
447 	UINT16 result = tms32031_io_regs[offset];
448 
449 	switch (offset)
450 	{
451 		case DMA_GLOBAL_CTL:
452 			result = (result & ~0xc) | (dma_enabled ? 0xc : 0x0);
453 			break;
454 	}
455 
456 	log_cb(RETRO_LOG_DEBUG, LOGPRE "CAGE:%06X:%s read -> %08X\n", activecpu_get_pc(), register_names[offset & 0x7f], result);
457 	return result;
458 }
459 
460 
WRITE32_HANDLER(tms32031_io_w)461 static WRITE32_HANDLER( tms32031_io_w )
462 {
463 	COMBINE_DATA(&tms32031_io_regs[offset]);
464 
465 	log_cb(RETRO_LOG_DEBUG, LOGPRE "CAGE:%06X:%s write = %08X\n", activecpu_get_pc(), register_names[offset & 0x7f], tms32031_io_regs[offset]);
466 
467 	switch (offset)
468 	{
469 		case DMA_GLOBAL_CTL:
470 		case DMA_SOURCE_ADDR:
471 		case DMA_DEST_ADDR:
472 		case DMA_TRANSFER_COUNT:
473 			update_dma_state();
474 			break;
475 
476 		case TIMER0_GLOBAL_CTL:
477 		case TIMER0_COUNTER:
478 		case TIMER0_PERIOD:
479 			update_timer(0);
480 			break;
481 
482 		case TIMER1_GLOBAL_CTL:
483 		case TIMER1_COUNTER:
484 		case TIMER1_PERIOD:
485 			update_timer(1);
486 			break;
487 
488 		case SPORT_TX_CTL:
489 		case SPORT_RX_CTL:
490 		case SPORT_TIMER_COUNTER:
491 		case SPORT_DATA_RX:
492 			break;
493 
494 		case SPORT_DATA_TX:
495 #if (DAC_BUFFER_CHANNELS == 4)
496 			if ((int)(1.0 / serial_time_per_word) == 22050*4 && (tms32031_io_regs[SPORT_RX_CTL] & 0xff) == 0x62)
497 				tms32031_io_regs[SPORT_RX_CTL] ^= 0x800;
498 #endif
499 			break;
500 
501 		case SPORT_GLOBAL_CTL:
502 		case SPORT_TIMER_CTL:
503 		case SPORT_TIMER_PERIOD:
504 			update_serial();
505 			break;
506 	}
507 }
508 
509 
510 
511 /*************************************
512  *
513  *	External interfaces
514  *
515  *************************************/
516 
update_control_lines(void)517 static void update_control_lines(void)
518 {
519 	int val;
520 
521 	/* set the IRQ to the main CPU */
522 	if (cage_irqhandler)
523 	{
524 		int reason = 0;
525 
526 		if ((cage_control & 3) == 3 && !cpu_to_cage_ready)
527 			reason |= CAGE_IRQ_REASON_BUFFER_EMPTY;
528 		if ((cage_control & 2) && cage_to_cpu_ready)
529 			reason |= CAGE_IRQ_REASON_DATA_READY;
530 
531 		(*cage_irqhandler)(reason);
532 	}
533 
534 	/* set the IOF input lines */
535 	cpuintrf_push_context(cage_cpu);
536 	val = activecpu_get_reg(TMS32031_IOF);
537 	val &= ~0x88;
538 	if (cpu_to_cage_ready) val |= 0x08;
539 	if (cage_to_cpu_ready) val |= 0x80;
540 	activecpu_set_reg(TMS32031_IOF, val);
541 	cpuintrf_pop_context();
542 }
543 
544 
READ32_HANDLER(cage_from_main_r)545 static READ32_HANDLER( cage_from_main_r )
546 {
547 	log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:CAGE read command = %04X\n", activecpu_get_pc(), cage_from_main);
548 	cpu_to_cage_ready = 0;
549 	update_control_lines();
550 	return cage_from_main;
551 }
552 
553 
WRITE32_HANDLER(cage_from_main_ack_w)554 static WRITE32_HANDLER( cage_from_main_ack_w )
555 {
556 	log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:CAGE ack command = %04X\n", activecpu_get_pc(), cage_from_main);
557 }
558 
559 
WRITE32_HANDLER(cage_to_main_w)560 static WRITE32_HANDLER( cage_to_main_w )
561 {
562 	log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Data from CAGE = %04X\n", activecpu_get_pc(), data);
563 	soundlatch_word_w(0, data, mem_mask);
564 	cage_to_cpu_ready = 1;
565 	update_control_lines();
566 }
567 
568 
READ32_HANDLER(cage_io_status_r)569 static READ32_HANDLER( cage_io_status_r )
570 {
571 	int result = 0;
572 	if (cpu_to_cage_ready)
573 		result |= 0x80;
574 	if (!cage_to_cpu_ready)
575 		result |= 0x40;
576 	return result;
577 }
578 
579 
main_from_cage_r(void)580 UINT16 main_from_cage_r(void)
581 {
582 	log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:main read data = %04X\n", activecpu_get_pc(), soundlatch_word_r(0, 0));
583 	cage_to_cpu_ready = 0;
584 	update_control_lines();
585 	return soundlatch_word_r(0, 0);
586 }
587 
588 
deferred_cage_w(int param)589 static void deferred_cage_w(int param)
590 {
591 	cage_from_main = param;
592 	cpu_to_cage_ready = 1;
593 	update_control_lines();
594 	cpu_set_irq_line(cage_cpu, TMS32031_IRQ0, ASSERT_LINE);
595 }
596 
597 
main_to_cage_w(UINT16 data)598 void main_to_cage_w(UINT16 data)
599 {
600 	log_cb(RETRO_LOG_DEBUG, LOGPRE "%06X:Command to CAGE = %04X\n", activecpu_get_pc(), data);
601 	timer_set(TIME_NOW, data, deferred_cage_w);
602 }
603 
604 
cage_control_r(void)605 UINT16 cage_control_r(void)
606 {
607 	UINT16 result = 0;
608 
609 	if (cpu_to_cage_ready)
610 		result |= 2;
611 	if (cage_to_cpu_ready)
612 		result |= 1;
613 
614 	return result;
615 }
616 
617 
cage_control_w(UINT16 data)618 void cage_control_w(UINT16 data)
619 {
620 	cage_control = data;
621 
622 	/* CPU is reset if both control lines are 0 */
623 	if (!(cage_control & 3))
624 	{
625 		cpu_set_reset_line(cage_cpu, ASSERT_LINE);
626 
627 		dma_enabled = 0;
628 		timer_adjust(dma_timer, TIME_NEVER, 0, TIME_NEVER);
629 
630 		timer_enabled[0] = 0;
631 		timer_enabled[1] = 0;
632 		timer_adjust(timer[0], TIME_NEVER, 0, TIME_NEVER);
633 		timer_adjust(timer[1], TIME_NEVER, 0, TIME_NEVER);
634 
635 		memset(tms32031_io_regs, 0, 0x60 * 4);
636 
637 		cpu_to_cage_ready = 0;
638 		cage_to_cpu_ready = 0;
639 	}
640 	else
641 		cpu_set_reset_line(cage_cpu, CLEAR_LINE);
642 
643 	/* update the control state */
644 	update_control_lines();
645 }
646 
647 
648 
649 /*************************************
650  *
651  *	Speedups
652  *
653  *************************************/
654 
WRITE32_HANDLER(speedup_w)655 static WRITE32_HANDLER( speedup_w )
656 {
657 	activecpu_eat_cycles(100);
658 	COMBINE_DATA(&speedup_ram[offset]);
659 }
660 
661 
662 
663 /*************************************
664  *
665  *	CPU memory map & config
666  *
667  *************************************/
668 
669 static struct tms32031_config cage_config =
670 {
671 	0x400000
672 };
673 
674 
MEMORY_READ32_START(readmem_cage)675 static MEMORY_READ32_START( readmem_cage )
676 	{ ADDR_RANGE(0x000000, 0x00ffff), MRA32_RAM },
677 	{ ADDR_RANGE(0x400000, 0x47ffff), MRA32_BANK10 },
678 	{ ADDR_RANGE(0x808000, 0x8080ff), tms32031_io_r },
679 	{ ADDR_RANGE(0x809800, 0x809fff), MRA32_RAM },
680 	{ ADDR_RANGE(0xa00000, 0xa00000), cage_from_main_r },
681 	{ ADDR_RANGE(0xc00000, 0xffffff), MRA32_BANK11 },
682 MEMORY_END
683 
684 
685 static MEMORY_WRITE32_START( writemem_cage )
686 	{ ADDR_RANGE(0x000000, 0x00ffff), MWA32_RAM },
687 	{ ADDR_RANGE(0x200000, 0x200000), MWA32_NOP },
688 	{ ADDR_RANGE(0x400000, 0x47ffff), MWA32_ROM },
689 	{ ADDR_RANGE(0x808000, 0x8080ff), tms32031_io_w, &tms32031_io_regs },
690 	{ ADDR_RANGE(0x809800, 0x809fff), MWA32_RAM },
691 	{ ADDR_RANGE(0xa00000, 0xa00000), cage_to_main_w },
692 	{ ADDR_RANGE(0xc00000, 0xffffff), MWA32_ROM },
693 MEMORY_END
694 
695 
696 static MEMORY_READ32_START( readmem_cage_seattle )
697 	{ ADDR_RANGE(0x000000, 0x00ffff), MRA32_RAM },
698 	{ ADDR_RANGE(0x400000, 0x47ffff), MRA32_BANK10 },
699 	{ ADDR_RANGE(0x808000, 0x8080ff), tms32031_io_r },
700 	{ ADDR_RANGE(0x809800, 0x809fff), MRA32_RAM },
701 	{ ADDR_RANGE(0xa00000, 0xa00000), cage_from_main_r },
702 	{ ADDR_RANGE(0xa00003, 0xa00003), cage_io_status_r },
703 	{ ADDR_RANGE(0xc00000, 0xffffff), MRA32_BANK11 },
704 MEMORY_END
705 
706 
707 static MEMORY_WRITE32_START( writemem_cage_seattle )
708 	{ ADDR_RANGE(0x000000, 0x00ffff), MWA32_RAM },
709 	{ ADDR_RANGE(0x200000, 0x200000), MWA32_NOP },
710 	{ ADDR_RANGE(0x400000, 0x47ffff), MWA32_ROM },
711 	{ ADDR_RANGE(0x808000, 0x8080ff), tms32031_io_w, &tms32031_io_regs },
712 	{ ADDR_RANGE(0x809800, 0x809fff), MWA32_RAM },
713 	{ ADDR_RANGE(0xa00000, 0xa00000), cage_from_main_ack_w },
714 	{ ADDR_RANGE(0xa00001, 0xa00001), cage_to_main_w },
715 	{ ADDR_RANGE(0xc00000, 0xffffff), MWA32_ROM },
716 MEMORY_END
717 
718 
719 
720 /*************************************
721  *
722  *	CAGE machine driver
723  *
724  *************************************/
725 
726 /* Custom structure */
727 struct CustomSound_interface cage_custom_interface =
728 {
729 	custom_start,custom_stop,0
730 };
731 
732 
733 MACHINE_DRIVER_START( cage )
734 
735 	/* basic machine hardware */
736 	MDRV_CPU_ADD_TAG("cage", TMS32031, 33868800)
737 	MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
738 	MDRV_CPU_CONFIG(cage_config)
739 	MDRV_CPU_MEMORY(readmem_cage,writemem_cage)
740 
741 	/* sound hardware */
742 	MDRV_SOUND_ATTRIBUTES(SOUND_SUPPORTS_STEREO)
743 	MDRV_SOUND_ADD(CUSTOM, cage_custom_interface)
744 MACHINE_DRIVER_END
745 
746 
747 MACHINE_DRIVER_START( cage_seattle )
748 	MDRV_IMPORT_FROM(cage)
749 
750 	MDRV_CPU_MODIFY("cage")
751 	MDRV_CPU_MEMORY(readmem_cage_seattle,writemem_cage_seattle)
752 MACHINE_DRIVER_END
753