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