static void duart68681_write_TX(duart68681_state* duart68681, int ch, UINT8 data) { attotime period; duart68681->channel[ch].tx_data = data; // tx_ready will stay on in local loopback mode if ((duart68681->channel[ch].MR2 & 0xc0) != 0x80) { duart68681->channel[ch].tx_ready = 0; duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY; } if (ch == 0) duart68681->ISR &= ~INT_TXRDYA; else duart68681->ISR &= ~INT_TXRDYB; duart68681_update_interrupts(duart68681); period = ATTOTIME_IN_HZ(duart68681->channel[ch].baud_rate / 10 ); timer_adjust_oneshot(duart68681->channel[ch].tx_timer, period, ch); // if local loopback is on, write the transmitted data as if a byte had been recieved if ((duart68681->channel[ch].MR2&0xC0) == 0x80) { if ( duart68681->channel[ch].rx_fifo_num >= RX_FIFO_SIZE ) { LOG(( "68681: FIFO overflow\n" )); duart68681->channel[ch].SR |= STATUS_OVERRUN_ERROR; return; } duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_write_ptr++] = data; if ( duart68681->channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE ) { duart68681->channel[ch].rx_fifo_write_ptr = 0; } duart68681->channel[ch].rx_fifo_num++; duart68681_update_interrupts(duart68681); } };
static void duart68681_write_MR(duart68681_state *duart68681, int ch, UINT8 data) { if ( duart68681->channel[ch].MR_ptr == 0 ) { duart68681->channel[ch].MR1 = data; duart68681->channel[ch].MR_ptr = 1; } else { duart68681->channel[ch].MR2 = data; } duart68681_update_interrupts(duart68681); };
static TIMER_CALLBACK( duart_timer_callback ) { device_t *device = (device_t *)ptr; duart68681_state *duart68681 = get_safe_token(device); duart68681->ISR |= INT_COUNTER_READY; duart68681_update_interrupts(duart68681); // if ((duart68681->OPCR & 0x0c)== 0x04) { // duart68681->OPR ^= 0x08; // if (duart68681->duart_config->output_port_write) // duart68681->duart_config->output_port_write(duart68681->device, duart68681->OPR ^ 0xff); // // } };
static TIMER_CALLBACK( tx_timer_callback ) { device_t *device = (device_t *)ptr; duart68681_state *duart68681 = get_safe_token(device); int ch = param & 1; // send the byte unless we're in loopback mode; // in loopback mode do NOT 'actually' send the byte: the TXn pin is held high when loopback mode is on. if ((duart68681->duart_config->tx_callback) && ((duart68681->channel[ch].MR2&0xC0) != 0x80)) duart68681->duart_config->tx_callback(device, ch, duart68681->channel[ch].tx_data); // if local loopback is on, write the transmitted data as if a byte had been received if ((duart68681->channel[ch].MR2 & 0xC0) == 0x80) { if (duart68681->channel[ch].rx_fifo_num >= RX_FIFO_SIZE) { LOG(( "68681: FIFO overflow\n" )); duart68681->channel[ch].SR |= STATUS_OVERRUN_ERROR; } else { duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_write_ptr++] = duart68681->channel[ch].tx_data; if (duart68681->channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE) { duart68681->channel[ch].rx_fifo_write_ptr = 0; } duart68681->channel[ch].rx_fifo_num++; } } duart68681->channel[ch].tx_ready = 1; duart68681->channel[ch].SR |= STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR |= INT_TXRDYA; else duart68681->ISR |= INT_TXRDYB; duart68681_update_interrupts(duart68681); duart68681->channel[ch].tx_timer->adjust(attotime::never, ch); };
static void duart68681_write_TX(duart68681_state* duart68681, int ch, UINT8 data) { attotime period; duart68681->channel[ch].tx_data = data; duart68681->channel[ch].tx_ready = 0; duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR &= ~INT_TXRDYA; else duart68681->ISR &= ~INT_TXRDYB; duart68681_update_interrupts(duart68681); period = attotime::from_hz(duart68681->channel[ch].baud_rate / 10 ); duart68681->channel[ch].tx_timer->adjust(period, ch); };
void duart68681_rx_data( device_t* device, int ch, UINT8 data ) { duart68681_state *duart68681 = get_safe_token(device); if ( duart68681->channel[ch].rx_enabled ) { if ( duart68681->channel[ch].rx_fifo_num >= RX_FIFO_SIZE ) { LOG(( "68681: FIFO overflow\n" )); duart68681->channel[ch].SR |= STATUS_OVERRUN_ERROR; return; } duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_write_ptr++] = data; if ( duart68681->channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE ) { duart68681->channel[ch].rx_fifo_write_ptr = 0; } duart68681->channel[ch].rx_fifo_num++; duart68681_update_interrupts(duart68681); } };
static UINT8 duart68681_read_rx_fifo(duart68681_state *duart68681, int ch) { UINT8 r; if ( duart68681->channel[ch].rx_fifo_num == 0 ) { LOG(( "68681: rx fifo underflow\n" )); return 0x0; } r = duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_read_ptr++]; if ( duart68681->channel[ch].rx_fifo_read_ptr == RX_FIFO_SIZE ) { duart68681->channel[ch].rx_fifo_read_ptr = 0; } duart68681->channel[ch].rx_fifo_num--; duart68681_update_interrupts(duart68681); return r; };
static TIMER_CALLBACK( tx_timer_callback ) { device_t *device = (device_t *)ptr; duart68681_state *duart68681 = get_safe_token(device); int ch = param & 1; // send the byte unless we're in loopback mode; // in loopback mode do NOT 'actually' send the byte: the TXn pin is held high when loopback mode is on. if ((duart68681->duart_config->tx_callback) && ((duart68681->channel[ch].MR2&0xC0) != 0x80)) duart68681->duart_config->tx_callback(device, ch, duart68681->channel[ch].tx_data); duart68681->channel[ch].tx_ready = 1; duart68681->channel[ch].SR |= STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR |= INT_TXRDYA; else duart68681->ISR |= INT_TXRDYB; duart68681_update_interrupts(duart68681); timer_adjust_oneshot(duart68681->channel[ch].tx_timer, attotime_never, ch); };
static void duart68681_write_CR(duart68681_state *duart68681, int ch, UINT8 data) { duart68681->channel[ch].CR = data; switch( (data >> 4) & 0x07 ) { case 0: /* No command */ break; case 1: /* Reset MR pointer. Causes the Channel A MR pointer to point to MR1 */ duart68681->channel[ch].MR_ptr = 0; break; case 2: /* Reset channel A receiver (disable receiver and flush fifo) */ duart68681->channel[ch].rx_enabled = 0; duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY; duart68681->channel[ch].SR &= ~STATUS_OVERRUN_ERROR; // is this correct? duart68681->channel[ch].rx_fifo_read_ptr = 0; duart68681->channel[ch].rx_fifo_write_ptr = 0; duart68681->channel[ch].rx_fifo_num = 0; break; case 3: /* Reset channel A transmitter */ duart68681->channel[ch].tx_enabled = 0; duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR &= ~INT_TXRDYA; else duart68681->ISR &= ~INT_TXRDYB; duart68681->channel[ch].tx_timer->adjust(attotime::never, ch); break; case 4: /* Reset Error Status */ duart68681->channel[ch].SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR); break; case 5: /* Reset Channel break change interrupt */ if ( ch == 0 ) { duart68681->ISR &= ~INT_DELTA_BREAK_A; } else { duart68681->ISR &= ~INT_DELTA_BREAK_B; } break; /* 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 */ default: LOG(( "68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, ch )); break; } duart68681_update_interrupts(duart68681); if (BIT(data, 0)) { duart68681->channel[ch].rx_enabled = 1; } if (BIT(data, 1)) { duart68681->channel[ch].rx_enabled = 0; duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY; } if (BIT(data, 2)) { duart68681->channel[ch].tx_enabled = 1; duart68681->channel[ch].tx_ready = 1; duart68681->channel[ch].SR |= STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR |= INT_TXRDYA; else duart68681->ISR |= INT_TXRDYB; } if (BIT(data, 3)) { duart68681->channel[ch].tx_enabled = 0; duart68681->channel[ch].tx_ready = 0; duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY; if (ch == 0) duart68681->ISR &= ~INT_TXRDYA; else duart68681->ISR &= ~INT_TXRDYB; } };