trunk/src/emu/machine/n68681.c
| r20112 | r20113 | |
| 23 | 23 | "MRA", "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" |
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | static const int baud_rate_ACR_0[] = { 50, 110, 134, 200, 300, 600, 1200, 1050, 2400, 4800, 7200, 9600, 38400, 0, 0, 0 }; |
| 27 | static const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000, 2400, 4800, 1800, 9600, 19200, 0, 0, 0 }; |
| 28 | |
| 26 | 29 | #define INT_INPUT_PORT_CHANGE 0x80 |
| 27 | 30 | #define INT_DELTA_BREAK_B 0x40 |
| 28 | 31 | #define INT_RXRDY_FFULLB 0x20 |
| r20112 | r20113 | |
| 43 | 46 | |
| 44 | 47 | #define MODE_RX_INT_SELECT_BIT 0x40 |
| 45 | 48 | |
| 49 | #define CHANA_TAG "cha" |
| 50 | #define CHANB_TAG "chb" |
| 51 | |
| 46 | 52 | // device type definition |
| 47 | 53 | const device_type DUARTN68681 = &device_creator<duartn68681_device>; |
| 54 | const device_type DUART68681CHANNEL = &device_creator<duart68681_channel>; |
| 48 | 55 | |
| 56 | MACHINE_CONFIG_FRAGMENT( duart68681 ) |
| 57 | MCFG_DUART68681_CHANNEL_ADD(CHANA_TAG) |
| 58 | MCFG_DUART68681_CHANNEL_ADD(CHANB_TAG) |
| 59 | MACHINE_CONFIG_END |
| 60 | |
| 49 | 61 | //************************************************************************** |
| 50 | 62 | // LIVE DEVICE |
| 51 | 63 | //************************************************************************** |
| 52 | 64 | |
| 53 | 65 | duartn68681_device::duartn68681_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 54 | 66 | : device_t(mconfig, DUARTN68681, "DUART 68681 (new)", tag, owner, clock), |
| 55 | | device_serial_interface(mconfig, *this) |
| 67 | m_chanA(*this, CHANA_TAG), |
| 68 | m_chanB(*this, CHANB_TAG) |
| 56 | 69 | { |
| 57 | 70 | } |
| 58 | 71 | |
| r20112 | r20113 | |
| 68 | 81 | m_in_port_func.resolve(m_in_port_cb, *this); |
| 69 | 82 | m_out_port_func.resolve(m_out_port_cb, *this); |
| 70 | 83 | |
| 71 | | channel[0].tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(duartn68681_device::tx_timer_callback),this), NULL); |
| 72 | | channel[1].tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(duartn68681_device::tx_timer_callback),this), NULL); |
| 73 | 84 | duart_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(duartn68681_device::duart_timer_callback),this), NULL); |
| 74 | 85 | |
| 75 | 86 | save_item(NAME(ACR)); |
| r20112 | r20113 | |
| 80 | 91 | save_item(NAME(CTR)); |
| 81 | 92 | save_item(NAME(IP_last_state)); |
| 82 | 93 | save_item(NAME(half_period)); |
| 83 | | |
| 84 | | save_item(NAME(channel[0].CR)); |
| 85 | | save_item(NAME(channel[0].CSR)); |
| 86 | | save_item(NAME(channel[0].MR1)); |
| 87 | | save_item(NAME(channel[0].MR2)); |
| 88 | | save_item(NAME(channel[0].MR_ptr)); |
| 89 | | save_item(NAME(channel[0].SR)); |
| 90 | | save_item(NAME(channel[0].baud_rate)); |
| 91 | | save_item(NAME(channel[0].rx_enabled)); |
| 92 | | save_item(NAME(channel[0].rx_fifo)); |
| 93 | | save_item(NAME(channel[0].rx_fifo_read_ptr)); |
| 94 | | save_item(NAME(channel[0].rx_fifo_write_ptr)); |
| 95 | | save_item(NAME(channel[0].rx_fifo_num)); |
| 96 | | save_item(NAME(channel[0].tx_enabled)); |
| 97 | | save_item(NAME(channel[0].tx_data)); |
| 98 | | save_item(NAME(channel[0].tx_ready)); |
| 99 | | |
| 100 | | save_item(NAME(channel[1].CR)); |
| 101 | | save_item(NAME(channel[1].CSR)); |
| 102 | | save_item(NAME(channel[1].MR1)); |
| 103 | | save_item(NAME(channel[1].MR2)); |
| 104 | | save_item(NAME(channel[1].MR_ptr)); |
| 105 | | save_item(NAME(channel[1].SR)); |
| 106 | | save_item(NAME(channel[1].baud_rate)); |
| 107 | | save_item(NAME(channel[1].rx_enabled)); |
| 108 | | save_item(NAME(channel[1].rx_fifo)); |
| 109 | | save_item(NAME(channel[1].rx_fifo_read_ptr)); |
| 110 | | save_item(NAME(channel[1].rx_fifo_write_ptr)); |
| 111 | | save_item(NAME(channel[1].rx_fifo_num)); |
| 112 | | save_item(NAME(channel[1].tx_enabled)); |
| 113 | | save_item(NAME(channel[1].tx_data)); |
| 114 | | save_item(NAME(channel[1].tx_ready)); |
| 115 | 94 | } |
| 116 | 95 | |
| 117 | 96 | /*------------------------------------------------- |
| r20112 | r20113 | |
| 120 | 99 | |
| 121 | 100 | void duartn68681_device::device_reset() |
| 122 | 101 | { |
| 123 | | emu_timer *save0, *save1; |
| 124 | | |
| 125 | 102 | ACR = 0; /* Interrupt Vector Register */ |
| 126 | 103 | IVR = 0x0f; /* Interrupt Vector Register */ |
| 127 | 104 | IMR = 0; /* Interrupt Mask Register */ |
| r20112 | r20113 | |
| 131 | 108 | CTR.d = 0; /* Counter/Timer Preset Value */ |
| 132 | 109 | IP_last_state = 0; /* last state of IP bits */ |
| 133 | 110 | // "reset clears internal registers (SRA, SRB, IMR, ISR, OPR, OPCR) puts OP0-7 in the high state, stops the counter/timer, and puts channels a/b in the inactive state" |
| 134 | | save0 = channel[0].tx_timer; |
| 135 | | save1 = channel[1].tx_timer; |
| 136 | | memset(channel, 0, sizeof(channel)); |
| 137 | | channel[0].tx_timer = save0; |
| 138 | | channel[1].tx_timer = save1; |
| 139 | 111 | |
| 140 | 112 | m_out_port_func(0, OPR ^ 0xff); |
| 141 | | |
| 142 | | // reset timers |
| 143 | | channel[0].tx_timer->adjust(attotime::never); |
| 144 | | channel[1].tx_timer->adjust(attotime::never, 1); |
| 145 | 113 | } |
| 146 | 114 | |
| 147 | 115 | //------------------------------------------------- |
| r20112 | r20113 | |
| 171 | 139 | } |
| 172 | 140 | } |
| 173 | 141 | |
| 142 | machine_config_constructor duartn68681_device::device_mconfig_additions() const |
| 143 | { |
| 144 | return MACHINE_CONFIG_NAME( duart68681 ); |
| 145 | } |
| 146 | |
| 174 | 147 | void duartn68681_device::update_interrupts() |
| 175 | 148 | { |
| 176 | 149 | /* update SR state and update interrupt ISR state for the following bits: |
| r20112 | r20113 | |
| 188 | 161 | ISR: bit 1: RxRDYA/FFULLA: this is handled here; depending on whether MSR1A bit 6 is 0 or 1, this bit holds the state of SRA bit 0 or bit 1 respectively |
| 189 | 162 | ISR: bit 0: TxRDYA: this is handled here; it mirrors SRA bit 2 |
| 190 | 163 | */ |
| 191 | | UINT8 ch = 0; |
| 192 | | //logerror("DEBUG: 68681 int check: upon func call, SRA is %02X, SRB is %02X, ISR is %02X\n", duart68681->channel[0].SR, duart68681->channel[1].SR, duart68681->ISR); |
| 193 | | for (ch = 0; ch < 2; ch++) |
| 194 | | { |
| 195 | | //if ( duart68681->channel[ch].rx_enabled ) |
| 196 | | //{ |
| 197 | | if ( channel[ch].rx_fifo_num > 0 ) |
| 198 | | { |
| 199 | | channel[ch].SR |= STATUS_RECEIVER_READY; |
| 200 | | } |
| 201 | | else |
| 202 | | { |
| 203 | | channel[ch].SR &= ~STATUS_RECEIVER_READY; |
| 204 | | } |
| 205 | | if ( channel[ch].rx_fifo_num == MC68681_RX_FIFO_SIZE ) |
| 206 | | { |
| 207 | | channel[ch].SR |= STATUS_FIFO_FULL; |
| 208 | | } |
| 209 | | else |
| 210 | | { |
| 211 | | channel[ch].SR &= ~STATUS_FIFO_FULL; |
| 212 | | } |
| 213 | | //} |
| 214 | | //else |
| 215 | | //{ |
| 216 | | //duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY; |
| 217 | | //duart68681->channel[ch].SR &= ~STATUS_FIFO_FULL; |
| 218 | | //} |
| 219 | | // Handle the TxEMT and TxRDY bits based on mode |
| 220 | | switch( channel[ch].MR2&0xC0) // what mode are we in? |
| 221 | | { |
| 222 | | case 0x00: // normal mode |
| 223 | | if ( channel[ch].tx_enabled ) |
| 224 | | { |
| 225 | | channel[ch].SR |= STATUS_TRANSMITTER_EMPTY; |
| 226 | | } |
| 227 | | else |
| 228 | | { |
| 229 | | channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 230 | | } |
| 231 | | break; |
| 232 | | case 0x40: // automatic echo mode |
| 233 | | channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 234 | | channel[ch].SR &= ~STATUS_TRANSMITTER_READY; |
| 235 | | break; |
| 236 | | case 0x80: // local loopback mode |
| 237 | | if ( channel[ch].tx_enabled ) |
| 238 | | { |
| 239 | | channel[ch].SR |= STATUS_TRANSMITTER_EMPTY; |
| 240 | | } |
| 241 | | else |
| 242 | | { |
| 243 | | channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 244 | | } |
| 245 | | break; |
| 246 | | case 0xC0: // remote loopback mode |
| 247 | | // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both |
| 248 | | channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 249 | | channel[ch].SR &= ~STATUS_TRANSMITTER_READY; |
| 250 | | break; |
| 251 | | } |
| 252 | | // now handle the ISR bits |
| 253 | | if ( channel[ch].SR & STATUS_TRANSMITTER_READY ) |
| 254 | | { |
| 255 | | if (ch == 0) |
| 256 | | ISR |= INT_TXRDYA; |
| 257 | | else |
| 258 | | ISR |= INT_TXRDYB; |
| 259 | | } |
| 260 | | else |
| 261 | | { |
| 262 | | if (ch == 0) |
| 263 | | ISR &= ~INT_TXRDYA; |
| 264 | | else |
| 265 | | ISR &= ~INT_TXRDYB; |
| 266 | | } |
| 267 | | //logerror("DEBUG: 68681 int check: before receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); |
| 268 | | if ( channel[ch].MR1 & MODE_RX_INT_SELECT_BIT ) |
| 269 | | { |
| 270 | | if ( channel[ch].SR & STATUS_FIFO_FULL ) |
| 271 | | { |
| 272 | | ISR |= ((ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 273 | | } |
| 274 | | else |
| 275 | | { |
| 276 | | ISR &= ((ch == 0) ? ~INT_RXRDY_FFULLA : ~INT_RXRDY_FFULLB); |
| 277 | | } |
| 278 | | } |
| 279 | | else |
| 280 | | { |
| 281 | | if ( channel[ch].SR & STATUS_RECEIVER_READY ) |
| 282 | | { |
| 283 | | ISR |= ((ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 284 | | } |
| 285 | | else |
| 286 | | { |
| 287 | | ISR &= ((ch == 0) ? ~INT_RXRDY_FFULLA : ~INT_RXRDY_FFULLB); |
| 288 | | } |
| 289 | | } |
| 290 | | //logerror("DEBUG: 68681 int check: after receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); |
| 291 | | } |
| 292 | 164 | if ( (ISR & IMR) != 0 ) |
| 293 | 165 | { |
| 294 | 166 | LOG(( "68681: Interrupt line active (IMR & ISR = %02X)\n", (ISR & IMR) )); |
| r20112 | r20113 | |
| 383 | 255 | |
| 384 | 256 | }; |
| 385 | 257 | |
| 386 | | void duartn68681_device::duart68681_write_MR(int ch, UINT8 data) |
| 387 | | { |
| 388 | | if ( channel[ch].MR_ptr == 0 ) |
| 389 | | { |
| 390 | | channel[ch].MR1 = data; |
| 391 | | channel[ch].MR_ptr = 1; |
| 392 | | } |
| 393 | | else |
| 394 | | { |
| 395 | | channel[ch].MR2 = data; |
| 396 | | } |
| 397 | | update_interrupts(); |
| 398 | | }; |
| 399 | | |
| 400 | | void duartn68681_device::duart68681_write_CSR(int ch, UINT8 data, UINT8 inACR) |
| 401 | | { |
| 402 | | static const int baud_rate_ACR_0[] = { 50, 110, 134, 200, 300, 600, 1200, 1050, 2400, 4800, 7200, 9600, 38400, 0, 0, 0 }; |
| 403 | | static const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000, 2400, 4800, 1800, 9600, 19200, 0, 0, 0 }; |
| 404 | | |
| 405 | | channel[ch].CSR = data; |
| 406 | | |
| 407 | | if ( BIT(inACR,7) == 0 ) |
| 408 | | { |
| 409 | | channel[ch].baud_rate = baud_rate_ACR_0[data & 0x0f]; |
| 410 | | |
| 411 | | if (ch == 0) |
| 412 | | { |
| 413 | | if ((data & 0xf) == 0xe) |
| 414 | | { |
| 415 | | channel[ch].baud_rate = ip3clk/16; |
| 416 | | } |
| 417 | | else if ((data & 0xf) == 0xf) |
| 418 | | { |
| 419 | | channel[ch].baud_rate = ip3clk; |
| 420 | | } |
| 421 | | } |
| 422 | | else if (ch == 1) |
| 423 | | { |
| 424 | | if ((data & 0xf) == 0xe) |
| 425 | | { |
| 426 | | channel[ch].baud_rate = ip5clk/16; |
| 427 | | } |
| 428 | | else if ((data & 0xf) == 0xf) |
| 429 | | { |
| 430 | | channel[ch].baud_rate = ip5clk; |
| 431 | | } |
| 432 | | } |
| 433 | | } |
| 434 | | else |
| 435 | | { |
| 436 | | channel[ch].baud_rate = baud_rate_ACR_1[data & 0x0f]; |
| 437 | | } |
| 438 | | if ( channel[ch].baud_rate == 0 ) |
| 439 | | { |
| 440 | | LOG(( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data )); |
| 441 | | } |
| 442 | | }; |
| 443 | | |
| 444 | | void duartn68681_device::duart68681_write_CR(int ch, UINT8 data) |
| 445 | | { |
| 446 | | channel[ch].CR = data; |
| 447 | | |
| 448 | | switch( (data >> 4) & 0x07 ) |
| 449 | | { |
| 450 | | case 0: /* No command */ |
| 451 | | break; |
| 452 | | case 1: /* Reset MR pointer. Causes the Channel A MR pointer to point to MR1 */ |
| 453 | | channel[ch].MR_ptr = 0; |
| 454 | | break; |
| 455 | | case 2: /* Reset channel A receiver (disable receiver and flush fifo) */ |
| 456 | | channel[ch].rx_enabled = 0; |
| 457 | | channel[ch].SR &= ~STATUS_RECEIVER_READY; |
| 458 | | channel[ch].SR &= ~STATUS_OVERRUN_ERROR; // is this correct? |
| 459 | | channel[ch].rx_fifo_read_ptr = 0; |
| 460 | | channel[ch].rx_fifo_write_ptr = 0; |
| 461 | | channel[ch].rx_fifo_num = 0; |
| 462 | | break; |
| 463 | | case 3: /* Reset channel A transmitter */ |
| 464 | | channel[ch].tx_enabled = 0; |
| 465 | | channel[ch].SR &= ~STATUS_TRANSMITTER_READY; |
| 466 | | if (ch == 0) |
| 467 | | ISR &= ~INT_TXRDYA; |
| 468 | | else |
| 469 | | ISR &= ~INT_TXRDYB; |
| 470 | | channel[ch].tx_timer->adjust(attotime::never, ch); |
| 471 | | break; |
| 472 | | case 4: /* Reset Error Status */ |
| 473 | | channel[ch].SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR); |
| 474 | | break; |
| 475 | | case 5: /* Reset Channel break change interrupt */ |
| 476 | | if ( ch == 0 ) |
| 477 | | { |
| 478 | | ISR &= ~INT_DELTA_BREAK_A; |
| 479 | | } |
| 480 | | else |
| 481 | | { |
| 482 | | ISR &= ~INT_DELTA_BREAK_B; |
| 483 | | } |
| 484 | | break; |
| 485 | | /* TODO: case 6 and case 7 are start break and stop break respectively, which start or stop holding the TxDA or TxDB line low (space) after whatever data is in the buffer finishes transmitting (following the stop bit?), or after two bit-times if no data is being transmitted */ |
| 486 | | default: |
| 487 | | LOG(( "68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, ch )); |
| 488 | | break; |
| 489 | | } |
| 490 | | |
| 491 | | if (BIT(data, 0)) { |
| 492 | | channel[ch].rx_enabled = 1; |
| 493 | | } |
| 494 | | if (BIT(data, 1)) { |
| 495 | | channel[ch].rx_enabled = 0; |
| 496 | | channel[ch].SR &= ~STATUS_RECEIVER_READY; |
| 497 | | } |
| 498 | | |
| 499 | | if (BIT(data, 2)) { |
| 500 | | channel[ch].tx_enabled = 1; |
| 501 | | channel[ch].tx_ready = 1; |
| 502 | | channel[ch].SR |= STATUS_TRANSMITTER_READY; |
| 503 | | if (ch == 0) |
| 504 | | ISR |= INT_TXRDYA; |
| 505 | | else |
| 506 | | ISR |= INT_TXRDYB; |
| 507 | | } |
| 508 | | if (BIT(data, 3)) { |
| 509 | | channel[ch].tx_enabled = 0; |
| 510 | | channel[ch].tx_ready = 0; |
| 511 | | channel[ch].SR &= ~STATUS_TRANSMITTER_READY; |
| 512 | | if (ch == 0) |
| 513 | | ISR &= ~INT_TXRDYA; |
| 514 | | else |
| 515 | | ISR &= ~INT_TXRDYB; |
| 516 | | } |
| 517 | | |
| 518 | | update_interrupts(); |
| 519 | | }; |
| 520 | | |
| 521 | | UINT8 duartn68681_device::duart68681_read_rx_fifo(int ch) |
| 522 | | { |
| 523 | | UINT8 r; |
| 524 | | |
| 525 | | if ( channel[ch].rx_fifo_num == 0 ) |
| 526 | | { |
| 527 | | LOG(( "68681: rx fifo underflow\n" )); |
| 528 | | return 0x0; |
| 529 | | } |
| 530 | | |
| 531 | | r = channel[ch].rx_fifo[channel[ch].rx_fifo_read_ptr++]; |
| 532 | | if ( channel[ch].rx_fifo_read_ptr == MC68681_RX_FIFO_SIZE ) |
| 533 | | { |
| 534 | | channel[ch].rx_fifo_read_ptr = 0; |
| 535 | | } |
| 536 | | |
| 537 | | channel[ch].rx_fifo_num--; |
| 538 | | update_interrupts(); |
| 539 | | |
| 540 | | return r; |
| 541 | | }; |
| 542 | | |
| 543 | | TIMER_CALLBACK_MEMBER( duartn68681_device::tx_timer_callback ) |
| 544 | | { |
| 545 | | int ch = param & 1; |
| 546 | | |
| 547 | | // send the byte unless we're in loopback mode; |
| 548 | | // in loopback mode do NOT 'actually' send the byte: the TXn pin is held high when loopback mode is on. |
| 549 | | if ((channel[ch].MR2&0xC0) != 0x80) |
| 550 | | { |
| 551 | | if (ch == 0) |
| 552 | | { |
| 553 | | m_out_a_tx_func(0, channel[0].tx_data); |
| 554 | | } |
| 555 | | else if (ch == 1) |
| 556 | | { |
| 557 | | m_out_b_tx_func(0, channel[1].tx_data); |
| 558 | | } |
| 559 | | } |
| 560 | | |
| 561 | | // if local loopback is on, write the transmitted data as if a byte had been received |
| 562 | | if ((channel[ch].MR2 & 0xC0) == 0x80) |
| 563 | | { |
| 564 | | if (channel[ch].rx_fifo_num >= MC68681_RX_FIFO_SIZE) |
| 565 | | { |
| 566 | | LOG(( "68681: FIFO overflow\n" )); |
| 567 | | channel[ch].SR |= STATUS_OVERRUN_ERROR; |
| 568 | | } |
| 569 | | else |
| 570 | | { |
| 571 | | channel[ch].rx_fifo[channel[ch].rx_fifo_write_ptr++] |
| 572 | | = channel[ch].tx_data; |
| 573 | | if (channel[ch].rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE) |
| 574 | | { |
| 575 | | channel[ch].rx_fifo_write_ptr = 0; |
| 576 | | } |
| 577 | | channel[ch].rx_fifo_num++; |
| 578 | | } |
| 579 | | } |
| 580 | | |
| 581 | | channel[ch].tx_ready = 1; |
| 582 | | channel[ch].SR |= STATUS_TRANSMITTER_READY; |
| 583 | | |
| 584 | | if (ch == 0) |
| 585 | | ISR |= INT_TXRDYA; |
| 586 | | else |
| 587 | | ISR |= INT_TXRDYB; |
| 588 | | |
| 589 | | update_interrupts(); |
| 590 | | channel[ch].tx_timer->adjust(attotime::never, ch); |
| 591 | | }; |
| 592 | | |
| 593 | | void duartn68681_device::duart68681_write_TX(int ch, UINT8 data) |
| 594 | | { |
| 595 | | attotime period; |
| 596 | | |
| 597 | | channel[ch].tx_data = data; |
| 598 | | |
| 599 | | channel[ch].tx_ready = 0; |
| 600 | | channel[ch].SR &= ~STATUS_TRANSMITTER_READY; |
| 601 | | |
| 602 | | if (ch == 0) |
| 603 | | ISR &= ~INT_TXRDYA; |
| 604 | | else |
| 605 | | ISR &= ~INT_TXRDYB; |
| 606 | | |
| 607 | | update_interrupts(); |
| 608 | | |
| 609 | | period = attotime::from_hz(channel[ch].baud_rate / 10 ); |
| 610 | | channel[ch].tx_timer->adjust(period, ch); |
| 611 | | }; |
| 612 | | |
| 613 | 258 | READ8_MEMBER( duartn68681_device::read ) |
| 614 | 259 | { |
| 615 | 260 | UINT8 r = 0xff; |
| r20112 | r20113 | |
| 621 | 266 | switch (offset) |
| 622 | 267 | { |
| 623 | 268 | case 0x00: /* MR1A/MR2A */ |
| 624 | | if ( channel[0].MR_ptr == 0 ) |
| 625 | | { |
| 626 | | r = channel[0].MR1; |
| 627 | | channel[0].MR_ptr = 1; |
| 628 | | } |
| 629 | | else |
| 630 | | { |
| 631 | | r = channel[0].MR2; |
| 632 | | } |
| 633 | | break; |
| 634 | | |
| 635 | 269 | case 0x01: /* SRA */ |
| 636 | | r = channel[0].SR; |
| 637 | | break; |
| 638 | | |
| 639 | 270 | case 0x03: /* Rx Holding Register A */ |
| 640 | | r = duart68681_read_rx_fifo(0); |
| 271 | r = m_chanA->read_chan_reg(offset & 3); |
| 641 | 272 | break; |
| 642 | 273 | |
| 643 | 274 | case 0x04: /* IPCR */ |
| r20112 | r20113 | |
| 664 | 295 | break; |
| 665 | 296 | |
| 666 | 297 | case 0x08: /* MR1B/MR2B */ |
| 667 | | if ( channel[1].MR_ptr == 0 ) |
| 668 | | { |
| 669 | | r = channel[1].MR1; |
| 670 | | channel[1].MR_ptr = 1; |
| 671 | | } |
| 672 | | else |
| 673 | | { |
| 674 | | r = channel[1].MR2; |
| 675 | | } |
| 676 | | break; |
| 677 | | |
| 678 | 298 | case 0x09: /* SRB */ |
| 679 | | r = channel[1].SR; |
| 680 | | break; |
| 681 | | |
| 682 | 299 | case 0x0b: /* RHRB */ |
| 683 | | r = duart68681_read_rx_fifo(1); |
| 300 | r = m_chanB->read_chan_reg(offset & 3); |
| 684 | 301 | break; |
| 685 | 302 | |
| 686 | 303 | case 0x0d: /* IP */ |
| r20112 | r20113 | |
| 727 | 344 | switch(offset) |
| 728 | 345 | { |
| 729 | 346 | case 0x00: /* MRA */ |
| 730 | | duart68681_write_MR(0, data); |
| 731 | | break; |
| 732 | | |
| 733 | 347 | case 0x01: /* CSRA */ |
| 734 | | duart68681_write_CSR(0, data, ACR); |
| 735 | | break; |
| 736 | | |
| 737 | 348 | case 0x02: /* CRA */ |
| 738 | | duart68681_write_CR(0, data); |
| 739 | | break; |
| 740 | | |
| 741 | 349 | case 0x03: /* THRA */ |
| 742 | | duart68681_write_TX(0, data); |
| 350 | m_chanA->write_chan_reg(offset&3, data); |
| 743 | 351 | break; |
| 744 | 352 | |
| 745 | 353 | case 0x04: /* ACR */ |
| r20112 | r20113 | |
| 767 | 375 | } |
| 768 | 376 | } |
| 769 | 377 | |
| 770 | | duart68681_write_CSR(0, channel[0].CSR, data); |
| 771 | | duart68681_write_CSR(1, channel[1].CSR, data); |
| 772 | | update_interrupts(); // need to add ACR checking for IP delta ints |
| 378 | m_chanA->write_chan_reg(1, data); |
| 379 | m_chanB->write_chan_reg(1, data); |
| 380 | m_chanA->update_interrupts(); // need to add ACR checking for IP delta ints |
| 381 | m_chanB->update_interrupts(); |
| 382 | update_interrupts(); |
| 773 | 383 | break; |
| 774 | 384 | } |
| 775 | 385 | case 0x05: /* IMR */ |
| r20112 | r20113 | |
| 786 | 396 | break; |
| 787 | 397 | |
| 788 | 398 | case 0x08: /* MRB */ |
| 789 | | duart68681_write_MR(1, data); |
| 790 | | break; |
| 791 | | |
| 792 | 399 | case 0x09: /* CSRB */ |
| 793 | | duart68681_write_CSR(1, data, ACR); |
| 794 | | break; |
| 795 | | |
| 796 | 400 | case 0x0a: /* CRB */ |
| 797 | | duart68681_write_CR(1, data); |
| 798 | | break; |
| 799 | | |
| 800 | 401 | case 0x0b: /* THRB */ |
| 801 | | duart68681_write_TX(1, data); |
| 402 | m_chanB->write_chan_reg(offset&3, data); |
| 802 | 403 | break; |
| 803 | 404 | |
| 804 | 405 | case 0x0c: /* IVR */ |
| r20112 | r20113 | |
| 823 | 424 | } |
| 824 | 425 | } |
| 825 | 426 | |
| 826 | | void duartn68681_device::duart68681_rx_data(int ch, UINT8 data) |
| 427 | duart68681_channel *duartn68681_device::get_channel(int chan) |
| 827 | 428 | { |
| 828 | | if ( channel[ch].rx_enabled ) |
| 429 | if (chan == 0) |
| 829 | 430 | { |
| 830 | | if ( channel[ch].rx_fifo_num >= MC68681_RX_FIFO_SIZE ) |
| 431 | return m_chanA; |
| 432 | } |
| 433 | |
| 434 | return m_chanB; |
| 435 | } |
| 436 | |
| 437 | int duartn68681_device::calc_baud(int ch, UINT8 data) |
| 438 | { |
| 439 | int baud_rate = 0; |
| 440 | |
| 441 | if ( BIT(ACR, 7) == 0 ) |
| 442 | { |
| 443 | baud_rate = baud_rate_ACR_0[data & 0x0f]; |
| 444 | |
| 445 | if (ch == 0) |
| 831 | 446 | { |
| 832 | | LOG(( "68681: FIFO overflow\n" )); |
| 833 | | channel[ch].SR |= STATUS_OVERRUN_ERROR; |
| 834 | | return; |
| 447 | if ((data & 0xf) == 0xe) |
| 448 | { |
| 449 | baud_rate = ip3clk/16; |
| 450 | } |
| 451 | else if ((data & 0xf) == 0xf) |
| 452 | { |
| 453 | baud_rate = ip3clk; |
| 454 | } |
| 835 | 455 | } |
| 836 | | channel[ch].rx_fifo[channel[ch].rx_fifo_write_ptr++] = data; |
| 837 | | if ( channel[ch].rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE ) |
| 456 | else if (ch == 1) |
| 838 | 457 | { |
| 839 | | channel[ch].rx_fifo_write_ptr = 0; |
| 458 | if ((data & 0xf) == 0xe) |
| 459 | { |
| 460 | baud_rate = ip5clk/16; |
| 461 | } |
| 462 | else if ((data & 0xf) == 0xf) |
| 463 | { |
| 464 | baud_rate = ip5clk; |
| 465 | } |
| 840 | 466 | } |
| 841 | | channel[ch].rx_fifo_num++; |
| 842 | | update_interrupts(); |
| 843 | 467 | } |
| 468 | else |
| 469 | { |
| 470 | baud_rate = baud_rate_ACR_1[data & 0x0f]; |
| 471 | } |
| 472 | |
| 473 | if ( baud_rate == 0 ) |
| 474 | { |
| 475 | LOG(( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data )); |
| 476 | } |
| 477 | |
| 478 | return baud_rate; |
| 844 | 479 | }; |
| 845 | 480 | |
| 481 | void duartn68681_device::clear_ISR_bits(int mask) |
| 482 | { |
| 483 | ISR &= ~mask; |
| 484 | } |
| 485 | |
| 486 | void duartn68681_device::set_ISR_bits(int mask) |
| 487 | { |
| 488 | ISR |= mask; |
| 489 | } |
| 490 | |
| 491 | // DUART channel class stuff |
| 492 | |
| 493 | duart68681_channel::duart68681_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 494 | : device_t(mconfig, DUART68681CHANNEL, "DUART 68681 channel", tag, owner, clock), |
| 495 | device_serial_interface(mconfig, *this) |
| 496 | { |
| 497 | } |
| 498 | |
| 499 | void duart68681_channel::device_start() |
| 500 | { |
| 501 | m_uart = downcast<duartn68681_device *>(owner()); |
| 502 | m_ch = m_uart->get_ch(this); // get our channel number |
| 503 | |
| 504 | save_item(NAME(CR)); |
| 505 | save_item(NAME(CSR)); |
| 506 | save_item(NAME(MR1)); |
| 507 | save_item(NAME(MR2)); |
| 508 | save_item(NAME(MR_ptr)); |
| 509 | save_item(NAME(SR)); |
| 510 | save_item(NAME(rx_baud_rate)); |
| 511 | save_item(NAME(tx_baud_rate)); |
| 512 | save_item(NAME(rx_enabled)); |
| 513 | save_item(NAME(rx_fifo)); |
| 514 | save_item(NAME(rx_fifo_read_ptr)); |
| 515 | save_item(NAME(rx_fifo_write_ptr)); |
| 516 | save_item(NAME(rx_fifo_num)); |
| 517 | save_item(NAME(tx_enabled)); |
| 518 | save_item(NAME(tx_data)); |
| 519 | save_item(NAME(tx_ready)); |
| 520 | } |
| 521 | |
| 522 | void duart68681_channel::device_reset() |
| 523 | { |
| 524 | write_CR(0x10); // reset MR |
| 525 | write_CR(0x20); // reset Rx |
| 526 | write_CR(0x30); // reset Tx |
| 527 | write_CR(0x40); // reset errors |
| 528 | |
| 529 | tx_baud_rate = rx_baud_rate = 0; |
| 530 | } |
| 531 | |
| 846 | 532 | // serial device virtual overrides |
| 847 | | void duartn68681_device::rcv_complete() |
| 533 | void duart68681_channel::rcv_complete() |
| 848 | 534 | { |
| 535 | receive_register_extract(); |
| 536 | |
| 537 | // printf("ch %d rcv complete\n", m_ch); |
| 538 | |
| 539 | if ( rx_enabled ) |
| 540 | { |
| 541 | if ( rx_fifo_num >= MC68681_RX_FIFO_SIZE ) |
| 542 | { |
| 543 | LOG(( "68681: FIFO overflow\n" )); |
| 544 | SR |= STATUS_OVERRUN_ERROR; |
| 545 | return; |
| 546 | } |
| 547 | rx_fifo[rx_fifo_write_ptr++] = get_received_char(); |
| 548 | if ( rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE ) |
| 549 | { |
| 550 | rx_fifo_write_ptr = 0; |
| 551 | } |
| 552 | rx_fifo_num++; |
| 553 | update_interrupts(); |
| 554 | } |
| 849 | 555 | } |
| 850 | 556 | |
| 851 | | void duartn68681_device::tra_complete() |
| 557 | void duart68681_channel::tra_complete() |
| 852 | 558 | { |
| 559 | // printf("ch %d Tx complete\n", m_ch); |
| 560 | tx_ready = 1; |
| 561 | SR |= STATUS_TRANSMITTER_READY; |
| 562 | |
| 563 | if (m_ch == 0) |
| 564 | m_uart->clear_ISR_bits(INT_TXRDYA); |
| 565 | else |
| 566 | m_uart->clear_ISR_bits(INT_TXRDYB); |
| 567 | |
| 568 | update_interrupts(); |
| 853 | 569 | } |
| 854 | 570 | |
| 855 | | void duartn68681_device::tra_callback() |
| 571 | void duart68681_channel::tra_callback() |
| 856 | 572 | { |
| 573 | int bit = transmit_register_get_data_bit(); |
| 574 | // printf("ch %d transmit %d\n", m_ch, bit); |
| 575 | if (m_ch == 0) |
| 576 | { |
| 577 | m_uart->m_out_a_tx_func(bit); |
| 578 | } |
| 579 | else |
| 580 | { |
| 581 | m_uart->m_out_b_tx_func(bit); |
| 582 | } |
| 857 | 583 | } |
| 858 | 584 | |
| 859 | | void duartn68681_device::input_callback(UINT8 state) |
| 585 | void duart68681_channel::input_callback(UINT8 state) |
| 860 | 586 | { |
| 861 | 587 | } |
| 862 | 588 | |
| 589 | void duart68681_channel::update_interrupts() |
| 590 | { |
| 591 | if ( rx_fifo_num > 0 ) |
| 592 | { |
| 593 | SR |= STATUS_RECEIVER_READY; |
| 594 | } |
| 595 | else |
| 596 | { |
| 597 | SR &= ~STATUS_RECEIVER_READY; |
| 598 | } |
| 599 | if ( rx_fifo_num == MC68681_RX_FIFO_SIZE ) |
| 600 | { |
| 601 | SR |= STATUS_FIFO_FULL; |
| 602 | } |
| 603 | else |
| 604 | { |
| 605 | SR &= ~STATUS_FIFO_FULL; |
| 606 | } |
| 607 | |
| 608 | // Handle the TxEMT and TxRDY bits based on mode |
| 609 | switch(MR2&0xC0) // what mode are we in? |
| 610 | { |
| 611 | case 0x00: // normal mode |
| 612 | if ( tx_enabled ) |
| 613 | { |
| 614 | SR |= STATUS_TRANSMITTER_EMPTY; |
| 615 | } |
| 616 | else |
| 617 | { |
| 618 | SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 619 | } |
| 620 | break; |
| 621 | case 0x40: // automatic echo mode |
| 622 | SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 623 | SR &= ~STATUS_TRANSMITTER_READY; |
| 624 | break; |
| 625 | case 0x80: // local loopback mode |
| 626 | if ( tx_enabled ) |
| 627 | { |
| 628 | SR |= STATUS_TRANSMITTER_EMPTY; |
| 629 | } |
| 630 | else |
| 631 | { |
| 632 | SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 633 | } |
| 634 | break; |
| 635 | case 0xC0: // remote loopback mode |
| 636 | // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both |
| 637 | SR &= ~STATUS_TRANSMITTER_EMPTY; |
| 638 | SR &= ~STATUS_TRANSMITTER_READY; |
| 639 | break; |
| 640 | } |
| 641 | // now handle the ISR bits |
| 642 | if ( SR & STATUS_TRANSMITTER_READY ) |
| 643 | { |
| 644 | if (m_ch == 0) |
| 645 | m_uart->set_ISR_bits(INT_TXRDYA); |
| 646 | else |
| 647 | m_uart->set_ISR_bits(INT_TXRDYB); |
| 648 | } |
| 649 | else |
| 650 | { |
| 651 | if (m_ch == 0) |
| 652 | m_uart->clear_ISR_bits(INT_TXRDYA); |
| 653 | else |
| 654 | m_uart->clear_ISR_bits(INT_TXRDYB); |
| 655 | } |
| 656 | //logerror("DEBUG: 68681 int check: before receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); |
| 657 | if ( MR1 & MODE_RX_INT_SELECT_BIT ) |
| 658 | { |
| 659 | if ( SR & STATUS_FIFO_FULL ) |
| 660 | { |
| 661 | m_uart->set_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 662 | } |
| 663 | else |
| 664 | { |
| 665 | m_uart->clear_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 666 | } |
| 667 | } |
| 668 | else |
| 669 | { |
| 670 | if ( SR & STATUS_RECEIVER_READY ) |
| 671 | { |
| 672 | m_uart->set_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 673 | } |
| 674 | else |
| 675 | { |
| 676 | m_uart->clear_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | m_uart->update_interrupts(); |
| 681 | |
| 682 | //logerror("DEBUG: 68681 int check: after receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); |
| 683 | } |
| 684 | |
| 685 | UINT8 duart68681_channel::read_rx_fifo() |
| 686 | { |
| 687 | UINT8 rv = 0; |
| 688 | |
| 689 | // printf("read_rx_fifo: rx_fifo_num %d\n", rx_fifo_num); |
| 690 | |
| 691 | if ( rx_fifo_num == 0 ) |
| 692 | { |
| 693 | LOG(( "68681 channel: rx fifo underflow\n" )); |
| 694 | return 0x0; |
| 695 | } |
| 696 | |
| 697 | rv = rx_fifo[rx_fifo_read_ptr++]; |
| 698 | if ( rx_fifo_read_ptr == MC68681_RX_FIFO_SIZE ) |
| 699 | { |
| 700 | rx_fifo_read_ptr = 0; |
| 701 | } |
| 702 | |
| 703 | rx_fifo_num--; |
| 704 | update_interrupts(); |
| 705 | |
| 706 | return rv; |
| 707 | }; |
| 708 | |
| 709 | UINT8 duart68681_channel::read_chan_reg(int reg) |
| 710 | { |
| 711 | UINT8 rv = 0xff; |
| 712 | |
| 713 | switch (reg) |
| 714 | { |
| 715 | case 0: // MR1/MR2 |
| 716 | if ( MR_ptr == 0 ) |
| 717 | { |
| 718 | rv = MR1; |
| 719 | MR_ptr = 1; |
| 720 | } |
| 721 | else |
| 722 | { |
| 723 | rv = MR2; |
| 724 | } |
| 725 | break; |
| 726 | |
| 727 | case 1: // SRA |
| 728 | rv = SR; |
| 729 | break; |
| 730 | |
| 731 | case 2: // CSRA: reading this is prohibited |
| 732 | break; |
| 733 | |
| 734 | case 3: // Rx holding register A |
| 735 | rv = read_rx_fifo(); |
| 736 | break; |
| 737 | } |
| 738 | |
| 739 | return rv; |
| 740 | } |
| 741 | |
| 742 | void duart68681_channel::write_chan_reg(int reg, UINT8 data) |
| 743 | { |
| 744 | switch (reg) |
| 745 | { |
| 746 | case 0x00: /* MRA */ |
| 747 | write_MR(data); |
| 748 | break; |
| 749 | |
| 750 | case 0x01: /* CSR */ |
| 751 | CSR = data; |
| 752 | tx_baud_rate = m_uart->calc_baud(m_ch, data & 0xf); |
| 753 | rx_baud_rate = m_uart->calc_baud(m_ch, (data>>4) & 0xf); |
| 754 | // printf("ch %d Tx baud %d Rx baud %d\n", m_ch, tx_baud_rate, rx_baud_rate); |
| 755 | set_rcv_rate(rx_baud_rate); |
| 756 | set_tra_rate(tx_baud_rate); |
| 757 | break; |
| 758 | |
| 759 | case 0x02: /* CR */ |
| 760 | write_CR(data); |
| 761 | break; |
| 762 | |
| 763 | case 0x03: /* THR */ |
| 764 | write_TX(data); |
| 765 | break; |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | void duart68681_channel::write_MR(UINT8 data) |
| 770 | { |
| 771 | if ( MR_ptr == 0 ) |
| 772 | { |
| 773 | MR1 = data; |
| 774 | MR_ptr = 1; |
| 775 | } |
| 776 | else |
| 777 | { |
| 778 | MR2 = data; |
| 779 | } |
| 780 | recalc_framing(); |
| 781 | update_interrupts(); |
| 782 | }; |
| 783 | |
| 784 | void duart68681_channel::recalc_framing() |
| 785 | { |
| 786 | int parity, stopbits; |
| 787 | |
| 788 | switch ((MR2 >> 2) & 3) |
| 789 | { |
| 790 | case 0: |
| 791 | case 1: |
| 792 | stopbits = 1; |
| 793 | break; |
| 794 | |
| 795 | case 2: // "1.5 async, 2 sync" |
| 796 | stopbits = 2; |
| 797 | break; |
| 798 | |
| 799 | case 3: |
| 800 | stopbits = 2; |
| 801 | break; |
| 802 | } |
| 803 | |
| 804 | switch ((MR1>>3) & 3) |
| 805 | { |
| 806 | case 0: // with parity |
| 807 | if (MR1 & 4) |
| 808 | { |
| 809 | parity = SERIAL_PARITY_ODD; |
| 810 | } |
| 811 | else |
| 812 | { |
| 813 | parity = SERIAL_PARITY_EVEN; |
| 814 | } |
| 815 | break; |
| 816 | |
| 817 | case 1: // force parity |
| 818 | if (MR1 & 4) |
| 819 | { |
| 820 | parity = SERIAL_PARITY_MARK; |
| 821 | } |
| 822 | else |
| 823 | { |
| 824 | parity = SERIAL_PARITY_SPACE; |
| 825 | } |
| 826 | break; |
| 827 | |
| 828 | case 2: // no parity |
| 829 | parity = SERIAL_PARITY_NONE; |
| 830 | break; |
| 831 | |
| 832 | case 3: // multidrop mode |
| 833 | fatalerror("68681: multidrop parity not supported\n"); |
| 834 | break; |
| 835 | } |
| 836 | |
| 837 | // printf("ch %d MR1 %02x MR2 %02x => %d bits / char, %d stop bits, parity %d\n", m_ch, MR1, MR2, (MR1 & 3)+5, stopbits, parity); |
| 838 | |
| 839 | set_data_frame((MR1 & 3)+5, stopbits, parity); |
| 840 | } |
| 841 | |
| 842 | void duart68681_channel::write_CR(UINT8 data) |
| 843 | { |
| 844 | CR = data; |
| 845 | |
| 846 | switch( (data >> 4) & 0x07 ) |
| 847 | { |
| 848 | case 0: /* No command */ |
| 849 | break; |
| 850 | case 1: /* Reset MR pointer. Causes the channel MR pointer to point to MR1 */ |
| 851 | MR_ptr = 0; |
| 852 | break; |
| 853 | case 2: /* Reset channel receiver (disable receiver and flush fifo) */ |
| 854 | rx_enabled = 0; |
| 855 | SR &= ~STATUS_RECEIVER_READY; |
| 856 | SR &= ~STATUS_OVERRUN_ERROR; // is this correct? |
| 857 | rx_fifo_read_ptr = 0; |
| 858 | rx_fifo_write_ptr = 0; |
| 859 | rx_fifo_num = 0; |
| 860 | receive_register_reset(); |
| 861 | break; |
| 862 | case 3: /* Reset channel transmitter */ |
| 863 | tx_enabled = 0; |
| 864 | SR &= ~STATUS_TRANSMITTER_READY; |
| 865 | if (m_ch == 0) |
| 866 | m_uart->clear_ISR_bits(INT_TXRDYA); |
| 867 | else |
| 868 | m_uart->clear_ISR_bits(INT_TXRDYB); |
| 869 | transmit_register_reset(); |
| 870 | break; |
| 871 | case 4: /* Reset Error Status */ |
| 872 | SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR); |
| 873 | break; |
| 874 | case 5: /* Reset Channel break change interrupt */ |
| 875 | if ( m_ch == 0 ) |
| 876 | { |
| 877 | m_uart->clear_ISR_bits(INT_DELTA_BREAK_A); |
| 878 | } |
| 879 | else |
| 880 | { |
| 881 | m_uart->clear_ISR_bits(INT_DELTA_BREAK_B); |
| 882 | } |
| 883 | break; |
| 884 | /* TODO: case 6 and case 7 are start break and stop break respectively, which start or stop holding the TxDA or TxDB line low (space) after whatever data is in the buffer finishes transmitting (following the stop bit?), or after two bit-times if no data is being transmitted */ |
| 885 | default: |
| 886 | LOG(( "68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, m_ch )); |
| 887 | break; |
| 888 | } |
| 889 | |
| 890 | if (BIT(data, 0)) { |
| 891 | rx_enabled = 1; |
| 892 | } |
| 893 | if (BIT(data, 1)) { |
| 894 | rx_enabled = 0; |
| 895 | SR &= ~STATUS_RECEIVER_READY; |
| 896 | } |
| 897 | |
| 898 | if (BIT(data, 2)) { |
| 899 | tx_enabled = 1; |
| 900 | tx_ready = 1; |
| 901 | SR |= STATUS_TRANSMITTER_READY; |
| 902 | if (m_ch == 0) |
| 903 | m_uart->set_ISR_bits(INT_TXRDYA); |
| 904 | else |
| 905 | m_uart->set_ISR_bits(INT_TXRDYB); |
| 906 | } |
| 907 | if (BIT(data, 3)) { |
| 908 | tx_enabled = 0; |
| 909 | tx_ready = 0; |
| 910 | SR &= ~STATUS_TRANSMITTER_READY; |
| 911 | if (m_ch == 0) |
| 912 | m_uart->clear_ISR_bits(INT_TXRDYA); |
| 913 | else |
| 914 | m_uart->clear_ISR_bits(INT_TXRDYB); |
| 915 | } |
| 916 | |
| 917 | update_interrupts(); |
| 918 | }; |
| 919 | |
| 920 | void duart68681_channel::write_TX(UINT8 data) |
| 921 | { |
| 922 | tx_data = data; |
| 923 | |
| 924 | /* if (!tx_ready) |
| 925 | { |
| 926 | printf("Write %02x to TX when TX not ready!\n", data); |
| 927 | }*/ |
| 928 | |
| 929 | // printf("ch %d Tx %02x\n", m_ch, data); |
| 930 | |
| 931 | // send the byte unless we're in loopback mode; |
| 932 | // in loopback mode do NOT 'actually' send the byte: the TXn pin is held high when loopback mode is on. |
| 933 | if ((MR2&0xC0) != 0x80) |
| 934 | { |
| 935 | tx_ready = 0; |
| 936 | SR &= ~STATUS_TRANSMITTER_READY; |
| 937 | |
| 938 | if (m_ch == 0) |
| 939 | m_uart->clear_ISR_bits(INT_TXRDYA); |
| 940 | else |
| 941 | m_uart->clear_ISR_bits(INT_TXRDYB); |
| 942 | |
| 943 | // send tx_data |
| 944 | transmit_register_setup(tx_data); |
| 945 | } |
| 946 | // if local loopback is on, write the transmitted data as if a byte had been received |
| 947 | else if ((MR2 & 0xC0) == 0x80) |
| 948 | { |
| 949 | if (rx_fifo_num >= MC68681_RX_FIFO_SIZE) |
| 950 | { |
| 951 | LOG(( "68681: FIFO overflow\n" )); |
| 952 | SR |= STATUS_OVERRUN_ERROR; |
| 953 | } |
| 954 | else |
| 955 | { |
| 956 | rx_fifo[rx_fifo_write_ptr++]= tx_data; |
| 957 | if (rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE) |
| 958 | { |
| 959 | rx_fifo_write_ptr = 0; |
| 960 | } |
| 961 | rx_fifo_num++; |
| 962 | } |
| 963 | |
| 964 | tx_ready = 1; |
| 965 | SR |= STATUS_TRANSMITTER_READY; |
| 966 | if (m_ch == 0) |
| 967 | m_uart->set_ISR_bits(INT_TXRDYA); |
| 968 | else |
| 969 | m_uart->set_ISR_bits(INT_TXRDYB); |
| 970 | } |
| 971 | |
| 972 | update_interrupts(); |
| 973 | }; |
| 974 | |
trunk/src/emu/machine/n68681.h
| r20112 | r20113 | |
| 3 | 3 | |
| 4 | 4 | #include "diserial.h" |
| 5 | 5 | |
| 6 | #define MCFG_DUARTN68681_ADD(_tag, _clock, _config) \ |
| 7 | MCFG_DEVICE_ADD(_tag, DUARTN68681, _clock) \ |
| 8 | MCFG_DEVICE_CONFIG(_config) |
| 9 | |
| 10 | #define MCFG_DUARTN68681_REPLACE(_tag, _clock, _config) \ |
| 11 | MCFG_DEVICE_REPLACE(_tag, DUARTN68681, _clock) \ |
| 12 | MCFG_DEVICE_CONFIG(_config) |
| 13 | |
| 14 | #define MCFG_DUART68681_CHANNEL_ADD(_tag) \ |
| 15 | MCFG_DEVICE_ADD(_tag, DUART68681CHANNEL, 0) \ |
| 16 | |
| 6 | 17 | // forward declaration |
| 7 | 18 | class duartn68681_device; |
| 8 | 19 | |
| 9 | 20 | struct duartn68681_config |
| 10 | 21 | { |
| 11 | 22 | devcb_write_line m_out_irq_cb; |
| 12 | | devcb_write8 m_out_a_tx_cb; |
| 13 | | devcb_write8 m_out_b_tx_cb; |
| 23 | devcb_write_line m_out_a_tx_cb; |
| 24 | devcb_write_line m_out_b_tx_cb; |
| 14 | 25 | devcb_read8 m_in_port_cb; |
| 15 | 26 | devcb_write8 m_out_port_cb; |
| 16 | 27 | |
| r20112 | r20113 | |
| 20 | 31 | |
| 21 | 32 | #define MC68681_RX_FIFO_SIZE 3 |
| 22 | 33 | |
| 23 | | struct DUART68681_CHANNEL |
| 34 | // forward declaration |
| 35 | class duartn68681_device; |
| 36 | |
| 37 | // n68681 channel class |
| 38 | class duart68681_channel : public device_t, public device_serial_interface |
| 24 | 39 | { |
| 40 | public: |
| 41 | duart68681_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 42 | |
| 43 | // device-level overrides |
| 44 | virtual void device_start(); |
| 45 | virtual void device_reset(); |
| 46 | |
| 47 | // device_serial overrides |
| 48 | virtual void rcv_complete(); // Rx completed receiving byte |
| 49 | virtual void tra_complete(); // Tx completed sending byte |
| 50 | virtual void tra_callback(); // Tx send bit |
| 51 | void input_callback(UINT8 state); |
| 52 | |
| 53 | UINT8 read_chan_reg(int reg); |
| 54 | void write_chan_reg(int reg, UINT8 data); |
| 55 | void update_interrupts(); |
| 56 | |
| 57 | UINT8 read_rx_fifo(); |
| 58 | |
| 59 | private: |
| 25 | 60 | /* Registers */ |
| 26 | 61 | UINT8 CR; /* Command register */ |
| 27 | 62 | UINT8 CSR; /* Clock select register */ |
| r20112 | r20113 | |
| 31 | 66 | UINT8 SR; /* Status register */ |
| 32 | 67 | |
| 33 | 68 | /* State */ |
| 34 | | int baud_rate; |
| 69 | int tx_baud_rate, rx_baud_rate; |
| 35 | 70 | |
| 36 | 71 | /* Receiver */ |
| 37 | 72 | UINT8 rx_enabled; |
| r20112 | r20113 | |
| 40 | 75 | int rx_fifo_write_ptr; |
| 41 | 76 | int rx_fifo_num; |
| 42 | 77 | |
| 78 | int m_ch; |
| 79 | |
| 43 | 80 | /* Transmitter */ |
| 44 | 81 | UINT8 tx_enabled; |
| 45 | 82 | UINT8 tx_data; |
| 46 | 83 | UINT8 tx_ready; |
| 47 | | emu_timer *tx_timer; |
| 84 | |
| 85 | duartn68681_device *m_uart; |
| 86 | |
| 87 | void write_MR(UINT8 data); |
| 88 | void write_CR(UINT8 data); |
| 89 | void write_TX(UINT8 data); |
| 90 | void recalc_framing(); |
| 48 | 91 | }; |
| 49 | 92 | |
| 50 | | class duartn68681_device : public device_t, public device_serial_interface, public duartn68681_config |
| 93 | class duartn68681_device : public device_t, public duartn68681_config |
| 51 | 94 | { |
| 95 | friend class duart68681_channel; |
| 96 | |
| 52 | 97 | public: |
| 53 | 98 | duartn68681_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 54 | 99 | |
| 100 | required_device<duart68681_channel> m_chanA; |
| 101 | required_device<duart68681_channel> m_chanB; |
| 102 | |
| 103 | // API |
| 55 | 104 | DECLARE_READ8_HANDLER(read); |
| 56 | 105 | DECLARE_WRITE8_HANDLER(write); |
| 106 | UINT8 get_irq_vector() { return IVR; } |
| 57 | 107 | |
| 58 | | void duart68681_rx_data(int ch, UINT8 data); |
| 108 | DECLARE_WRITE_LINE_MEMBER( rx_a_w ) { m_chanA->check_for_start((UINT8)state); } |
| 109 | DECLARE_WRITE_LINE_MEMBER( rx_b_w ) { m_chanB->check_for_start((UINT8)state); } |
| 59 | 110 | |
| 60 | | TIMER_CALLBACK_MEMBER( tx_timer_callback ); |
| 61 | | TIMER_CALLBACK_MEMBER( duart_timer_callback ); |
| 62 | | |
| 63 | | UINT8 get_irq_vector() { return IVR; } |
| 64 | | |
| 65 | 111 | protected: |
| 66 | 112 | // device-level overrides |
| 67 | 113 | virtual void device_config_complete(); |
| 68 | 114 | virtual void device_start(); |
| 69 | 115 | virtual void device_reset(); |
| 116 | virtual machine_config_constructor device_mconfig_additions() const; |
| 70 | 117 | |
| 71 | | // device_serial overrides |
| 72 | | virtual void rcv_complete(); // Rx complete |
| 73 | | virtual void tra_complete(); // Tx complete |
| 74 | | virtual void tra_callback(); // Tx bit ready |
| 75 | | void input_callback(UINT8 state); |
| 118 | private: |
| 119 | TIMER_CALLBACK_MEMBER( duart_timer_callback ); |
| 76 | 120 | |
| 77 | | private: |
| 78 | 121 | /* registers */ |
| 79 | 122 | UINT8 ACR; /* Auxiliary Control Register */ |
| 80 | 123 | UINT8 IMR; /* Interrupt Mask Register */ |
| r20112 | r20113 | |
| 91 | 134 | UINT8 half_period; |
| 92 | 135 | emu_timer *duart_timer; |
| 93 | 136 | |
| 94 | | /* UART channels */ |
| 95 | | DUART68681_CHANNEL channel[2]; |
| 96 | | |
| 97 | | void update_interrupts(); |
| 98 | 137 | double duart68681_get_ct_rate(); |
| 99 | 138 | UINT16 duart68681_get_ct_count(); |
| 100 | 139 | void duart68681_start_ct(int count); |
| 101 | | void duart68681_write_MR(int ch, UINT8 data); |
| 102 | | void duart68681_write_CSR(int ch, UINT8 data, UINT8 ACR); |
| 103 | | void duart68681_write_CR(int ch, UINT8 data); |
| 104 | | UINT8 duart68681_read_rx_fifo(int ch); |
| 105 | | void duart68681_write_TX(int ch, UINT8 data); |
| 140 | int calc_baud(int ch, UINT8 data); |
| 141 | int get_ch(duart68681_channel *ch) { return (ch == m_chanA) ? 0 : 1; } |
| 142 | void clear_ISR_bits(int mask); |
| 143 | void set_ISR_bits(int mask); |
| 144 | void update_interrupts(); |
| 106 | 145 | |
| 146 | duart68681_channel *get_channel(int chan); |
| 147 | |
| 107 | 148 | devcb_resolved_write_line m_out_irq_func; |
| 108 | | devcb_resolved_write8 m_out_a_tx_func; |
| 109 | | devcb_resolved_write8 m_out_b_tx_func; |
| 149 | devcb_resolved_write_line m_out_a_tx_func; |
| 150 | devcb_resolved_write_line m_out_b_tx_func; |
| 110 | 151 | devcb_resolved_read8 m_in_port_func; |
| 111 | 152 | devcb_resolved_write8 m_out_port_func; |
| 112 | | |
| 113 | 153 | }; |
| 114 | 154 | |
| 115 | | #define MCFG_DUARTN68681_ADD(_tag, _clock, _config) \ |
| 116 | | MCFG_DEVICE_ADD(_tag, DUARTN68681, _clock) \ |
| 117 | | MCFG_DEVICE_CONFIG(_config) |
| 118 | | |
| 119 | 155 | extern const device_type DUARTN68681; |
| 156 | extern const device_type DUART68681CHANNEL; |
| 120 | 157 | |
| 121 | 158 | #endif //_N68681_H |
| 122 | 159 | |
trunk/src/mess/drivers/esq5505.c
| r20112 | r20113 | |
| 108 | 108 | #include "formats/esq16_dsk.h" |
| 109 | 109 | |
| 110 | 110 | #include "machine/esqvfd.h" |
| 111 | #include "machine/esqpanel.h" |
| 111 | 112 | |
| 112 | 113 | #define GENERIC (0) |
| 113 | 114 | #define EPS (1) |
| 114 | 115 | #define SQ1 (2) |
| 115 | 116 | |
| 116 | 117 | #define KEYBOARD_HACK (1) // turn on to play the SQ-1, SD-1, and SD-1 32-voice: Z and X are program up/down, A/S/D/F/G/H/J/K/L and Q/W/E/R/T/Y/U play notes |
| 117 | | #define HACK_VIA_MIDI (1) |
| 118 | #define HACK_VIA_MIDI (0) // won't work right now |
| 118 | 119 | |
| 119 | 120 | #if KEYBOARD_HACK |
| 120 | 121 | #if HACK_VIA_MIDI |
| r20112 | r20113 | |
| 132 | 133 | m_maincpu(*this, "maincpu"), |
| 133 | 134 | m_duart(*this, "duart"), |
| 134 | 135 | m_fdc(*this, "wd1772"), |
| 135 | | m_epsvfd(*this, "epsvfd"), |
| 136 | | m_sq1vfd(*this, "sq1vfd"), |
| 137 | | m_vfd(*this, "vfd"), |
| 136 | m_epspanel(*this, "epspanel"), |
| 137 | m_sq1panel(*this, "sq1panel"), |
| 138 | m_panel(*this, "panel"), |
| 138 | 139 | m_dmac(*this, "mc68450") |
| 139 | 140 | { } |
| 140 | 141 | |
| 141 | 142 | required_device<m68000_device> m_maincpu; |
| 142 | 143 | required_device<duartn68681_device> m_duart; |
| 143 | 144 | optional_device<wd1772_t> m_fdc; |
| 144 | | optional_device<esq1x22_t> m_epsvfd; |
| 145 | | optional_device<esq2x40_sq1_t> m_sq1vfd; |
| 146 | | optional_device<esq2x40_t> m_vfd; |
| 145 | optional_device<esqpanel1x22_device> m_epspanel; |
| 146 | optional_device<esqpanel2x40_sq1_device> m_sq1panel; |
| 147 | optional_device<esqpanel2x40_device> m_panel; |
| 147 | 148 | optional_device<hd63450_device> m_dmac; |
| 148 | 149 | |
| 149 | 150 | virtual void machine_reset(); |
| r20112 | r20113 | |
| 156 | 157 | DECLARE_WRITE16_MEMBER(lower_w); |
| 157 | 158 | |
| 158 | 159 | DECLARE_WRITE_LINE_MEMBER(duart_irq_handler); |
| 159 | | DECLARE_WRITE8_MEMBER(duart_tx_a); |
| 160 | | DECLARE_WRITE8_MEMBER(duart_tx_b); |
| 160 | DECLARE_WRITE_LINE_MEMBER(duart_tx_a); |
| 161 | DECLARE_WRITE_LINE_MEMBER(duart_tx_b); |
| 161 | 162 | DECLARE_READ8_MEMBER(duart_input); |
| 162 | 163 | DECLARE_WRITE8_MEMBER(duart_output); |
| 163 | 164 | |
| 164 | 165 | int m_system_type; |
| 165 | 166 | UINT8 m_duart_io; |
| 166 | | bool m_bCalibSecondByte; |
| 167 | 167 | |
| 168 | 168 | DECLARE_FLOPPY_FORMATS( floppy_formats ); |
| 169 | 169 | |
| r20112 | r20113 | |
| 179 | 179 | |
| 180 | 180 | UINT16 *m_rom, *m_ram; |
| 181 | 181 | |
| 182 | #if KEYBOARD_HACK |
| 183 | void send_through_panel(UINT8 data); |
| 184 | #endif |
| 185 | |
| 182 | 186 | public: |
| 183 | 187 | DECLARE_DRIVER_INIT(eps); |
| 184 | 188 | DECLARE_DRIVER_INIT(common); |
| r20112 | r20113 | |
| 199 | 203 | { |
| 200 | 204 | m_rom = (UINT16 *)machine().root_device().memregion("osrom")->base(); |
| 201 | 205 | m_ram = (UINT16 *)machine().root_device().memshare("osram")->ptr(); |
| 202 | | |
| 203 | | m_bCalibSecondByte = false; |
| 204 | 206 | } |
| 205 | 207 | |
| 206 | 208 | READ16_MEMBER(esq5505_state::es5510_dsp_r) |
| r20112 | r20113 | |
| 522 | 524 | } |
| 523 | 525 | |
| 524 | 526 | // MIDI send, we don't care yet |
| 525 | | WRITE8_MEMBER(esq5505_state::duart_tx_a) |
| 527 | WRITE_LINE_MEMBER(esq5505_state::duart_tx_a) |
| 526 | 528 | { |
| 527 | 529 | } |
| 528 | 530 | |
| 529 | | WRITE8_MEMBER(esq5505_state::duart_tx_b) |
| 531 | WRITE_LINE_MEMBER(esq5505_state::duart_tx_b) |
| 530 | 532 | { |
| 531 | | /* if (data >= 'A' && data <= 'z') |
| 532 | | { |
| 533 | | printf("ch 1: [%02x](%c) (PC=%x)\n", data, data, m_maincpu->pc()); |
| 534 | | } |
| 535 | | else |
| 536 | | { |
| 537 | | printf("ch 1: [%02x] (PC=%x)\n", data, m_maincpu->pc()); |
| 538 | | }*/ |
| 539 | | |
| 533 | // printf("Tx B: %d\n", state); |
| 540 | 534 | switch (m_system_type) |
| 541 | 535 | { |
| 542 | 536 | case GENERIC: |
| 543 | | m_vfd->write_char(data); |
| 537 | m_panel->rx_w(state); |
| 544 | 538 | break; |
| 545 | 539 | |
| 546 | 540 | case EPS: |
| 547 | | m_epsvfd->write_char(data); |
| 541 | m_epspanel->rx_w(state); |
| 548 | 542 | break; |
| 549 | 543 | |
| 550 | 544 | case SQ1: |
| 551 | | m_sq1vfd->write_char(data); |
| 545 | m_sq1panel->rx_w(state); |
| 552 | 546 | break; |
| 553 | 547 | } |
| 554 | 548 | |
| 549 | #if 0 |
| 555 | 550 | if (m_bCalibSecondByte) |
| 556 | 551 | { |
| 557 | 552 | if (data == 0xfd) // calibration request |
| r20112 | r20113 | |
| 584 | 579 | } |
| 585 | 580 | } |
| 586 | 581 | } |
| 582 | #endif |
| 587 | 583 | } |
| 588 | 584 | |
| 589 | 585 | static const duartn68681_config duart_config = |
| 590 | 586 | { |
| 591 | 587 | DEVCB_DRIVER_LINE_MEMBER(esq5505_state, duart_irq_handler), |
| 592 | | DEVCB_DRIVER_MEMBER(esq5505_state, duart_tx_a), |
| 593 | | DEVCB_DRIVER_MEMBER(esq5505_state, duart_tx_b), |
| 588 | DEVCB_DRIVER_LINE_MEMBER(esq5505_state, duart_tx_a), |
| 589 | DEVCB_DRIVER_LINE_MEMBER(esq5505_state, duart_tx_b), |
| 594 | 590 | DEVCB_DRIVER_MEMBER(esq5505_state, duart_input), |
| 595 | 591 | DEVCB_DRIVER_MEMBER(esq5505_state, duart_output), |
| 596 | 592 | |
| r20112 | r20113 | |
| 631 | 627 | } |
| 632 | 628 | |
| 633 | 629 | #if KEYBOARD_HACK |
| 630 | void esq5505_state::send_through_panel(UINT8 data) |
| 631 | { |
| 632 | switch (m_system_type) |
| 633 | { |
| 634 | case GENERIC: |
| 635 | m_panel->xmit_char(data); |
| 636 | break; |
| 637 | |
| 638 | case EPS: |
| 639 | m_epspanel->xmit_char(data); |
| 640 | break; |
| 641 | |
| 642 | case SQ1: |
| 643 | m_sq1panel->xmit_char(data); |
| 644 | break; |
| 645 | } |
| 646 | } |
| 647 | |
| 634 | 648 | INPUT_CHANGED_MEMBER(esq5505_state::key_stroke) |
| 635 | 649 | { |
| 636 | 650 | #if HACK_VIA_MIDI |
| r20112 | r20113 | |
| 704 | 718 | if (oldval == 0 && newval == 1) |
| 705 | 719 | { |
| 706 | 720 | printf("key pressed %d\n", val&0x7f); |
| 707 | | m_duart->duart68681_rx_data(1, val); |
| 708 | | m_duart->duart68681_rx_data(1, 0x00); |
| 721 | send_through_panel(val); |
| 722 | send_through_panel(0x00); |
| 709 | 723 | } |
| 710 | 724 | else if (oldval == 1 && newval == 0) |
| 711 | 725 | { |
| 712 | 726 | // printf("key off %x\n", (UINT8)(FPTR)param); |
| 713 | | m_duart->duart68681_rx_data(1, val&0x7f); |
| 714 | | m_duart->duart68681_rx_data(1, 0x00); |
| 727 | send_through_panel(val&0x7f); |
| 728 | send_through_panel(0x00); |
| 715 | 729 | } |
| 716 | 730 | } |
| 717 | 731 | #endif |
| r20112 | r20113 | |
| 737 | 751 | esq5505_read_adc |
| 738 | 752 | }; |
| 739 | 753 | |
| 754 | static const esqpanel_interface esqpanel_config = |
| 755 | { |
| 756 | DEVCB_DEVICE_LINE_MEMBER("duart", duartn68681_device, rx_b_w) |
| 757 | }; |
| 758 | |
| 740 | 759 | static MACHINE_CONFIG_START( vfx, esq5505_state ) |
| 741 | 760 | MCFG_CPU_ADD("maincpu", M68000, XTAL_10MHz) |
| 742 | 761 | MCFG_CPU_PROGRAM_MAP(vfx_map) |
| 743 | 762 | |
| 744 | | MCFG_ESQ2x40_ADD("vfd") |
| 763 | MCFG_ESQPANEL2x40_ADD("panel", esqpanel_config) |
| 745 | 764 | |
| 746 | 765 | MCFG_DUARTN68681_ADD("duart", 4000000, duart_config) |
| 747 | 766 | |
| r20112 | r20113 | |
| 756 | 775 | MCFG_CPU_MODIFY( "maincpu" ) |
| 757 | 776 | MCFG_CPU_PROGRAM_MAP(eps_map) |
| 758 | 777 | |
| 759 | | MCFG_ESQ2x40_REMOVE("vfd") |
| 760 | | MCFG_ESQ1x22_ADD("epsvfd") |
| 778 | MCFG_ESQPANEL_2x40_REMOVE("panel") |
| 779 | MCFG_ESQPANEL1x22_ADD("epspanel", esqpanel_config) |
| 761 | 780 | |
| 762 | 781 | MCFG_WD1772x_ADD("wd1772", 8000000) |
| 763 | 782 | MCFG_FLOPPY_DRIVE_ADD("wd1772:0", ensoniq_floppies, "35dd", 0, esq5505_state::floppy_formats) |
| r20112 | r20113 | |
| 778 | 797 | MCFG_CPU_ADD("maincpu", M68000, XTAL_30_4761MHz / 2) |
| 779 | 798 | MCFG_CPU_PROGRAM_MAP(vfxsd_map) |
| 780 | 799 | |
| 781 | | MCFG_ESQ2x40_ADD("vfd") |
| 800 | MCFG_ESQPANEL2x40_ADD("panel", esqpanel_config) |
| 782 | 801 | |
| 783 | 802 | MCFG_DUARTN68681_ADD("duart", 4000000, duart_config) |
| 784 | 803 | |
| r20112 | r20113 | |
| 796 | 815 | MCFG_CPU_MODIFY( "maincpu" ) |
| 797 | 816 | MCFG_CPU_PROGRAM_MAP(sq1_map) |
| 798 | 817 | |
| 799 | | MCFG_ESQ2x40_REMOVE("vfd") |
| 800 | | MCFG_ESQ2x40_SQ1_ADD("sq1vfd") |
| 818 | MCFG_ESQPANEL_2x40_REMOVE("panel") |
| 819 | MCFG_ESQPANEL2x40_SQ1_ADD("sq1panel", esqpanel_config) |
| 801 | 820 | MACHINE_CONFIG_END |
| 802 | 821 | |
| 803 | 822 | static INPUT_PORTS_START( vfx ) |
trunk/src/mess/machine/esqpanel.c
| r0 | r20113 | |
| 1 | /* |
| 2 | Ensoniq panel/display device |
| 3 | */ |
| 4 | #include "emu.h" |
| 5 | #include "esqpanel.h" |
| 6 | |
| 7 | //************************************************************************** |
| 8 | // MACROS / CONSTANTS |
| 9 | //************************************************************************** |
| 10 | |
| 11 | //************************************************************************** |
| 12 | // DEVICE DEFINITIONS |
| 13 | //************************************************************************** |
| 14 | |
| 15 | const device_type ESQPANEL1x22 = &device_creator<esqpanel1x22_device>; |
| 16 | const device_type ESQPANEL2x40 = &device_creator<esqpanel2x40_device>; |
| 17 | const device_type ESQPANEL2x40_SQ1 = &device_creator<esqpanel2x40_sq1_device>; |
| 18 | |
| 19 | //************************************************************************** |
| 20 | // LIVE DEVICE |
| 21 | //************************************************************************** |
| 22 | |
| 23 | //------------------------------------------------- |
| 24 | // esqpanel_device - constructor |
| 25 | //------------------------------------------------- |
| 26 | |
| 27 | esqpanel_device::esqpanel_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : |
| 28 | device_t(mconfig, type, name, tag, owner, clock), |
| 29 | device_serial_interface(mconfig, *this) |
| 30 | { |
| 31 | } |
| 32 | |
| 33 | void esqpanel_device::device_config_complete() |
| 34 | { |
| 35 | m_shortname = "esqpanel"; |
| 36 | |
| 37 | // inherit a copy of the static data |
| 38 | const esqpanel_interface *intf = reinterpret_cast<const esqpanel_interface *>(static_config()); |
| 39 | if (intf != NULL) |
| 40 | { |
| 41 | *static_cast<esqpanel_interface *>(this) = *intf; |
| 42 | } |
| 43 | // or initialize to defaults if none provided |
| 44 | else |
| 45 | { |
| 46 | memset(&m_out_tx_cb, 0, sizeof(m_out_tx_cb)); |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | //------------------------------------------------- |
| 51 | // device_start - device-specific startup |
| 52 | //------------------------------------------------- |
| 53 | |
| 54 | void esqpanel_device::device_start() |
| 55 | { |
| 56 | m_out_tx_func.resolve(m_out_tx_cb, *this); |
| 57 | } |
| 58 | |
| 59 | |
| 60 | //------------------------------------------------- |
| 61 | // device_reset - device-specific reset |
| 62 | //------------------------------------------------- |
| 63 | |
| 64 | void esqpanel_device::device_reset() |
| 65 | { |
| 66 | // panel comms is at 62500 baud (double the MIDI rate), 8N2 |
| 67 | set_rcv_rate(62500); |
| 68 | set_tra_rate(62500); |
| 69 | set_data_frame(8, 2, SERIAL_PARITY_NONE); |
| 70 | |
| 71 | m_tx_busy = false; |
| 72 | m_xmit_read = m_xmit_write = 0; |
| 73 | m_bCalibSecondByte = false; |
| 74 | } |
| 75 | |
| 76 | void esqpanel_device::rcv_complete() // Rx completed receiving byte |
| 77 | { |
| 78 | receive_register_extract(); |
| 79 | UINT8 data = get_received_char(); |
| 80 | |
| 81 | // if (data >= 0xe0) printf("Got %02x from motherboard (second %s)\n", data, m_bCalibSecondByte ? "yes" : "no"); |
| 82 | |
| 83 | send_to_display(data); |
| 84 | |
| 85 | if (m_bCalibSecondByte) |
| 86 | { |
| 87 | // printf("second byte is %02x\n", data); |
| 88 | if (data == 0xfd) // calibration request |
| 89 | { |
| 90 | // printf("let's send reply!\n"); |
| 91 | xmit_char(0xff); // this is the correct response for "calibration OK" |
| 92 | } |
| 93 | m_bCalibSecondByte = false; |
| 94 | } |
| 95 | else if (data == 0xfb) // request calibration |
| 96 | { |
| 97 | m_bCalibSecondByte = true; |
| 98 | } |
| 99 | else |
| 100 | { |
| 101 | // EPS wants a throwaway reply byte for each byte sent to the KPC |
| 102 | // VFX-SD and SD-1 definitely don't :) |
| 103 | if (m_eps_mode) |
| 104 | { |
| 105 | if (data == 0xe7) |
| 106 | { |
| 107 | xmit_char(0x00); // actual value of response is never checked |
| 108 | } |
| 109 | else if (data == 0x71) |
| 110 | { |
| 111 | xmit_char(0x00); // actual value of response is never checked |
| 112 | } |
| 113 | else |
| 114 | { |
| 115 | xmit_char(data); // actual value of response is never checked |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | void esqpanel_device::tra_complete() // Tx completed sending byte |
| 122 | { |
| 123 | // printf("panel Tx complete\n"); |
| 124 | // is there more waiting to send? |
| 125 | if (m_xmit_read != m_xmit_write) |
| 126 | { |
| 127 | transmit_register_setup(m_xmitring[m_xmit_read++]); |
| 128 | if (m_xmit_read >= XMIT_RING_SIZE) |
| 129 | { |
| 130 | m_xmit_read = 0; |
| 131 | } |
| 132 | } |
| 133 | else |
| 134 | { |
| 135 | m_tx_busy = false; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | void esqpanel_device::tra_callback() // Tx send bit |
| 140 | { |
| 141 | int bit = transmit_register_get_data_bit(); |
| 142 | m_out_tx_func(bit); |
| 143 | } |
| 144 | |
| 145 | void esqpanel_device::input_callback(UINT8 state) |
| 146 | { |
| 147 | } |
| 148 | |
| 149 | void esqpanel_device::xmit_char(UINT8 data) |
| 150 | { |
| 151 | // printf("Panel: xmit %02x\n", data); |
| 152 | |
| 153 | // if tx is busy it'll pick this up automatically when it completes |
| 154 | if (!m_tx_busy) |
| 155 | { |
| 156 | m_tx_busy = true; |
| 157 | transmit_register_setup(data); |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | // tx is busy, it'll pick this up next time |
| 162 | m_xmitring[m_xmit_write++] = data; |
| 163 | if (m_xmit_write >= XMIT_RING_SIZE) |
| 164 | { |
| 165 | m_xmit_write = 0; |
| 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /* panel with 1x22 VFD display used in the EPS-16 and EPS-16 Plus */ |
| 171 | |
| 172 | static MACHINE_CONFIG_FRAGMENT(esqpanel1x22) |
| 173 | MCFG_ESQ1x22_ADD("vfd") |
| 174 | MACHINE_CONFIG_END |
| 175 | |
| 176 | machine_config_constructor esqpanel1x22_device::device_mconfig_additions() const |
| 177 | { |
| 178 | return MACHINE_CONFIG_NAME( esqpanel1x22 ); |
| 179 | } |
| 180 | |
| 181 | esqpanel1x22_device::esqpanel1x22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 182 | esqpanel_device(mconfig, ESQPANEL1x22, "Ensoniq front panel with 1x22 VFD", tag, owner, clock), |
| 183 | m_vfd(*this, "vfd") |
| 184 | { |
| 185 | m_eps_mode = true; |
| 186 | } |
| 187 | |
| 188 | /* panel with 2x40 VFD display used in the ESQ-1, VFX-SD, SD-1, and others */ |
| 189 | |
| 190 | static MACHINE_CONFIG_FRAGMENT(esqpanel2x40) |
| 191 | MCFG_ESQ2x40_ADD("vfd") |
| 192 | MACHINE_CONFIG_END |
| 193 | |
| 194 | machine_config_constructor esqpanel2x40_device::device_mconfig_additions() const |
| 195 | { |
| 196 | return MACHINE_CONFIG_NAME( esqpanel2x40 ); |
| 197 | } |
| 198 | |
| 199 | esqpanel2x40_device::esqpanel2x40_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 200 | esqpanel_device(mconfig, ESQPANEL2x40, "Ensoniq front panel with 2x40 VFD", tag, owner, clock), |
| 201 | m_vfd(*this, "vfd") |
| 202 | { |
| 203 | m_eps_mode = false; |
| 204 | } |
| 205 | |
| 206 | /* panel with 2x16? LCD display used in the SQ and MR series, plus probably more */ |
| 207 | |
| 208 | static MACHINE_CONFIG_FRAGMENT(esqpanel2x40_sq1) |
| 209 | MCFG_ESQ2x40_SQ1_ADD("vfd") |
| 210 | MACHINE_CONFIG_END |
| 211 | |
| 212 | machine_config_constructor esqpanel2x40_sq1_device::device_mconfig_additions() const |
| 213 | { |
| 214 | return MACHINE_CONFIG_NAME( esqpanel2x40_sq1 ); |
| 215 | } |
| 216 | |
| 217 | esqpanel2x40_sq1_device::esqpanel2x40_sq1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 218 | esqpanel_device(mconfig, ESQPANEL2x40, "Ensoniq front panel with 2x16 LCD", tag, owner, clock), |
| 219 | m_vfd(*this, "vfd") |
| 220 | { |
| 221 | m_eps_mode = false; |
| 222 | } |
| 223 | |