1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 Emulation of various Midway ICs
6
7 ***************************************************************************/
8
9 #include "emu.h"
10 #include "debugger.h"
11 #include "midwayic.h"
12
13
14 #define LOG_NVRAM (0)
15
16 #define PRINTF_DEBUG (0)
17 #define LOG_IOASIC (0)
18 #define LOG_FIFO (0)
19
20
21 /*************************************
22 *
23 * Constants
24 *
25 *************************************/
26
27 #define FIFO_SIZE 512
28
29 /*************************************
30 *
31 * Serial number input kludge
32 *
33 *************************************/
34
35 static INPUT_PORTS_START( pic_serial_adjust )
36 PORT_START("SERIAL_DIGIT")
37 PORT_DIPNAME( 0x0f, 0x06, "Serial Low Digit")
38 PORT_DIPSETTING( 0x00, "0")
39 PORT_DIPSETTING( 0x01, "1")
40 PORT_DIPSETTING( 0x02, "2")
41 PORT_DIPSETTING( 0x03, "3")
42 PORT_DIPSETTING( 0x04, "4")
43 PORT_DIPSETTING( 0x05, "5")
44 PORT_DIPSETTING( 0x06, "6")
45 PORT_DIPSETTING( 0x07, "7")
46 PORT_DIPSETTING( 0x08, "8")
47 PORT_DIPSETTING( 0x09, "9")
48 PORT_BIT( 0xf0, 0x00, IPT_UNUSED )
49 INPUT_PORTS_END
50
device_input_ports() const51 ioport_constructor midway_serial_pic_device::device_input_ports() const
52 {
53 return INPUT_PORTS_NAME(pic_serial_adjust);
54 }
55
56 /*************************************
57 *
58 * Serial number encoding
59 *
60 *************************************/
61
generate_serial_data(int upper)62 void midway_serial_pic_device::generate_serial_data(int upper)
63 {
64 int year = atoi(machine().system().year), month = 12, day = 11;
65 uint32_t serial_number, temp;
66 uint8_t serial_digit[9];
67
68 serial_number = 123450;
69 serial_number += upper * 1000000;
70 serial_number += m_io_serial_digit->read() & 0x0f;
71
72 serial_digit[0] = (serial_number / 100000000) % 10;
73 serial_digit[1] = (serial_number / 10000000) % 10;
74 serial_digit[2] = (serial_number / 1000000) % 10;
75 serial_digit[3] = (serial_number / 100000) % 10;
76 serial_digit[4] = (serial_number / 10000) % 10;
77 serial_digit[5] = (serial_number / 1000) % 10;
78 serial_digit[6] = (serial_number / 100) % 10;
79 serial_digit[7] = (serial_number / 10) % 10;
80 serial_digit[8] = (serial_number / 1) % 10;
81
82 m_data[12] = machine().rand() & 0xff;
83 m_data[13] = machine().rand() & 0xff;
84
85 m_data[14] = 0; /* ??? */
86 m_data[15] = 0; /* ??? */
87
88 temp = 0x174 * (year - 1980) + 0x1f * (month - 1) + day;
89 m_data[10] = (temp >> 8) & 0xff;
90 m_data[11] = temp & 0xff;
91
92 temp = serial_digit[4] + serial_digit[7] * 10 + serial_digit[1] * 100;
93 temp = (temp + 5 * m_data[13]) * 0x1bcd + 0x1f3f0;
94 m_data[7] = temp & 0xff;
95 m_data[8] = (temp >> 8) & 0xff;
96 m_data[9] = (temp >> 16) & 0xff;
97
98 temp = serial_digit[6] + serial_digit[8] * 10 + serial_digit[0] * 100 + serial_digit[2] * 10000;
99 temp = (temp + 2 * m_data[13] + m_data[12]) * 0x107f + 0x71e259;
100 m_data[3] = temp & 0xff;
101 m_data[4] = (temp >> 8) & 0xff;
102 m_data[5] = (temp >> 16) & 0xff;
103 m_data[6] = (temp >> 24) & 0xff;
104
105 temp = serial_digit[5] * 10 + serial_digit[3] * 100;
106 temp = (temp + m_data[12]) * 0x245 + 0x3d74;
107 m_data[0] = temp & 0xff;
108 m_data[1] = (temp >> 8) & 0xff;
109 m_data[2] = (temp >> 16) & 0xff;
110 }
111
112
113
114 /*************************************
115 *
116 * Original serial number PIC
117 * interface - simulation
118 *
119 *************************************/
120
serial_register_state()121 void midway_serial_pic_device::serial_register_state()
122 {
123 save_item(NAME(m_data));
124 save_item(NAME(m_buff));
125 save_item(NAME(m_idx));
126 save_item(NAME(m_status));
127 save_item(NAME(m_bits));
128 }
129
130 DEFINE_DEVICE_TYPE(MIDWAY_SERIAL_PIC, midway_serial_pic_device, "midway_serial_pic_sim", "Midway Serial PIC Simulation")
131
132
133 //-------------------------------------------------
134 // midway_serial_pic_device - constructor
135 //-------------------------------------------------
136
midway_serial_pic_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)137 midway_serial_pic_device::midway_serial_pic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
138 midway_serial_pic_device(mconfig, MIDWAY_SERIAL_PIC, tag, owner, clock)
139 {
140 }
141
midway_serial_pic_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)142 midway_serial_pic_device::midway_serial_pic_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
143 device_t(mconfig, type, tag, owner, clock),
144 m_io_serial_digit(*this, "SERIAL_DIGIT"),
145 m_upper(0),
146 m_buff(0),
147 m_idx(0),
148 m_status(0),
149 m_bits(0)
150 {
151 memset(m_data,0,sizeof(m_data));
152 }
153
154 //-------------------------------------------------
155 // device_start - device-specific startup
156 //-------------------------------------------------
157
device_start()158 void midway_serial_pic_device::device_start()
159 {
160 serial_register_state();
161 }
162
device_reset()163 void midway_serial_pic_device::device_reset()
164 {
165 generate_serial_data(m_upper);
166 }
167
WRITE_LINE_MEMBER(midway_serial_pic_device::reset_w)168 WRITE_LINE_MEMBER(midway_serial_pic_device::reset_w)
169 {
170 if (state)
171 {
172 m_idx = 0;
173 m_status = 0;
174 m_buff = 0;
175 }
176 }
177
178
status_r()179 u8 midway_serial_pic_device::status_r()
180 {
181 return m_status;
182 }
183
184
read()185 u8 midway_serial_pic_device::read()
186 {
187 if (!machine().side_effects_disabled())
188 {
189 logerror("%s:security R = %04X\n", machine().describe_context(), m_buff);
190 m_status = 1;
191 }
192 return m_buff;
193 }
194
195
write(u8 data)196 void midway_serial_pic_device::write(u8 data)
197 {
198 logerror("%s:security W = %04X\n", machine().describe_context(), data);
199
200 /* status seems to reflect the clock bit */
201 m_status = (data >> 4) & 1;
202
203 /* on the falling edge, clock the next data byte through */
204 if (!m_status)
205 {
206 /* the self-test writes 1F, 0F, and expects to read an F in the low 4 bits */
207 if (data & 0x0f)
208 m_buff = data & 0xf;
209 else
210 m_buff = m_data[m_idx++ % sizeof(m_data)];
211 }
212 }
213
214
215 /*************************************
216 *
217 * Original serial number PIC
218 * interface - emulation
219 *
220 * PIC16C57 wiring notes:
221 * PORTA - 4bit command in (usually 0 = read SN#)
222 * PORTB - 8bit data out
223 * PORTC bit 7 - access clock in
224 * PORTC bit 6 - status out
225 * PORTC bit 2 - in/out (optional) MK41T56N RTC/NVRAM Data
226 * PORTC bit 1 - out (optional) MK41T56N RTC/NVRAM Clock
227 *
228 *************************************/
229
230
231 DEFINE_DEVICE_TYPE(MIDWAY_SERIAL_PIC_EMU, midway_serial_pic_emu_device, "midway_serial_pic_emu", "Midway Serial PIC Emulation")
232
233
234 //-------------------------------------------------
235 // midway_serial_pic_emu_device - constructor
236 //-------------------------------------------------
237
midway_serial_pic_emu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)238 midway_serial_pic_emu_device::midway_serial_pic_emu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
239 device_t(mconfig, MIDWAY_SERIAL_PIC_EMU, tag, owner, clock)
240 , m_pic(*this, "pic")
241 {
242 }
243
244 //-------------------------------------------------
245 // device_start - device-specific startup
246 //-------------------------------------------------
247
device_start()248 void midway_serial_pic_emu_device::device_start()
249 {
250 save_item(NAME(m_command));
251 save_item(NAME(m_data_out));
252 save_item(NAME(m_clk));
253 save_item(NAME(m_status));
254
255 m_command = 0;
256 m_data_out = 0;
257 m_clk = 0;
258 m_status = 0;
259 }
260
WRITE_LINE_MEMBER(midway_serial_pic_emu_device::reset_w)261 WRITE_LINE_MEMBER(midway_serial_pic_emu_device::reset_w)
262 {
263 if (!state) // fixme, PIC should be stopped while 0 and start running at 0->1 transition
264 m_pic->reset();
265 }
266
status_r()267 u8 midway_serial_pic_emu_device::status_r()
268 {
269 return m_status;
270 }
271
read()272 u8 midway_serial_pic_emu_device::read()
273 {
274 return m_data_out;
275 }
276
write(u8 data)277 void midway_serial_pic_emu_device::write(u8 data)
278 {
279 // perhaps this should be split in 2 handlers ?
280 m_command = data & 0x0f;
281 m_clk = BIT(data, 4);
282 }
283
read_c()284 u8 midway_serial_pic_emu_device::read_c()
285 {
286 u8 data = 0;
287 data |= m_clk << 7;
288 // bit 2 RTC Data
289 return data;
290 }
291
write_c(u8 data)292 void midway_serial_pic_emu_device::write_c(u8 data)
293 {
294 m_status = BIT(data, 6);
295 // bits 1 and 2 is RTC Clock and Data
296 // printf("%s: write_c %02x\n", machine().describe_context().c_str(), data);
297 }
298
device_add_mconfig(machine_config & config)299 void midway_serial_pic_emu_device::device_add_mconfig(machine_config &config)
300 {
301 PIC16C57(config, m_pic, 4000000); /* ? Mhz */
302 m_pic->read_a().set([this]() { return m_command; });
303 m_pic->write_b().set([this](u8 data) { m_data_out = data; });
304 m_pic->read_c().set(FUNC(midway_serial_pic_emu_device::read_c));
305 m_pic->write_c().set(FUNC(midway_serial_pic_emu_device::write_c));
306 }
307
308
309 /*************************************
310 *
311 * Second generation serial number
312 * PIC interface; this version also
313 * contained some NVRAM and a real
314 * time clock
315 *
316 *************************************/
317
make_bcd(uint8_t data)318 static inline uint8_t make_bcd(uint8_t data)
319 {
320 return ((data / 10) << 4) | (data % 10);
321 }
322
323 DEFINE_DEVICE_TYPE(MIDWAY_SERIAL_PIC2, midway_serial_pic2_device, "midway_serial_pic2", "Midway Serial PIC 2")
324
325
326 //-------------------------------------------------
327 // midway_serial_pic2_device - constructor
328 //-------------------------------------------------
329
midway_serial_pic2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)330 midway_serial_pic2_device::midway_serial_pic2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
331 midway_serial_pic2_device(mconfig, MIDWAY_SERIAL_PIC2, tag, owner, clock)
332 {
333 }
334
midway_serial_pic2_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)335 midway_serial_pic2_device::midway_serial_pic2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
336 midway_serial_pic_device(mconfig, type, tag, owner, clock),
337 device_nvram_interface(mconfig, *this),
338 m_latch(0),
339 m_state(0),
340 m_index(0),
341 m_total(0),
342 m_nvram_addr(0),
343 m_time_index(0),
344 m_time_just_written(0),
345 m_yearoffs(0),
346 m_time_write_timer(nullptr)
347 {
348 memset(m_buffer,0,sizeof(m_buffer));
349 memset(m_time_buf,0,sizeof(m_time_buf));
350 memset(m_nvram,0,sizeof(m_nvram));
351 memset(m_default_nvram,0,sizeof(m_default_nvram));
352 }
353
354
355 //-------------------------------------------------
356 // device_start - device-specific startup
357 //-------------------------------------------------
358
device_start()359 void midway_serial_pic2_device::device_start()
360 {
361 midway_serial_pic_device::device_start();
362 //void midway_serial_pic2_init(running_machine &machine, int upper, int yearoffs)
363 pic_register_state();
364
365 //m_yearoffs = yearoffs;
366 m_time_just_written = 0;
367 m_time_write_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(midway_serial_pic2_device::reset_timer),this));
368 memset(m_default_nvram, 0xff, sizeof(m_default_nvram));
369 }
370
371
TIMER_CALLBACK_MEMBER(midway_serial_pic2_device::reset_timer)372 TIMER_CALLBACK_MEMBER( midway_serial_pic2_device::reset_timer )
373 {
374 m_time_just_written = 0;
375 }
376
377
pic_register_state()378 void midway_serial_pic2_device::pic_register_state()
379 {
380 save_item(NAME(m_latch));
381 save_item(NAME(m_latch_expire_time));
382 save_item(NAME(m_state));
383 save_item(NAME(m_index));
384 save_item(NAME(m_total));
385 save_item(NAME(m_nvram_addr));
386 save_item(NAME(m_buffer));
387 save_item(NAME(m_nvram));
388 save_item(NAME(m_default_nvram));
389 save_item(NAME(m_time_buf));
390 save_item(NAME(m_time_index));
391 save_item(NAME(m_time_just_written));
392 save_item(NAME(m_yearoffs));
393 }
394
395
396
set_default_nvram(const uint8_t * nvram)397 void midway_serial_pic2_device::set_default_nvram(const uint8_t *nvram)
398 {
399 memcpy(m_default_nvram, nvram, sizeof(m_default_nvram));
400 }
401
402
status_r()403 u8 midway_serial_pic2_device::status_r()
404 {
405 uint8_t result = 0;
406
407 if (!machine().side_effects_disabled())
408 {
409 /* if we're still holding the data ready bit high, do it */
410 if (m_latch & 0xf00)
411 {
412 if (machine().time() > m_latch_expire_time)
413 m_latch &= 0xff;
414 else
415 m_latch -= 0x100;
416 result = 1;
417 }
418
419 logerror("%s:PIC status %d\n", machine().describe_context(), result);
420 }
421 return result;
422 }
423
424
read()425 u8 midway_serial_pic2_device::read()
426 {
427 uint8_t result = 0;
428
429 /* PIC data register */
430 if (!machine().side_effects_disabled())
431 logerror("%s:PIC data read (index=%d total=%d latch=%03X) =", machine().describe_context(), m_index, m_total, m_latch);
432
433 /* return the current result */
434 if (m_latch & 0xf00)
435 result = m_latch & 0xff;
436
437 /* otherwise, return 0xff if we have data ready */
438 else if (m_index < m_total)
439 result = 0xff;
440
441 if (!machine().side_effects_disabled())
442 logerror("%02X\n", result);
443 return result;
444 }
445
446
write(u8 data)447 void midway_serial_pic2_device::write(u8 data)
448 {
449 static FILE *nvramlog;
450 if (LOG_NVRAM && !nvramlog)
451 nvramlog = fopen("nvram.log", "w");
452
453 /* PIC command register */
454 if (m_state == 0)
455 logerror("%s:PIC command %02X\n", machine().describe_context(), data);
456 else
457 logerror("%s:PIC data %02X\n", machine().describe_context(), data);
458
459 /* store in the latch, along with a bit to indicate we have data */
460 m_latch = (data & 0x00f) | 0x480;
461 m_latch_expire_time = machine().time() + attotime::from_msec(1);
462 if (data & 0x10)
463 {
464 int cmd = m_state ? (m_state & 0x0f) : (m_latch & 0x0f);
465 switch (cmd)
466 {
467 /* written to latch the next byte of data */
468 case 0:
469 if (m_index < m_total)
470 m_latch = 0x400 | m_buffer[m_index++];
471 break;
472
473 /* fetch the serial number */
474 case 1:
475 /* note: Biofreaks assumes that it can latch the next byte this way */
476 if (m_index < m_total)
477 m_latch = 0x400 | m_buffer[m_index++];
478 else
479 {
480 memcpy(m_buffer, m_data, 16);
481 m_total = 16;
482 m_index = 0;
483 machine().debug_break();
484 }
485 break;
486
487 /* read the clock */
488 case 3:
489 {
490 /* stuff it into the data bytes */
491 m_index = 0;
492 m_total = 0;
493
494 /* if we haven't written a new time recently, use the real live time */
495 if (!m_time_just_written)
496 {
497 system_time systime;
498 machine().base_datetime(systime);
499
500 m_buffer[m_total++] = make_bcd(systime.local_time.second);
501 m_buffer[m_total++] = make_bcd(systime.local_time.minute);
502 m_buffer[m_total++] = make_bcd(systime.local_time.hour);
503 m_buffer[m_total++] = make_bcd(systime.local_time.weekday + 1);
504 m_buffer[m_total++] = make_bcd(systime.local_time.mday);
505 m_buffer[m_total++] = make_bcd(systime.local_time.month + 1);
506 m_buffer[m_total++] = make_bcd(systime.local_time.year - 1900 - m_yearoffs);
507 }
508
509 /* otherwise, just parrot back what was written to pass self tests */
510 else
511 {
512 m_buffer[m_total++] = m_time_buf[0];
513 m_buffer[m_total++] = m_time_buf[1];
514 m_buffer[m_total++] = m_time_buf[2];
515 m_buffer[m_total++] = m_time_buf[3];
516 m_buffer[m_total++] = m_time_buf[4];
517 m_buffer[m_total++] = m_time_buf[5];
518 m_buffer[m_total++] = m_time_buf[6];
519 }
520 break;
521 }
522
523 /* write the clock */
524 case 4:
525
526 /* if coming from state 0, go to state 1 (this is just the command byte) */
527 if (m_state == 0)
528 {
529 m_state = 0x14;
530 m_time_index = 0;
531 }
532
533 /* if in states 1-2 put data in the buffer until it's full */
534 else if (m_state == 0x14)
535 {
536 m_time_buf[m_time_index] = m_latch & 0x0f;
537 m_state = 0x24;
538 }
539 else if (m_state == 0x24)
540 {
541 m_time_buf[m_time_index++] |= m_latch << 4;
542
543 /* if less than 7 bytes accumulated, go back to state 1 */
544 if (m_time_index < 7)
545 m_state = 0x14;
546
547 /* otherwise, flag the time as having just been written for 1/2 second */
548 else
549 {
550 m_time_write_timer->adjust(attotime::from_msec(500));
551 m_time_just_written = 1;
552 m_state = 0;
553 }
554 }
555 break;
556
557 /* write to NVRAM */
558 case 5:
559
560 /* if coming from state 0, go to state 1 (this is just the command byte) */
561 if (m_state == 0)
562 m_state = 0x15;
563
564 /* coming from state 1, go to state 2 and latch the low 4 address bits */
565 else if (m_state == 0x15)
566 {
567 m_nvram_addr = m_latch & 0x0f;
568 m_state = 0x25;
569 }
570
571 /* coming from state 2, go to state 3 and latch the high 4 address bits */
572 else if (m_state == 0x25)
573 {
574 m_state = 0x35;
575 m_nvram_addr |= m_latch << 4;
576 }
577
578 /* coming from state 3, go to state 4 and write the low 4 bits */
579 else if (m_state == 0x35)
580 {
581 m_state = 0x45;
582 m_nvram[m_nvram_addr] = m_latch & 0x0f;
583 }
584
585 /* coming from state 4, reset the states and write the upper 4 bits */
586 else if (m_state == 0x45)
587 {
588 m_state = 0;
589 m_nvram[m_nvram_addr] |= m_latch << 4;
590 if (nvramlog)
591 fprintf(nvramlog, "Write byte %02X = %02X\n", m_nvram_addr, m_nvram[m_nvram_addr]);
592 }
593 break;
594
595 /* read from NVRAM */
596 case 6:
597
598 /* if coming from state 0, go to state 1 (this is just the command byte) */
599 if (m_state == 0)
600 m_state = 0x16;
601
602 /* coming from state 1, go to state 2 and latch the low 4 address bits */
603 else if (m_state == 0x16)
604 {
605 m_nvram_addr = m_latch & 0x0f;
606 m_state = 0x26;
607 }
608
609 /* coming from state 2, reset the states and make the data available */
610 else if (m_state == 0x26)
611 {
612 m_state = 0;
613 m_nvram_addr |= m_latch << 4;
614
615 m_total = 0;
616 m_index = 0;
617 m_buffer[m_total++] = m_nvram[m_nvram_addr];
618 if (nvramlog)
619 fprintf(nvramlog, "Read byte %02X = %02X\n", m_nvram_addr, m_nvram[m_nvram_addr]);
620 }
621 break;
622
623 /* reflect inverted? (Cruisin' Exotica) */
624 case 8:
625 m_latch = 0x400 | (~cmd & 0xff);
626 break;
627 }
628 }
629 }
630
nvram_default()631 void midway_serial_pic2_device::nvram_default()
632 {
633 memcpy(m_nvram, m_default_nvram, sizeof(m_nvram));
634 }
635
nvram_read(emu_file & file)636 void midway_serial_pic2_device::nvram_read(emu_file &file)
637 {
638 file.read(m_nvram, sizeof(m_nvram));
639 }
640
nvram_write(emu_file & file)641 void midway_serial_pic2_device::nvram_write(emu_file &file)
642 {
643 file.write(m_nvram, sizeof(m_nvram));
644 }
645
646
647 /*************************************
648 *
649 * The I/O ASIC was first introduced
650 * in War Gods, then later used on
651 * the Seattle hardware
652 *
653 *************************************/
654
655 enum
656 {
657 IOASIC_PORT0, /* 0: input port 0 */
658 IOASIC_PORT1, /* 1: input port 1 */
659 IOASIC_PORT2, /* 2: input port 2 */
660 IOASIC_PORT3, /* 3: input port 3 */
661 IOASIC_UARTCONTROL, /* 4: controls some UART behavior */
662 IOASIC_UARTOUT, /* 5: UART output */
663 IOASIC_UARTIN, /* 6: UART input */
664 IOASIC_COIN, /* 7: triggered on coin insertion */
665 IOASIC_SOUNDCTL, /* 8: sound communications control */
666 IOASIC_SOUNDOUT, /* 9: sound output port */
667 IOASIC_SOUNDSTAT, /* a: sound status port */
668 IOASIC_SOUNDIN, /* b: sound input port */
669 IOASIC_PICOUT, /* c: PIC output port */
670 IOASIC_PICIN, /* d: PIC input port */
671 IOASIC_INTSTAT, /* e: interrupt status */
672 IOASIC_INTCTL /* f: interrupt control */
673 };
674
ioasic_register_state()675 void midway_ioasic_device::ioasic_register_state()
676 {
677 save_item(NAME(m_reg));
678 save_item(NAME(m_shuffle_active));
679 save_item(NAME(m_irq_state));
680 save_item(NAME(m_sound_irq_state));
681 save_item(NAME(m_auto_ack));
682 save_item(NAME(m_force_fifo_full));
683 save_item(NAME(m_fifo));
684 save_item(NAME(m_fifo_in));
685 save_item(NAME(m_fifo_out));
686 save_item(NAME(m_fifo_bytes));
687 save_item(NAME(m_fifo_force_buffer_empty_pc));
688 }
689
690 DEFINE_DEVICE_TYPE(MIDWAY_IOASIC, midway_ioasic_device, "midway_ioasic", "Midway IOASIC")
691
692
693 //-------------------------------------------------
694 // midway_serial_pic2_device - constructor
695 //-------------------------------------------------
696
midway_ioasic_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)697 midway_ioasic_device::midway_ioasic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
698 midway_serial_pic2_device(mconfig, MIDWAY_IOASIC, tag, owner, clock),
699 m_io_dips(*this, ":DIPS"),
700 m_io_system(*this, ":SYSTEM"),
701 m_io_in1(*this, ":IN1"),
702 m_io_in2(*this, ":IN2"),
703 m_serial_tx_cb(*this),
704 m_aux_output_cb(*this),
705 m_has_dcs(0),
706 m_has_cage(0),
707 m_dcs_cpu(nullptr),
708 m_shuffle_type(0),
709 m_shuffle_default(0),
710 m_shuffle_active(0),
711 m_shuffle_map(nullptr),
712 m_irq_callback(*this),
713 m_irq_state(0),
714 m_sound_irq_state(0),
715 m_auto_ack(0),
716 m_force_fifo_full(0),
717 m_fifo_in(0),
718 m_fifo_out(0),
719 m_fifo_bytes(0),
720 m_fifo_force_buffer_empty_pc(0),
721 m_cage(*this, ":cage"),
722 m_dcs(*this, ":dcs")
723 {
724 memset(m_fifo,0,sizeof(m_fifo));
725 memset(m_reg,0,sizeof(m_reg));
726 }
727
728
729 //-------------------------------------------------
730 // device_start - device-specific startup
731 //-------------------------------------------------
732
device_start()733 void midway_ioasic_device::device_start()
734 //void midway_ioasic_init(running_machine &machine, int shuffle, int upper, int yearoffs, void (*irq_callback)(running_machine &, int))
735 {
736 static const uint8_t shuffle_maps[][16] =
737 {
738 { 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf }, /* WarGods, WG3DH, SFRush, MK4 */
739 { 0x4,0x5,0x6,0x7,0xb,0xa,0x9,0x8,0x3,0x2,0x1,0x0,0xf,0xe,0xd,0xc }, /* Blitz, Blitz99 */
740 { 0x7,0x3,0x2,0x0,0x1,0xc,0xd,0xe,0xf,0x4,0x5,0x6,0x8,0x9,0xa,0xb }, /* Carnevil */
741 { 0x8,0x9,0xa,0xb,0x0,0x1,0x2,0x3,0xf,0xe,0xc,0xd,0x4,0x5,0x6,0x7 }, /* Calspeed, Gauntlet Legends */
742 { 0xf,0xe,0xd,0xc,0x4,0x5,0x6,0x7,0x9,0x8,0xa,0xb,0x2,0x3,0x1,0x0 }, /* Mace */
743 { 0xc,0xd,0xe,0xf,0x0,0x1,0x2,0x3,0x7,0x8,0x9,0xb,0xa,0x5,0x6,0x4 }, /* Gauntlet Dark Legacy */
744 { 0x7,0x4,0x5,0x6,0x2,0x0,0x1,0x3,0x8,0x9,0xa,0xb,0xd,0xc,0xe,0xf }, /* Vapor TRX */
745 { 0x7,0x4,0x5,0x6,0x2,0x0,0x1,0x3,0x8,0x9,0xa,0xb,0xd,0xc,0xe,0xf }, /* San Francisco Rush: The Rock */
746 { 0x1,0x2,0x3,0x0,0x4,0x5,0x6,0x7,0xa,0xb,0x8,0x9,0xc,0xd,0xe,0xf }, /* Hyperdrive */
747 };
748
749 ioasic_register_state();
750
751 /* do we have a DCS2 sound chip connected? */
752 m_has_dcs = (m_dcs != nullptr);
753 m_has_cage = (m_cage != nullptr);
754
755 if (m_has_dcs)
756 {
757 m_dcs_cpu = m_dcs->get_cpu();
758 }
759
760 m_shuffle_map = &shuffle_maps[m_shuffle_type][0];
761 // resolve callbacks
762 m_irq_callback.resolve_safe();
763 m_serial_tx_cb.resolve_safe();
764 m_aux_output_cb.resolve();
765
766 /* initialize the PIC */
767 midway_serial_pic2_device::device_start();
768
769 /* reset the chip */
770 ioasic_reset();
771
772 m_reg[IOASIC_SOUNDCTL] = 0x0001;
773
774
775 /* configure the fifo */
776 if (m_has_dcs)
777 {
778 m_dcs->set_fifo_callbacks(
779 read16smo_delegate(*this, FUNC(midway_ioasic_device::fifo_r)),
780 read16mo_delegate(*this, FUNC(midway_ioasic_device::fifo_status_r)),
781 write_line_delegate(*this, FUNC(midway_ioasic_device::fifo_reset_w)));
782 m_dcs->set_io_callbacks(
783 write_line_delegate(*this, FUNC(midway_ioasic_device::ioasic_output_full)),
784 write_line_delegate(*this, FUNC(midway_ioasic_device::ioasic_input_empty)));
785 }
786
787 fifo_reset_w(1);
788 }
789
set_shuffle_state(int state)790 void midway_ioasic_device::set_shuffle_state(int state)
791 {
792 m_shuffle_active = state;
793 }
794
795
ioasic_reset()796 void midway_ioasic_device::ioasic_reset()
797 {
798 m_shuffle_active = m_shuffle_default;
799 m_sound_irq_state = 0x0080;
800 m_reg[IOASIC_INTCTL] = 0;
801 if (m_has_dcs)
802 fifo_reset_w(1);
803 update_ioasic_irq();
804 midway_serial_pic_device::reset_w(1);
805 }
806
807
update_ioasic_irq()808 void midway_ioasic_device::update_ioasic_irq()
809 {
810 uint16_t fifo_state = fifo_status_r(machine().dummy_space());
811 uint16_t irqbits = 0x2000;
812 uint8_t new_state;
813
814 irqbits |= m_sound_irq_state & 0xff;
815 irqbits |= m_reg[IOASIC_UARTIN] & 0x3f00;
816 if (fifo_state & 8)
817 irqbits |= 0x0008;
818 if (irqbits)
819 irqbits |= 0x0001;
820
821 m_reg[IOASIC_INTSTAT] = irqbits;
822
823 new_state = ((m_reg[IOASIC_INTCTL] & 0x0001) != 0) && ((m_reg[IOASIC_INTSTAT] & m_reg[IOASIC_INTCTL] & 0x3ffe) != 0);
824 if (new_state != m_irq_state)
825 {
826 m_irq_state = new_state;
827 if (!m_irq_callback.isnull())
828 m_irq_callback(m_irq_state ? ASSERT_LINE : CLEAR_LINE);
829 if (m_irq_state && (m_reg[IOASIC_UARTIN] & 0x1000))
830 logerror("IOASIC: Asserting IRQ INTCTRL=%04x INTSTAT=%04X\n", m_reg[IOASIC_INTCTL], m_reg[IOASIC_INTSTAT]);
831 }
832 }
833
834
cage_irq_handler(uint8_t data)835 void midway_ioasic_device::cage_irq_handler(uint8_t data)
836 {
837 logerror("CAGE irq handler: %d\n", data);
838 m_sound_irq_state = 0;
839 if (data & atari_cage_device::CAGE_IRQ_REASON_DATA_READY)
840 m_sound_irq_state |= 0x0040;
841 if (data & atari_cage_device::CAGE_IRQ_REASON_BUFFER_EMPTY)
842 m_sound_irq_state |= 0x0080;
843 update_ioasic_irq();
844 }
845
846
WRITE_LINE_MEMBER(midway_ioasic_device::ioasic_input_empty)847 WRITE_LINE_MEMBER(midway_ioasic_device::ioasic_input_empty)
848 {
849 // logerror("ioasic_input_empty(%d)\n", state);
850 if (state)
851 m_sound_irq_state |= 0x0080;
852 else
853 m_sound_irq_state &= ~0x0080;
854 update_ioasic_irq();
855 }
856
857
WRITE_LINE_MEMBER(midway_ioasic_device::ioasic_output_full)858 WRITE_LINE_MEMBER(midway_ioasic_device::ioasic_output_full)
859 {
860 // logerror("ioasic_output_full(%d)\n", state);
861 if (state)
862 m_sound_irq_state |= 0x0040;
863 else
864 m_sound_irq_state &= ~0x0040;
865 update_ioasic_irq();
866 }
867
868
869
870 /*************************************
871 *
872 * ASIC sound FIFO; used by CarnEvil
873 *
874 *************************************/
875
fifo_r()876 uint16_t midway_ioasic_device::fifo_r()
877 {
878 uint16_t result = 0;
879
880 /* we can only read data if there's some to read! */
881 if (m_fifo_bytes != 0)
882 {
883 /* fetch the data from the buffer and update the IOASIC state */
884 result = m_fifo[m_fifo_out++ % FIFO_SIZE];
885 m_fifo_bytes--;
886 update_ioasic_irq();
887
888 if (LOG_FIFO && (m_fifo_bytes < 4 || m_fifo_bytes >= FIFO_SIZE - 4))
889 logerror("fifo_r(%04X): FIFO bytes = %d!\n", result, m_fifo_bytes);
890
891 /* if we just cleared the buffer, this may generate an IRQ on the master CPU */
892 /* because of the way the streaming code works, we need to make sure that the */
893 /* next status read indicates an empty buffer, even if we've timesliced and the */
894 /* main CPU is handling the I/O ASIC interrupt */
895 if (m_fifo_bytes == 0 && m_has_dcs)
896 {
897 m_fifo_force_buffer_empty_pc = m_dcs_cpu->pc();
898 if (LOG_FIFO)
899 logerror("fifo_r(%04X): FIFO empty, PC = %04X\n", result, m_fifo_force_buffer_empty_pc);
900 }
901 }
902 else
903 {
904 if (LOG_FIFO)
905 logerror("fifo_r(): nothing to read!\n");
906 }
907 return result;
908 }
909
910
fifo_status_r(address_space & space)911 uint16_t midway_ioasic_device::fifo_status_r(address_space &space)
912 {
913 uint16_t result = 0;
914
915 if (m_fifo_bytes == 0 && !m_force_fifo_full)
916 result |= 0x08;
917 if (m_fifo_bytes >= FIFO_SIZE/2)
918 result |= 0x10;
919 if (m_fifo_bytes >= FIFO_SIZE || m_force_fifo_full)
920 result |= 0x20;
921
922 /* kludge alert: if we're reading this from the DCS CPU itself, and we recently cleared */
923 /* the FIFO, and we're within 16 instructions of the read that cleared the FIFO, make */
924 /* sure the FIFO clear bit is set */
925 if (m_fifo_force_buffer_empty_pc && &space.device() == m_dcs_cpu)
926 {
927 offs_t currpc = m_dcs_cpu->pc();
928 if (currpc >= m_fifo_force_buffer_empty_pc && currpc < m_fifo_force_buffer_empty_pc + 0x10)
929 {
930 m_fifo_force_buffer_empty_pc = 0;
931 result |= 0x08;
932 if (LOG_FIFO)
933 logerror("ioasic_fifo_status_r(%04X): force empty, PC = %04X\n", result, currpc);
934 }
935 }
936
937 return result;
938 }
939
940
WRITE_LINE_MEMBER(midway_ioasic_device::fifo_reset_w)941 WRITE_LINE_MEMBER(midway_ioasic_device::fifo_reset_w)
942 {
943 /* on the high state, reset the FIFO data */
944 if (state)
945 {
946 m_fifo_in = 0;
947 m_fifo_out = 0;
948 m_fifo_bytes = 0;
949 m_force_fifo_full = 0;
950 update_ioasic_irq();
951 }
952 if (LOG_FIFO)
953 logerror("%s:fifo_reset(%d)\n", machine().describe_context(), state);
954 }
955
956
fifo_w(uint16_t data)957 void midway_ioasic_device::fifo_w(uint16_t data)
958 {
959 /* if we have room, add it to the FIFO buffer */
960 if (m_fifo_bytes < FIFO_SIZE)
961 {
962 m_fifo[m_fifo_in++ % FIFO_SIZE] = data;
963 m_fifo_bytes++;
964 update_ioasic_irq();
965 if (LOG_FIFO && (m_fifo_bytes < 4 || m_fifo_bytes >= FIFO_SIZE - 4))
966 logerror("fifo_w(%04X): FIFO bytes = %d!\n", data, m_fifo_bytes);
967 }
968 else
969 {
970 if (LOG_FIFO)
971 logerror("fifo_w(%04X): out of space!\n", data);
972 }
973 m_dcs->fifo_notify(m_fifo_bytes, FIFO_SIZE);
974 }
975
976
fifo_full_w(uint16_t data)977 void midway_ioasic_device::fifo_full_w(uint16_t data)
978 {
979 if (LOG_FIFO)
980 logerror("fifo_full_w(%04X)\n", data);
981 m_force_fifo_full = 1;
982 update_ioasic_irq();
983 m_dcs->fifo_notify(m_fifo_bytes, FIFO_SIZE);
984 }
985
986
987
988 /*************************************
989 *
990 * I/O ASIC master read/write
991 *
992 *************************************/
993
packed_r(address_space & space,offs_t offset,uint32_t mem_mask)994 uint32_t midway_ioasic_device::packed_r(address_space &space, offs_t offset, uint32_t mem_mask)
995 {
996 uint32_t result = 0;
997 if (ACCESSING_BITS_0_15)
998 result |= read(space, offset*2) & 0xffff;
999 if (ACCESSING_BITS_16_31)
1000 result |= (read(space, offset*2+1) & 0xffff) << 16;
1001 return result;
1002 }
1003
1004
read(address_space & space,offs_t offset)1005 uint32_t midway_ioasic_device::read(address_space &space, offs_t offset)
1006 {
1007 uint32_t result;
1008
1009 offset = m_shuffle_active ? m_shuffle_map[offset & 15] : offset;
1010 result = m_reg[offset];
1011
1012 switch (offset)
1013 {
1014 case IOASIC_PORT0:
1015 // bit 0 is PIC ready flag before shuffling happens
1016 // bits 15:13 == 001
1017 if (!m_shuffle_active)
1018 {
1019 /* blitz99 wants bit bits 13-15 to be 1 */
1020 result = 0x2001;
1021 }
1022 else {
1023 result = m_io_dips->read();
1024 }
1025 break;
1026
1027 case IOASIC_PORT1:
1028 result = m_io_system->read();
1029 break;
1030
1031 case IOASIC_PORT2:
1032 result = m_io_in1->read();
1033 break;
1034
1035 case IOASIC_PORT3:
1036 result = m_io_in2->read();
1037 break;
1038
1039 case IOASIC_UARTIN:
1040 m_reg[offset] &= ~0x1000;
1041 if (result & 0x1000)
1042 logerror("%s: ioasic_r(%d) = %08X\n", machine().describe_context(), offset, result);
1043 // Add lf
1044 if ((result & 0xff)==0x0d)
1045 m_reg[offset] = 0x300a;
1046 update_ioasic_irq();
1047 break;
1048
1049 case IOASIC_SOUNDSTAT:
1050 /* status from sound CPU */
1051 result = 0;
1052 if (m_has_dcs)
1053 {
1054 result |= ((m_dcs->control_r() >> 4) ^ 0x40) & 0x00c0;
1055 result |= fifo_status_r(space) & 0x0038;
1056 result |= m_dcs->data2_r() & 0xff00;
1057 }
1058 else if (m_has_cage)
1059 {
1060 result |= (m_cage->control_r() << 6) ^ 0x80;
1061 }
1062 else
1063 result |= 0x48;
1064 break;
1065
1066 case IOASIC_SOUNDIN:
1067 result = 0;
1068 if (m_has_dcs)
1069 {
1070 result = m_dcs->data_r();
1071 if (m_auto_ack)
1072 m_dcs->ack_w();
1073 }
1074 else if (m_has_cage)
1075 result = m_cage->main_r();
1076 else
1077 {
1078 static uint16_t val = 0;
1079 result = val = ~val;
1080 }
1081 break;
1082
1083 case IOASIC_PICIN:
1084 result = midway_serial_pic2_device::read() | (midway_serial_pic2_device::status_r() << 8);
1085 break;
1086
1087 default:
1088 break;
1089 }
1090
1091 if (LOG_IOASIC && offset != IOASIC_SOUNDSTAT && offset != IOASIC_SOUNDIN)
1092 logerror("%s:ioasic_r(%d) = %08X\n", machine().describe_context(), offset, result);
1093
1094 return result;
1095 }
1096
1097
packed_w(offs_t offset,uint32_t data,uint32_t mem_mask)1098 void midway_ioasic_device::packed_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1099 {
1100 if (ACCESSING_BITS_0_15)
1101 write(offset*2, data & 0xffff, 0x0000ffff);
1102 if (ACCESSING_BITS_16_31)
1103 write(offset*2+1, data >> 16, 0x0000ffff);
1104 }
1105
serial_rx_w(u8 data)1106 void midway_ioasic_device::serial_rx_w(u8 data)
1107 {
1108 // Break Detect 0x0100
1109 // Frame Error 0x0200
1110 // Overrun 0x0400
1111 // Rx FIFO FULL 0x0800
1112 // Rx Ready 0x1000
1113 // Tx EMPTY 0x2000
1114 // CTS IN 0x4000
1115 // CTS OUT 0x8000
1116 if (m_reg[IOASIC_UARTCONTROL] & 0x200) {
1117 m_reg[IOASIC_UARTIN] = data | 0x3000;
1118 update_ioasic_irq();
1119 }
1120
1121 }
1122
write(offs_t offset,uint32_t data,uint32_t mem_mask)1123 void midway_ioasic_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
1124 {
1125 uint32_t oldreg, newreg;
1126
1127 offset = m_shuffle_active ? m_shuffle_map[offset & 15] : offset;
1128 oldreg = m_reg[offset];
1129 // Block register updates until ioasic is unlocked
1130 // mwskins and thegrid use this as test to see if the ioasic is unlocked
1131 if (m_shuffle_active)
1132 COMBINE_DATA(&m_reg[offset]);
1133 newreg = m_reg[offset];
1134
1135 if (LOG_IOASIC && offset != IOASIC_SOUNDOUT)
1136 logerror("%s ioasic_w(%d) = %08X\n", machine().describe_context(), offset, data);
1137
1138 switch (offset)
1139 {
1140 case IOASIC_PORT0:
1141 /* the last write here seems to turn on shuffling */
1142 if (data == 0xe2)
1143 {
1144 m_shuffle_active = 1;
1145 logerror("*** I/O ASIC unlocked!\n");
1146 m_reg[IOASIC_INTCTL] = 0;
1147 m_reg[IOASIC_UARTCONTROL] = 0; /* bug in 10th Degree assumes this */
1148 }
1149 break;
1150
1151 case IOASIC_PORT2:
1152 case IOASIC_PORT3:
1153 /* ignore writes here if we're not shuffling yet */
1154 if (!m_shuffle_active)
1155 break;
1156 break;
1157
1158 case IOASIC_UARTCONTROL:
1159 logerror("%s: IOASIC uart control = %04X INTCTRL=%04x\n", machine().describe_context(), data, m_reg[IOASIC_INTCTL]);
1160 break;
1161
1162 case IOASIC_UARTOUT:
1163 if (m_reg[IOASIC_UARTCONTROL] & 0x800)
1164 {
1165 /* we're in loopback mode -- copy to the input */
1166 m_reg[IOASIC_UARTIN] = (newreg & 0x00ff) | 0x3000;
1167 update_ioasic_irq();
1168 }
1169 else {
1170 m_serial_tx_cb(data);
1171 m_reg[IOASIC_UARTIN] |= 0x2000;
1172 update_ioasic_irq();
1173 if (PRINTF_DEBUG) {
1174 osd_printf_info("%c", data & 0xff);
1175 logerror("%c", data & 0xff);
1176 }
1177 }
1178 //logerror("IOASIC uart tx data = %04X\n", data);
1179 break;
1180
1181 case IOASIC_SOUNDCTL:
1182 if (LOG_IOASIC)
1183 logerror("%s: write IOASIC_SOUNDCTL=%04x\n", machine().describe_context(), data);
1184 /* sound reset? */
1185 if (m_has_dcs)
1186 {
1187 m_dcs->reset_w(newreg & 1);
1188 }
1189 else if (m_has_cage)
1190 {
1191 if ((oldreg ^ newreg) & 1)
1192 {
1193 m_cage->control_w(0);
1194 if (!(~newreg & 1))
1195 m_cage->control_w(3);
1196 }
1197 }
1198
1199 /* FIFO reset? */
1200 fifo_reset_w(~newreg & 4);
1201 break;
1202
1203 case IOASIC_SOUNDOUT:
1204 if (m_has_dcs)
1205 m_dcs->data_w(newreg);
1206 else if (m_has_cage)
1207 m_cage->main_w(newreg);
1208 break;
1209
1210 case IOASIC_SOUNDIN:
1211 m_dcs->ack_w();
1212 /* acknowledge data read */
1213 break;
1214
1215 case IOASIC_PICOUT:
1216 if (m_shuffle_type == MIDWAY_IOASIC_VAPORTRX)
1217 midway_serial_pic2_device::write(newreg ^ 0x0a);
1218 else if (m_shuffle_type == MIDWAY_IOASIC_SFRUSHRK)
1219 midway_serial_pic2_device::write(newreg ^ 0x05);
1220 else
1221 midway_serial_pic2_device::write(newreg);
1222 break;
1223
1224 case IOASIC_PICIN:
1225 /* This is P15 on vegas boards */
1226 if (!m_aux_output_cb.isnull())
1227 m_aux_output_cb(data);
1228 break;
1229
1230 case IOASIC_INTCTL:
1231 /* interrupt enables */
1232 /* bit 0 = global interrupt enable */
1233 /* bit 3 = FIFO empty */
1234 /* bit 6 = sound input buffer full */
1235 /* bit 7 = sound output buffer empty */
1236 /* bit 14 = LED */
1237 /* bit 15 = TI320Cx Mode Enable */
1238 if (LOG_IOASIC && ((oldreg ^ newreg) & 0x3ff6))
1239 logerror("IOASIC interrupt control = %04X\n", data);
1240 update_ioasic_irq();
1241 break;
1242
1243 default:
1244 break;
1245 }
1246 }
1247