1 /***************************************************************************
2 
3 	Emulation of various Midway ICs
4 
5 ***************************************************************************/
6 
7 #include "driver.h"
8 #include "midwayic.h"
9 #include "machine/idectrl.h"
10 #include "sndhrdw/cage.h"
11 #include "sndhrdw/dcs.h"
12 #include <time.h>
13 
14 
15 #define LOG_NVRAM			(0)
16 
17 #define PRINTF_DEBUG		(0)
18 #define LOG_IOASIC			(0)
19 #define LOG_FIFO			(0)
20 
21 
22 /*************************************
23  *
24  *	Constants
25  *
26  *************************************/
27 
28 #define PIC_NVRAM_SIZE		0x100
29 #define FIFO_SIZE			512
30 
31 
32 
33 /*************************************
34  *
35  *	Type definitions
36  *
37  *************************************/
38 
39 struct serial_state
40 {
41 	UINT8	data[16];
42 	UINT8	buffer;
43 	UINT8	index;
44 	UINT8	status;
45 	UINT8	bits;
46 	UINT8	ormask;
47 };
48 
49 struct pic_state
50 {
51 	UINT16	latch;
52 	UINT8	state;
53 	UINT8	index;
54 	UINT8	total;
55 	UINT8	nvram_addr;
56 	UINT8	buffer[0x10];
57 	UINT8	nvram[PIC_NVRAM_SIZE];
58 	UINT8 	default_nvram[PIC_NVRAM_SIZE];
59 	UINT16	yearoffs;
60 };
61 
62 struct ioasic_state
63 {
64 	UINT32	reg[16];
65 	UINT8	has_dcs;
66 	UINT8	has_cage;
67 	UINT8	dcs_cpu;
68 	UINT8	shuffle_type;
69 	UINT8	shuffle_active;
70 	UINT8 *	shuffle_map;
71 	void 	(*irq_callback)(int);
72 	UINT8	irq_state;
73 	UINT16	sound_irq_state;
74 	UINT8	auto_ack;
75 
76 	UINT16	fifo[FIFO_SIZE];
77 	UINT16	fifo_in;
78 	UINT16	fifo_out;
79 	UINT16	fifo_bytes;
80 	offs_t	fifo_force_buffer_empty_pc;
81 };
82 
83 
84 
85 /*************************************
86  *
87  *	Local variables
88  *
89  *************************************/
90 
91 static struct serial_state serial;
92 static struct pic_state pic;
93 static struct ioasic_state ioasic;
94 
95 
96 
97 
98 /*************************************
99  *
100  *	Serial number encoding
101  *
102  *************************************/
103 
generate_serial_data(int upper)104 static void generate_serial_data(int upper)
105 {
106 	int year = atoi(Machine->gamedrv->year), month = 12, day = 11;
107 	UINT32 serial_number, temp;
108 	UINT8 serial_digit[9];
109 
110 	serial_number = 123456;
111 	serial_number += upper * 1000000;
112 
113 	serial_digit[0] = (serial_number / 100000000) % 10;
114 	serial_digit[1] = (serial_number / 10000000) % 10;
115 	serial_digit[2] = (serial_number / 1000000) % 10;
116 	serial_digit[3] = (serial_number / 100000) % 10;
117 	serial_digit[4] = (serial_number / 10000) % 10;
118 	serial_digit[5] = (serial_number / 1000) % 10;
119 	serial_digit[6] = (serial_number / 100) % 10;
120 	serial_digit[7] = (serial_number / 10) % 10;
121 	serial_digit[8] = (serial_number / 1) % 10;
122 
123 	serial.data[12] = rand() & 0xff;
124 	serial.data[13] = rand() & 0xff;
125 
126 	serial.data[14] = 0; /* ??? */
127 	serial.data[15] = 0; /* ??? */
128 
129 	temp = 0x174 * (year - 1980) + 0x1f * (month - 1) + day;
130 	serial.data[10] = (temp >> 8) & 0xff;
131 	serial.data[11] = temp & 0xff;
132 
133 	temp = serial_digit[4] + serial_digit[7] * 10 + serial_digit[1] * 100;
134 	temp = (temp + 5 * serial.data[13]) * 0x1bcd + 0x1f3f0;
135 	serial.data[7] = temp & 0xff;
136 	serial.data[8] = (temp >> 8) & 0xff;
137 	serial.data[9] = (temp >> 16) & 0xff;
138 
139 	temp = serial_digit[6] + serial_digit[8] * 10 + serial_digit[0] * 100 + serial_digit[2] * 10000;
140 	temp = (temp + 2 * serial.data[13] + serial.data[12]) * 0x107f + 0x71e259;
141 	serial.data[3] = temp & 0xff;
142 	serial.data[4] = (temp >> 8) & 0xff;
143 	serial.data[5] = (temp >> 16) & 0xff;
144 	serial.data[6] = (temp >> 24) & 0xff;
145 
146 	temp = serial_digit[5] * 10 + serial_digit[3] * 100;
147 	temp = (temp + serial.data[12]) * 0x245 + 0x3d74;
148 	serial.data[0] = temp & 0xff;
149 	serial.data[1] = (temp >> 8) & 0xff;
150 	serial.data[2] = (temp >> 16) & 0xff;
151 
152 	/* special hack for RevX */
153 	serial.ormask = 0x80;
154 	if (upper == 419)
155 		serial.ormask = 0x00;
156 }
157 
158 
159 
160 /*************************************
161  *
162  *	Original serial number PIC
163  *	interface
164  *
165  *************************************/
166 
midway_serial_pic_init(int upper)167 void midway_serial_pic_init(int upper)
168 {
169 	generate_serial_data(upper);
170 }
171 
172 
midway_serial_pic_reset_w(int state)173 void midway_serial_pic_reset_w(int state)
174 {
175 	if (state)
176 	{
177 		serial.index = 0;
178 		serial.status = 0;
179 		serial.buffer = 0;
180 	}
181 }
182 
183 
midway_serial_pic_status_r(void)184 UINT8 midway_serial_pic_status_r(void)
185 {
186 	return serial.status;
187 }
188 
189 
midway_serial_pic_r(void)190 UINT8 midway_serial_pic_r(void)
191 {
192 	logerror("%08X:security R = %04X\n", activecpu_get_pc(), serial.buffer);
193 	serial.status = 1;
194 	return serial.buffer;
195 }
196 
197 
midway_serial_pic_w(UINT8 data)198 void midway_serial_pic_w(UINT8 data)
199 {
200 	logerror("%08X:security W = %04X\n", activecpu_get_pc(), data);
201 
202 	/* status seems to reflect the clock bit */
203 	serial.status = (data >> 4) & 1;
204 
205 	/* on the falling edge, clock the next data byte through */
206 	if (!serial.status)
207 	{
208 		/* the self-test writes 1F, 0F, and expects to read an F in the low 4 bits */
209 		/* Cruis'n World expects the high bit to be set as well */
210 		if (data & 0x0f)
211 			serial.buffer = serial.ormask | data;
212 		else
213 			serial.buffer = serial.data[serial.index++ % sizeof(serial.data)];
214 	}
215 }
216 
217 
218 
219 /*************************************
220  *
221  *	Second generation serial number
222  *	PIC interface; this version also
223  *	contained some NVRAM and a real
224  *	time clock
225  *
226  *************************************/
227 
make_bcd(UINT8 data)228 static INLINE UINT8 make_bcd(UINT8 data)
229 {
230 	return ((data / 10) << 4) | (data % 10);
231 }
232 
233 
midway_serial_pic2_init(int upper,int yearoffs)234 void midway_serial_pic2_init(int upper, int yearoffs)
235 {
236 	pic.yearoffs = yearoffs;
237 	memset(pic.default_nvram, 0xff, sizeof(pic.default_nvram));
238 	generate_serial_data(upper);
239 }
240 
241 
midway_serial_pic2_set_default_nvram(const UINT8 * nvram)242 void midway_serial_pic2_set_default_nvram(const UINT8 *nvram)
243 {
244 	memcpy(pic.default_nvram, nvram, sizeof(pic.default_nvram));
245 }
246 
247 
midway_serial_pic2_status_r(void)248 UINT8 midway_serial_pic2_status_r(void)
249 {
250 	UINT8 result = 0;
251 
252 	/* if we're still holding the data ready bit high, do it */
253 	if (pic.latch & 0xf00)
254 	{
255 		pic.latch -= 0x100;
256 		result = 1;
257 	}
258 
259 	logerror("%06X:PIC status %d\n", activecpu_get_pc(), result);
260 	return result;
261 }
262 
263 
midway_serial_pic2_r(void)264 UINT8 midway_serial_pic2_r(void)
265 {
266 	UINT8 result = 0;
267 
268 	/* PIC data register */
269 	logerror("%06X:PIC data read (index=%d total=%d latch=%03X) =", activecpu_get_pc(), pic.index, pic.total, pic.latch);
270 
271 	/* return the current result */
272 	if (pic.latch & 0xf00)
273 		result = pic.latch & 0xff;
274 
275 	/* otherwise, return 0xff if we have data ready */
276 	else if (pic.index < pic.total)
277 		result = 0xff;
278 
279 	logerror("%02X\n", result);
280 	return result;
281 }
282 
283 
midway_serial_pic2_w(UINT8 data)284 void midway_serial_pic2_w(UINT8 data)
285 {
286 	static FILE *nvramlog;
287 	if (LOG_NVRAM && !nvramlog)
288 		nvramlog = fopen("nvram.log", "w");
289 
290 	/* PIC command register */
291 	if (pic.state == 0)
292 		logerror("%06X:PIC command %02X\n", activecpu_get_pc(), data);
293 	else
294 		logerror("%06X:PIC data %02X\n", activecpu_get_pc(), data);
295 
296 	/* store in the latch, along with a bit to indicate we have data */
297 	pic.latch = (data & 0x00f) | 0x480;
298 	if (data & 0x10)
299 	{
300 		int cmd = pic.state ? (pic.state & 0x0f) : (pic.latch & 0x0f);
301 		switch (cmd)
302 		{
303 			/* written to latch the next byte of data */
304 			case 0:
305 				if (pic.index < pic.total)
306 					pic.latch = 0x400 | pic.buffer[pic.index++];
307 				break;
308 
309 			/* fetch the serial number */
310 			case 1:
311 				/* note: Biofreaks assumes that it can latch the next byte this way */
312 				if (pic.index < pic.total)
313 					pic.latch = 0x400 | pic.buffer[pic.index++];
314 				else
315 				{
316 					memcpy(pic.buffer, serial.data, 16);
317 					pic.total = 16;
318 					pic.index = 0;
319 #ifdef MAME_DEBUG
320 {
321 	extern int debug_key_pressed;
322 	debug_key_pressed = 1;
323 }
324 #endif
325 				}
326 				break;
327 
328 			/* read the clock */
329 			case 3:
330 			{
331 				/* get the time */
332 				struct tm *exptime;
333 				time_t curtime;
334 				time(&curtime);
335 				exptime = localtime(&curtime);
336 
337 				/* stuff it into the data bytes */
338 				pic.index = 0;
339 				pic.total = 0;
340 				pic.buffer[pic.total++] = make_bcd(exptime->tm_sec);
341 				pic.buffer[pic.total++] = make_bcd(exptime->tm_min);
342 				pic.buffer[pic.total++] = make_bcd(exptime->tm_hour);
343 				pic.buffer[pic.total++] = make_bcd(exptime->tm_wday + 1);
344 				pic.buffer[pic.total++] = make_bcd(exptime->tm_mday);
345 				pic.buffer[pic.total++] = make_bcd(exptime->tm_mon + 1);
346 				pic.buffer[pic.total++] = make_bcd(exptime->tm_year - pic.yearoffs);
347 				break;
348 			}
349 
350 			/* write to NVRAM */
351 			case 5:
352 
353 				/* if coming from state 0, go to state 1 (this is just the command byte) */
354 				if (pic.state == 0)
355 					pic.state = 0x15;
356 
357 				/* coming from state 1, go to state 2 and latch the low 4 address bits */
358 				else if (pic.state == 0x15)
359 				{
360 					pic.nvram_addr = pic.latch & 0x0f;
361 					pic.state = 0x25;
362 				}
363 
364 				/* coming from state 2, go to state 3 and latch the high 4 address bits */
365 				else if (pic.state == 0x25)
366 				{
367 					pic.state = 0x35;
368 					pic.nvram_addr |= pic.latch << 4;
369 				}
370 
371 				/* coming from state 3, go to state 4 and write the low 4 bits */
372 				else if (pic.state == 0x35)
373 				{
374 					pic.state = 0x45;
375 					pic.nvram[pic.nvram_addr] = pic.latch & 0x0f;
376 				}
377 
378 				/* coming from state 4, reset the states and write the upper 4 bits */
379 				else if (pic.state == 0x45)
380 				{
381 					pic.state = 0;
382 					pic.nvram[pic.nvram_addr] |= pic.latch << 4;
383 					if (nvramlog)
384 						fprintf(nvramlog, "Write byte %02X = %02X\n", pic.nvram_addr, pic.nvram[pic.nvram_addr]);
385 				}
386 				break;
387 
388 			/* read from NVRAM */
389 			case 6:
390 
391 				/* if coming from state 0, go to state 1 (this is just the command byte) */
392 				if (pic.state == 0)
393 					pic.state = 0x16;
394 
395 				/* coming from state 1, go to state 2 and latch the low 4 address bits */
396 				else if (pic.state == 0x16)
397 				{
398 					pic.nvram_addr = pic.latch & 0x0f;
399 					pic.state = 0x26;
400 				}
401 
402 				/* coming from state 2, reset the states and make the data available */
403 				else if (pic.state == 0x26)
404 				{
405 					pic.state = 0;
406 					pic.nvram_addr |= pic.latch << 4;
407 
408 					pic.total = 0;
409 					pic.index = 0;
410 					pic.buffer[pic.total++] = pic.nvram[pic.nvram_addr];
411 					if (nvramlog)
412 						fprintf(nvramlog, "Read byte %02X = %02X\n", pic.nvram_addr, pic.nvram[pic.nvram_addr]);
413 				}
414 				break;
415 		}
416 	}
417 }
418 
419 
NVRAM_HANDLER(midway_serial_pic2)420 NVRAM_HANDLER( midway_serial_pic2 )
421 {
422 	if (read_or_write)
423 		mame_fwrite(file, pic.nvram, sizeof(pic.nvram));
424 	else if (file)
425 		mame_fread(file, pic.nvram, sizeof(pic.nvram));
426 	else
427 		memcpy(pic.nvram, pic.default_nvram, sizeof(pic.nvram));
428 }
429 
430 
431 
432 /*************************************
433  *
434  *	The I/O ASIC was first introduced
435  *	in War Gods, then later used on
436  *	the Seattle hardware
437  *
438  *************************************/
439 
440 enum
441 {
442 	IOASIC_PORT0,		/* 0: input port 0 */
443 	IOASIC_PORT1,		/* 1: input port 1 */
444 	IOASIC_PORT2,		/* 2: input port 2 */
445 	IOASIC_PORT3,		/* 3: input port 3 */
446 	IOASIC_UNKNOWN4,	/* 4: ??? */
447 	IOASIC_DEBUGOUT,	/* 5: debugger output (UART likely) */
448 	IOASIC_UNKNOWN6,	/* 6: ??? */
449 	IOASIC_UNKNOWN7,	/* 7: ??? */
450 	IOASIC_SOUNDCTL,	/* 8: sound communications control */
451 	IOASIC_SOUNDOUT,	/* 9: sound output port */
452 	IOASIC_SOUNDSTAT,	/* a: sound status port */
453 	IOASIC_SOUNDIN,		/* b: sound input port */
454 	IOASIC_PICOUT,		/* c: PIC output port */
455 	IOASIC_PICIN,		/* d: PIC input port */
456 	IOASIC_INTSTAT,		/* e: interrupt status */
457 	IOASIC_INTCTL		/* f: interrupt control */
458 };
459 
460 
461 static UINT16 ioasic_fifo_r(void);
462 static UINT16 ioasic_fifo_status_r(void);
463 static void ioasic_fifo_reset_w(int state);
464 static void ioasic_input_empty(int state);
465 static void ioasic_output_full(int state);
466 static void update_ioasic_irq(void);
467 static void cage_irq_handler(int state);
468 
midway_ioasic_init(int shuffle,int upper,int yearoffs,void (* irq_callback)(int))469 void midway_ioasic_init(int shuffle, int upper, int yearoffs, void (*irq_callback)(int))
470 {
471 	static UINT8 shuffle_maps[][16] =
472 	{
473 		{ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf },	/* WarGods, WG3DH, SFRush, MK4 */
474 		{ 0x4,0x5,0x6,0x7,0xb,0xa,0x9,0x8,0x3,0x2,0x1,0x0,0xf,0xe,0xd,0xc },	/* Blitz, Blitz99 */
475 		{ 0x7,0x3,0x2,0x0,0x1,0xc,0xd,0xe,0xf,0x4,0x5,0x6,0x8,0x9,0xa,0xb },	/* Carnevil */
476 		{ 0x8,0x9,0xa,0xb,0x0,0x1,0x2,0x3,0xf,0xe,0xc,0xd,0x4,0x5,0x6,0x7 },	/* Calspeed, Gauntlet Legends */
477 		{ 0xf,0xe,0xd,0xc,0x4,0x5,0x6,0x7,0x9,0x8,0xa,0xb,0x2,0x3,0x1,0x0 },	/* Mace */
478 		{ 0xc,0xd,0xe,0xf,0x0,0x1,0x2,0x3,0x7,0x8,0x9,0xb,0xa,0x5,0x6,0x4 },	/* Gauntlet Dark Legacy */
479 		{ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf },	/* Invasion */
480 	};
481 
482 	/* do we have a DCS2 sound chip connected? (most likely) */
483 	ioasic.has_dcs = (mame_find_cpu_index("dcs2") != -1);
484 	ioasic.has_cage = (mame_find_cpu_index("cage") != -1);
485 	ioasic.dcs_cpu = mame_find_cpu_index("dcs2");
486 	ioasic.shuffle_type = shuffle;
487 	ioasic.shuffle_map = &shuffle_maps[shuffle][0];
488 	ioasic.auto_ack = 0;
489 	ioasic.irq_callback = irq_callback;
490 
491 	/* initialize the PIC */
492 	midway_serial_pic2_init(upper, yearoffs);
493 
494 	/* reset the chip */
495 	midway_ioasic_reset();
496 
497 	/* configure the fifo */
498 	if (ioasic.has_dcs)
499 	{
500 		dcs_set_fifo_callbacks(ioasic_fifo_r, ioasic_fifo_status_r);
501 		dcs_set_io_callbacks(ioasic_output_full, ioasic_input_empty);
502 	}
503 	ioasic_fifo_reset_w(1);
504 
505 	/* configure the CAGE IRQ */
506 	if (ioasic.has_cage)
507 		cage_set_irq_handler(cage_irq_handler);
508 }
509 
510 
midway_ioasic_set_auto_ack(int auto_ack)511 void midway_ioasic_set_auto_ack(int auto_ack)
512 {
513 	ioasic.auto_ack = auto_ack;
514 }
515 
516 
midway_ioasic_reset(void)517 void midway_ioasic_reset(void)
518 {
519 	ioasic.shuffle_active = 0;
520 	ioasic.sound_irq_state = 0x0080;
521 	ioasic.reg[IOASIC_INTCTL] = 0;
522 	if (ioasic.has_dcs)
523 		ioasic_fifo_reset_w(1);
524 	update_ioasic_irq();
525 }
526 
527 
update_ioasic_irq(void)528 static void update_ioasic_irq(void)
529 {
530 	UINT16 fifo_state = ioasic_fifo_status_r();
531 	UINT16 irqbits = 0x2000;
532 	UINT8 new_state;
533 
534 	irqbits |= ioasic.sound_irq_state;
535 	if (fifo_state & 8)
536 		irqbits |= 0x0008;
537 	if (irqbits)
538 		irqbits |= 0x0001;
539 
540 	ioasic.reg[IOASIC_INTSTAT] = irqbits;
541 
542 	new_state = ((ioasic.reg[IOASIC_INTCTL] & 0x0001) != 0) && ((ioasic.reg[IOASIC_INTSTAT] & ioasic.reg[IOASIC_INTCTL] & 0x3ffe) != 0);
543 	if (new_state != ioasic.irq_state)
544 	{
545 		ioasic.irq_state = new_state;
546 		if (ioasic.irq_callback)
547 			(*ioasic.irq_callback)(ioasic.irq_state ? ASSERT_LINE : CLEAR_LINE);
548 	}
549 }
550 
551 
cage_irq_handler(int reason)552 static void cage_irq_handler(int reason)
553 {
554 	logerror("CAGE irq handler: %d\n", reason);
555 	ioasic.sound_irq_state = 0;
556 	if (reason & CAGE_IRQ_REASON_DATA_READY)
557 		ioasic.sound_irq_state |= 0x0040;
558 	if (reason & CAGE_IRQ_REASON_BUFFER_EMPTY)
559 		ioasic.sound_irq_state |= 0x0080;
560 	update_ioasic_irq();
561 }
562 
563 
ioasic_input_empty(int state)564 static void ioasic_input_empty(int state)
565 {
566 	logerror("ioasic_input_empty(%d)\n", state);
567 	if (state)
568 		ioasic.sound_irq_state |= 0x0080;
569 	else
570 		ioasic.sound_irq_state &= ~0x0080;
571 	update_ioasic_irq();
572 }
573 
574 
ioasic_output_full(int state)575 static void ioasic_output_full(int state)
576 {
577 	logerror("ioasic_output_full(%d)\n", state);
578 	if (state)
579 		ioasic.sound_irq_state |= 0x0040;
580 	else
581 		ioasic.sound_irq_state &= ~0x0040;
582 	update_ioasic_irq();
583 }
584 
585 
586 
587 /*************************************
588  *
589  *	ASIC sound FIFO; used by CarnEvil
590  *
591  *************************************/
592 
ioasic_fifo_r(void)593 static UINT16 ioasic_fifo_r(void)
594 {
595 	UINT16 result = 0;
596 
597 	/* we can only read data if there's some to read! */
598 	if (ioasic.fifo_bytes != 0)
599 	{
600 		/* fetch the data from the buffer and update the IOASIC state */
601 		result = ioasic.fifo[ioasic.fifo_out++ % FIFO_SIZE];
602 		ioasic.fifo_bytes--;
603 		update_ioasic_irq();
604 
605 		if (LOG_FIFO && (ioasic.fifo_bytes < 4 || ioasic.fifo_bytes >= FIFO_SIZE - 4))
606 			logerror("fifo_r(%04X): FIFO bytes = %d!\n", result, ioasic.fifo_bytes);
607 
608 		/* if we just cleared the buffer, this may generate an IRQ on the master CPU */
609 		/* because of the way the streaming code works, we need to make sure that the */
610 		/* next status read indicates an empty buffer, even if we've timesliced and the */
611 		/* main CPU is handling the I/O ASIC interrupt */
612 		if (ioasic.fifo_bytes == 0 && ioasic.has_dcs)
613 		{
614 			ioasic.fifo_force_buffer_empty_pc = activecpu_get_pc();
615 			if (LOG_FIFO)
616 				logerror("fifo_r(%04X): FIFO empty, PC = %04X\n", result, ioasic.fifo_force_buffer_empty_pc);
617 		}
618 	}
619 	else
620 	{
621 		if (LOG_FIFO)
622 			logerror("fifo_r(): nothing to read!\n");
623 	}
624 	return result;
625 }
626 
627 
ioasic_fifo_status_r(void)628 static UINT16 ioasic_fifo_status_r(void)
629 {
630 	UINT16 result = 0;
631 
632 	if (ioasic.fifo_bytes == 0)
633 		result |= 0x08;
634 	if (ioasic.fifo_bytes >= FIFO_SIZE/2)
635 		result |= 0x10;
636 	if (ioasic.fifo_bytes >= FIFO_SIZE)
637 		result |= 0x20;
638 
639 	/* kludge alert: if we're reading this from the DCS CPU itself, and we recently cleared */
640 	/* the FIFO, and we're within 16 instructions of the read that cleared the FIFO, make */
641 	/* sure the FIFO clear bit is set */
642 	if (ioasic.fifo_force_buffer_empty_pc && cpu_getactivecpu() == ioasic.dcs_cpu)
643 	{
644 		offs_t currpc = activecpu_get_pc();
645 		if (currpc >= ioasic.fifo_force_buffer_empty_pc && currpc < ioasic.fifo_force_buffer_empty_pc + 0x10)
646 		{
647 			ioasic.fifo_force_buffer_empty_pc = 0;
648 			result |= 0x08;
649 			if (LOG_FIFO)
650 				logerror("ioasic_fifo_status_r(%04X): force empty, PC = %04X\n", result, currpc);
651 		}
652 	}
653 
654 	return result;
655 }
656 
657 
ioasic_fifo_reset_w(int state)658 static void ioasic_fifo_reset_w(int state)
659 {
660 	/* on the high state, reset the FIFO data */
661 	if (state)
662 	{
663 		ioasic.fifo_in = 0;
664 		ioasic.fifo_out = 0;
665 		ioasic.fifo_bytes = 0;
666 		update_ioasic_irq();
667 	}
668 	if (LOG_FIFO)
669 		logerror("fifo_reset(%d)\n", state);
670 }
671 
672 
midway_ioasic_fifo_w(data16_t data)673 void midway_ioasic_fifo_w(data16_t data)
674 {
675 	/* if we have room, add it to the FIFO buffer */
676 	if (ioasic.fifo_bytes < FIFO_SIZE)
677 	{
678 		ioasic.fifo[ioasic.fifo_in++ % FIFO_SIZE] = data;
679 		ioasic.fifo_bytes++;
680 		update_ioasic_irq();
681 		if (LOG_FIFO && (ioasic.fifo_bytes < 4 || ioasic.fifo_bytes >= FIFO_SIZE - 4))
682 			logerror("fifo_w(%04X): FIFO bytes = %d!\n", data, ioasic.fifo_bytes);
683 	}
684 	else
685 	{
686 		if (LOG_FIFO)
687 			logerror("fifo_w(%04X): out of space!\n", data);
688 	}
689 }
690 
691 
692 
693 /*************************************
694  *
695  *	I/O ASIC master read/write
696  *
697  *************************************/
698 
READ32_HANDLER(midway_ioasic_packed_r)699 READ32_HANDLER( midway_ioasic_packed_r )
700 {
701 	data32_t result = 0;
702 	if ((mem_mask & 0x0000ffff) != 0x0000ffff)
703 		result |= midway_ioasic_r(offset*2, 0xffff0000) & 0xffff;
704 	if ((mem_mask & 0xffff0000) != 0xffff0000)
705 		result |= (midway_ioasic_r(offset*2+1, 0xffff0000) & 0xffff) << 16;
706 	return result;
707 }
708 
709 
READ32_HANDLER(midway_ioasic_r)710 READ32_HANDLER( midway_ioasic_r )
711 {
712 	data32_t result;
713 
714 	offset = ioasic.shuffle_active ? ioasic.shuffle_map[offset & 15] : offset;
715 	result = ioasic.reg[offset];
716 
717 	switch (offset)
718 	{
719 		case IOASIC_PORT0:
720 			result = readinputport(0);
721 			/* bit 0 seems to be a ready flag before shuffling happens */
722 			if (!ioasic.shuffle_active)
723 			{
724 				result |= 0x0001;
725 				/* blitz99 wants bit bits 13-15 to be 1 */
726 				result &= ~0xe000;
727 				result |= 0x2000;
728 			}
729 			break;
730 
731 		case IOASIC_PORT1:
732 			result = readinputport(1);
733 			break;
734 
735 		case IOASIC_PORT2:
736 			result = readinputport(2);
737 			break;
738 
739 		case IOASIC_PORT3:
740 			result = readinputport(3);
741 			break;
742 
743 		case IOASIC_SOUNDSTAT:
744 			/* status from sound CPU */
745 			result = 0;
746 			if (ioasic.has_dcs)
747 			{
748 				result |= ((dcs_control_r() >> 4) ^ 0x40) & 0x00c0;
749 				result |= ioasic_fifo_status_r() & 0x0038;
750 				result |= dcs_data2_r() & 0xff00;
751 			}
752 			else if (ioasic.has_cage)
753 			{
754 				result |= (cage_control_r() << 6) ^ 0x80;
755 			}
756 			else
757 				result |= 0x48;
758 			break;
759 
760 		case IOASIC_SOUNDIN:
761 			result = 0;
762 			if (ioasic.has_dcs)
763 			{
764 				result = dcs_data_r();
765 				if (ioasic.auto_ack)
766 					dcs_ack_w();
767 			}
768 			else if (ioasic.has_cage)
769 				result = main_from_cage_r();
770 			else
771 			{
772 				static UINT16 val = 0;
773 				result = val = ~val;
774 			}
775 			break;
776 
777 		case IOASIC_PICIN:
778 			result = midway_serial_pic2_r() | (midway_serial_pic2_status_r() << 8);
779 			break;
780 
781 		default:
782 			break;
783 	}
784 
785 	if (LOG_IOASIC)
786 		logerror("%06X:ioasic_r(%d) = %08X\n", activecpu_get_pc(), offset, result);
787 
788 	return result;
789 }
790 
791 
WRITE32_HANDLER(midway_ioasic_packed_w)792 WRITE32_HANDLER( midway_ioasic_packed_w )
793 {
794 	if ((mem_mask & 0x0000ffff) != 0x0000ffff)
795 		midway_ioasic_w(offset*2, data & 0xffff, 0xffff0000);
796 	if ((mem_mask & 0xffff0000) != 0xffff0000)
797 		midway_ioasic_w(offset*2+1, data >> 16, 0xffff0000);
798 }
799 
800 
WRITE32_HANDLER(midway_ioasic_w)801 WRITE32_HANDLER( midway_ioasic_w )
802 {
803 	UINT32 oldreg, newreg;
804 
805 	offset = ioasic.shuffle_active ? ioasic.shuffle_map[offset & 15] : offset;
806 	oldreg = ioasic.reg[offset];
807 	COMBINE_DATA(&ioasic.reg[offset]);
808 	newreg = ioasic.reg[offset];
809 
810 	if (LOG_IOASIC)
811 		logerror("%06X:ioasic_w(%d) = %08X\n", activecpu_get_pc(), offset, data);
812 
813 	switch (offset)
814 	{
815 		case IOASIC_PORT0:
816 			/* the last write here seems to turn on shuffling */
817 			if (data == 0xe2)
818 			{
819 				ioasic.shuffle_active = 1;
820 				logerror("*** I/O ASIC shuffling enabled!\n");
821 				ioasic.reg[IOASIC_INTCTL] = 0;
822 				ioasic.reg[IOASIC_UNKNOWN4] = 0;	/* bug in 10th Degree assumes this */
823 			}
824 			break;
825 
826 		case IOASIC_PORT2:
827 		case IOASIC_PORT3:
828 			/* ignore writes here if we're not shuffling yet */
829 			if (!ioasic.shuffle_active)
830 				break;
831 			break;
832 
833 		case IOASIC_DEBUGOUT:
834 			if (PRINTF_DEBUG)
835 				printf("%c", data & 0xff);
836 			break;
837 
838 		case IOASIC_SOUNDCTL:
839 			/* sound reset? */
840 			if (ioasic.has_dcs)
841 			{
842 				dcs_reset_w(newreg & 1);
843 
844 			}
845 			else if (ioasic.has_cage)
846 			{
847 				if ((oldreg ^ newreg) & 1)
848 				{
849 					cage_control_w(0);
850 					if (!(~newreg & 1))
851 						cage_control_w(3);
852 				}
853 			}
854 
855 			/* FIFO reset? */
856 			ioasic_fifo_reset_w(~newreg & 4);
857 			break;
858 
859 		case IOASIC_SOUNDOUT:
860 			if (ioasic.has_dcs)
861 				dcs_data_w(newreg);
862 			else if (ioasic.has_cage)
863 				main_to_cage_w(newreg);
864 			break;
865 
866 		case IOASIC_SOUNDIN:
867 			dcs_ack_w();
868 			/* acknowledge data read */
869 			break;
870 
871 		case IOASIC_PICOUT:
872 			midway_serial_pic2_w(newreg);
873 			break;
874 
875 		case IOASIC_INTCTL:
876 			/* interrupt enables */
877 			/* bit  0 = global interrupt enable */
878 			/* bit  3 = FIFO empty */
879 			/* bit  6 = sound input buffer full */
880 			/* bit  7 = sound output buffer empty */
881 			/* bit 14 = LED? */
882 			if ((oldreg ^ newreg) & 0x3ff6)
883 				logerror("IOASIC int control = %04X\n", data);
884 			update_ioasic_irq();
885 			break;
886 
887 		default:
888 			break;
889 	}
890 }
891 
892 
893 
894 /*************************************
895  *
896  *	The IDE ASIC was used on War Gods
897  *	and Killer Instinct to map the IDE
898  *	registers
899  *
900  *************************************/
901 
READ32_HANDLER(midway_ide_asic_r)902 READ32_HANDLER( midway_ide_asic_r )
903 {
904 	/* convert to standard IDE offsets */
905 	offs_t ideoffs = 0x1f0/4 + (offset >> 2);
906 	UINT8 shift = 8 * (offset & 3);
907 	data32_t result;
908 
909 	/* offset 0 is a special case */
910 	if (offset == 0)
911 		result = ide_controller32_0_r(ideoffs, 0xffff0000);
912 
913 	/* everything else is byte-sized */
914 	else
915 		result = ide_controller32_0_r(ideoffs, ~(0xff << shift)) >> shift;
916 	return result;
917 }
918 
919 
WRITE32_HANDLER(midway_ide_asic_w)920 WRITE32_HANDLER( midway_ide_asic_w )
921 {
922 	/* convert to standard IDE offsets */
923 	offs_t ideoffs = 0x1f0/4 + (offset >> 2);
924 	UINT8 shift = 8 * (offset & 3);
925 
926 	/* offset 0 is a special case */
927 	if (offset == 0)
928 		ide_controller32_0_w(ideoffs, data, 0xffff0000);
929 
930 	/* everything else is byte-sized */
931 	else
932 		ide_controller32_0_w(ideoffs, data << shift, ~(0xff << shift));;
933 }
934