trunk/src/mess/machine/isa_sblaster.c
| r20624 | r20625 | |
| 44 | 44 | -1, -1, -1, -1, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, /* 0x */ |
| 45 | 45 | 2, -1, -1, -1, 3, -1, 3, 3, -1, -1, -1, -1, 1, -1, -1, 1, /* 1x */ |
| 46 | 46 | -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 2x */ |
| 47 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 3x */ |
| 47 | 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, /* 3x */ |
| 48 | 48 | 2, 3, 3, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, /* 4x */ |
| 49 | 49 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 5x */ |
| 50 | 50 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 6x */ |
| r20624 | r20625 | |
| 71 | 71 | NULL |
| 72 | 72 | }; |
| 73 | 73 | |
| 74 | static SLOT_INTERFACE_START(midiout_slot) |
| 75 | SLOT_INTERFACE("midiout", MIDIOUT_PORT) |
| 76 | SLOT_INTERFACE_END |
| 77 | |
| 78 | static const serial_port_interface midiout_intf = |
| 79 | { |
| 80 | DEVCB_NULL // midi out ports don't transmit inward |
| 81 | }; |
| 82 | |
| 74 | 83 | static MACHINE_CONFIG_FRAGMENT( sblaster1_0_config ) |
| 75 | 84 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") |
| 76 | 85 | MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock) |
| r20624 | r20625 | |
| 90 | 99 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) |
| 91 | 100 | |
| 92 | 101 | MCFG_PC_JOY_ADD("joy") |
| 102 | MCFG_SERIAL_PORT_ADD("mdout", midiout_intf, midiout_slot, "midiout", NULL) |
| 93 | 103 | MACHINE_CONFIG_END |
| 94 | 104 | |
| 95 | 105 | static MACHINE_CONFIG_FRAGMENT( sblaster1_5_config ) |
| r20624 | r20625 | |
| 106 | 116 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) |
| 107 | 117 | |
| 108 | 118 | MCFG_PC_JOY_ADD("joy") |
| 119 | MCFG_SERIAL_PORT_ADD("mdout", midiout_intf, midiout_slot, "midiout", NULL) |
| 109 | 120 | MACHINE_CONFIG_END |
| 110 | 121 | |
| 111 | 122 | static MACHINE_CONFIG_FRAGMENT( sblaster_16_config ) |
| r20624 | r20625 | |
| 122 | 133 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) |
| 123 | 134 | |
| 124 | 135 | MCFG_PC_JOY_ADD("joy") |
| 136 | MCFG_SERIAL_PORT_ADD("mdout", midiout_intf, midiout_slot, "midiout", NULL) |
| 125 | 137 | MACHINE_CONFIG_END |
| 126 | 138 | |
| 127 | 139 | static READ8_DEVICE_HANDLER( ym3812_16_r ) |
| r20624 | r20625 | |
| 225 | 237 | if(offset) |
| 226 | 238 | return; |
| 227 | 239 | |
| 228 | | if(data == 0 && m_dsp.reset_latch == 1) |
| 240 | // a reset while in UART MIDI mode simply restores the previous |
| 241 | // operating state (page 5-3 of the Creative manual). |
| 242 | if (!m_uart_midi) |
| 229 | 243 | { |
| 230 | | // reset routine |
| 231 | | m_dsp.fifo_ptr = 0; |
| 232 | | m_dsp.fifo_r_ptr = 0; |
| 233 | | for(int i=0;i < 15; i++) |
| 244 | if(data == 0 && m_dsp.reset_latch == 1) |
| 234 | 245 | { |
| 235 | | m_dsp.fifo[i] = 0; |
| 236 | | m_dsp.fifo_r[i] = 0; |
| 246 | // reset routine |
| 247 | m_dsp.fifo_ptr = 0; |
| 248 | m_dsp.fifo_r_ptr = 0; |
| 249 | for(int i=0;i < 15; i++) |
| 250 | { |
| 251 | m_dsp.fifo[i] = 0; |
| 252 | m_dsp.fifo_r[i] = 0; |
| 253 | } |
| 254 | queue_r(0xaa); // reset OK ID |
| 237 | 255 | } |
| 238 | | queue_r(0xaa); // reset OK ID |
| 256 | |
| 257 | m_dsp.reset_latch = data; |
| 258 | drq_w(0); |
| 259 | m_dsp.dma_autoinit = 0; |
| 260 | irq_w(0, IRQ_ALL); |
| 261 | m_timer->adjust(attotime::never, 0); |
| 262 | m_dsp.d_rptr = 0; |
| 263 | m_dsp.d_wptr = 0; |
| 264 | m_dsp.dma_throttled = false; |
| 265 | m_dsp.dma_timer_started = false; |
| 239 | 266 | } |
| 240 | 267 | |
| 241 | | m_dsp.reset_latch = data; |
| 242 | | drq_w(0); |
| 243 | | m_dsp.dma_autoinit = 0; |
| 244 | | irq_w(0, IRQ_ALL); |
| 245 | | m_timer->adjust(attotime::never, 0); |
| 246 | | m_dsp.d_rptr = 0; |
| 247 | | m_dsp.d_wptr = 0; |
| 248 | | m_dsp.dma_throttled = false; |
| 249 | | m_dsp.dma_timer_started = false; |
| 268 | m_onebyte_midi = false; |
| 269 | m_uart_midi = false; |
| 270 | m_uart_irq = false; |
| 271 | m_mpu_midi = false; |
| 272 | m_tx_busy = false; |
| 273 | m_xmit_read = m_xmit_write = 0; |
| 274 | m_recv_read = m_recv_write = 0; |
| 250 | 275 | |
| 251 | 276 | //printf("%02x\n",data); |
| 252 | 277 | } |
| r20624 | r20625 | |
| 257 | 282 | if(offset) |
| 258 | 283 | return 0xff; |
| 259 | 284 | |
| 285 | if (m_uart_midi) |
| 286 | { |
| 287 | UINT8 rv = m_recvring[m_recv_read]; |
| 288 | |
| 289 | // only advance the read pointer if the ring wasn't empty |
| 290 | if (m_recv_read != m_xmit_read) |
| 291 | { |
| 292 | m_recv_read++; |
| 293 | } |
| 294 | |
| 295 | return rv; |
| 296 | } |
| 297 | |
| 260 | 298 | return dequeue_r(); |
| 261 | 299 | } |
| 262 | 300 | |
| r20624 | r20625 | |
| 282 | 320 | // printf("Clear IRQ5\n"); |
| 283 | 321 | irq_w(0, IRQ_DMA8); // reading this port ACKs the card's IRQ, 8-bit dma only? |
| 284 | 322 | |
| 323 | // in UART MIDI mode, bit 7 indicates if a character is available |
| 324 | // to read. |
| 325 | if (m_uart_midi) |
| 326 | { |
| 327 | if (m_recv_read != m_recv_write) |
| 328 | { |
| 329 | return 0x80; |
| 330 | } |
| 331 | |
| 332 | return 0x00; |
| 333 | } |
| 334 | |
| 285 | 335 | return m_dsp.rbuf_status; |
| 286 | 336 | } |
| 287 | 337 | |
| r20624 | r20625 | |
| 363 | 413 | logerror("SB: ADC capture unimplemented\n"); |
| 364 | 414 | break; |
| 365 | 415 | |
| 416 | case 0x34: |
| 417 | m_uart_midi = true; |
| 418 | m_uart_irq = true; |
| 419 | break; |
| 420 | |
| 421 | case 0x35: |
| 422 | m_uart_midi = true; |
| 423 | m_uart_irq = false; |
| 424 | break; |
| 425 | |
| 426 | case 0x36: |
| 427 | case 0x37: // Enter UART mode |
| 428 | printf("timestamp MIDI mode not supported, contact MESSDEV!\n"); |
| 429 | break; |
| 430 | |
| 431 | case 0x38: // single-byte MIDI send |
| 432 | m_onebyte_midi = true; |
| 433 | break; |
| 434 | |
| 366 | 435 | case 0x40: // set time constant |
| 367 | 436 | m_dsp.frequency = (1000000 / (256 - m_dsp.fifo[1])); |
| 368 | 437 | //printf("Set time constant: %02x -> %d\n", m_dsp.fifo[1], m_dsp.frequency); |
| r20624 | r20625 | |
| 609 | 678 | |
| 610 | 679 | WRITE8_MEMBER(sb_device::dsp_cmd_w) |
| 611 | 680 | { |
| 612 | | // printf("%02x to DSP command @ %x\n", data, offset); |
| 681 | // printf("%02x to DSP command @ %x\n", data, offset); |
| 613 | 682 | |
| 614 | 683 | if(offset) |
| 615 | 684 | return; |
| 616 | 685 | |
| 686 | if (m_uart_midi || m_onebyte_midi) |
| 687 | { |
| 688 | xmit_char(data); |
| 689 | m_onebyte_midi = false; // clear onebyte (if this is uart, that's harmless) |
| 690 | return; |
| 691 | } |
| 692 | |
| 617 | 693 | queue(data); |
| 618 | 694 | |
| 619 | 695 | process_fifo(m_dsp.fifo[0]); |
| r20624 | r20625 | |
| 698 | 774 | if(offset == 0) // data |
| 699 | 775 | { |
| 700 | 776 | logerror("SB MPU401:%02x %02x\n",offset,data); |
| 777 | if (m_mpu_midi) |
| 778 | { |
| 779 | xmit_char(data); |
| 780 | } |
| 701 | 781 | } |
| 702 | 782 | else // command |
| 703 | 783 | { |
| r20624 | r20625 | |
| 705 | 785 | |
| 706 | 786 | switch(data) |
| 707 | 787 | { |
| 788 | case 0x3f: // enter MPU-401 UART mode |
| 789 | irq_w(1, IRQ_MPU); |
| 790 | m_head = m_tail = 0; |
| 791 | m_mpu_queue[m_head++] = 0xfe; |
| 792 | m_mpu_midi = true; |
| 793 | break; |
| 794 | |
| 708 | 795 | case 0xff: // reset |
| 709 | 796 | irq_w(1, IRQ_MPU); |
| 710 | 797 | m_head = m_tail = 0; |
| 711 | 798 | m_mpu_queue[m_head++] = 0xfe; |
| 799 | m_mpu_midi = false; |
| 712 | 800 | break; |
| 713 | 801 | } |
| 714 | 802 | } |
| r20624 | r20625 | |
| 988 | 1076 | |
| 989 | 1077 | sb_device::sb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name) : |
| 990 | 1078 | device_t(mconfig, type, name, tag, owner, clock), |
| 1079 | device_serial_interface(mconfig, *this), |
| 991 | 1080 | m_dacl(*this, "sbdacl"), |
| 992 | 1081 | m_dacr(*this, "sbdacr"), |
| 993 | | m_joy(*this, "joy") |
| 1082 | m_joy(*this, "joy"), |
| 1083 | m_mdout(*this, "mdout") |
| 994 | 1084 | { |
| 995 | 1085 | } |
| 996 | 1086 | |
| r20624 | r20625 | |
| 1116 | 1206 | m_dsp.irq_active = 0; |
| 1117 | 1207 | m_dsp.dma_no_irq = false; |
| 1118 | 1208 | mixer_reset(); |
| 1209 | |
| 1210 | // MIDI is 31250 baud, 8-N-1 |
| 1211 | set_rcv_rate(31250); |
| 1212 | set_tra_rate(31250); |
| 1213 | set_data_frame(8, 1, SERIAL_PARITY_NONE); |
| 1119 | 1214 | } |
| 1120 | 1215 | |
| 1121 | 1216 | UINT8 sb_device::dack_r(int line) |
| r20624 | r20625 | |
| 1406 | 1501 | } |
| 1407 | 1502 | } |
| 1408 | 1503 | } |
| 1504 | |
| 1505 | void sb_device::rcv_complete() // Rx completed receiving byte |
| 1506 | { |
| 1507 | receive_register_extract(); |
| 1508 | UINT8 data = get_received_char(); |
| 1509 | |
| 1510 | // in UART MIDI mode, we set the DMA8 IRQ on receiving a character |
| 1511 | if (m_uart_midi) |
| 1512 | { |
| 1513 | m_recvring[m_recv_write++] = data; |
| 1514 | |
| 1515 | // if not polling mode, trigger the DMA8 IRQ |
| 1516 | if (m_uart_irq) |
| 1517 | { |
| 1518 | irq_w(1, IRQ_DMA8); |
| 1519 | } |
| 1520 | } |
| 1521 | } |
| 1522 | |
| 1523 | void sb16_device::rcv_complete() // Rx completed receiving byte |
| 1524 | { |
| 1525 | receive_register_extract(); |
| 1526 | UINT8 data = get_received_char(); |
| 1527 | |
| 1528 | // in UART MIDI mode, we set the DMA8 IRQ on receiving a character |
| 1529 | if (m_uart_midi) |
| 1530 | { |
| 1531 | m_recvring[m_recv_write++] = data; |
| 1532 | irq_w(1, IRQ_DMA8); |
| 1533 | } |
| 1534 | |
| 1535 | // in MPU MIDI mode, do this instead |
| 1536 | if (m_mpu_midi) |
| 1537 | { |
| 1538 | m_mpu_queue[m_head++] = data; |
| 1539 | if (m_head >= 16) |
| 1540 | { |
| 1541 | m_head = 0; |
| 1542 | } |
| 1543 | irq_w(1, IRQ_MPU); |
| 1544 | } |
| 1545 | } |
| 1546 | |
| 1547 | void sb_device::tra_complete() // Tx completed sending byte |
| 1548 | { |
| 1549 | // printf("Tx complete\n"); |
| 1550 | // is there more waiting to send? |
| 1551 | if (m_xmit_read != m_xmit_write) |
| 1552 | { |
| 1553 | transmit_register_setup(m_xmitring[m_xmit_read++]); |
| 1554 | if (m_xmit_read >= MIDI_RING_SIZE) |
| 1555 | { |
| 1556 | m_xmit_read = 0; |
| 1557 | } |
| 1558 | } |
| 1559 | else |
| 1560 | { |
| 1561 | m_tx_busy = false; |
| 1562 | } |
| 1563 | } |
| 1564 | |
| 1565 | void sb_device::tra_callback() // Tx send bit |
| 1566 | { |
| 1567 | int bit = transmit_register_get_data_bit(); |
| 1568 | m_mdout->tx(bit); |
| 1569 | } |
| 1570 | |
| 1571 | void sb_device::xmit_char(UINT8 data) |
| 1572 | { |
| 1573 | // printf("SB: xmit %02x\n", data); |
| 1574 | |
| 1575 | // if tx is busy it'll pick this up automatically when it completes |
| 1576 | if (!m_tx_busy) |
| 1577 | { |
| 1578 | m_tx_busy = true; |
| 1579 | transmit_register_setup(data); |
| 1580 | } |
| 1581 | else |
| 1582 | { |
| 1583 | // tx is busy, it'll pick this up next time |
| 1584 | m_xmitring[m_xmit_write++] = data; |
| 1585 | if (m_xmit_write >= MIDI_RING_SIZE) |
| 1586 | { |
| 1587 | m_xmit_write = 0; |
| 1588 | } |
| 1589 | |
| 1590 | if (m_xmit_write == m_xmit_read) |
| 1591 | { |
| 1592 | printf("Overflow xmitring!\n"); |
| 1593 | } |
| 1594 | } |
| 1595 | } |
| 1596 | |