summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/i8251.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/i8251.cpp')
-rw-r--r--src/devices/machine/i8251.cpp445
1 files changed, 265 insertions, 180 deletions
diff --git a/src/devices/machine/i8251.cpp b/src/devices/machine/i8251.cpp
index 1c3189d8f8f..bae0d9b638f 100644
--- a/src/devices/machine/i8251.cpp
+++ b/src/devices/machine/i8251.cpp
@@ -80,10 +80,9 @@ void i8251_device::device_start()
m_rxrdy_handler.resolve_safe();
m_txrdy_handler.resolve_safe();
m_txempty_handler.resolve_safe();
+ m_syndet_handler.resolve_safe();
save_item(NAME(m_flags));
- save_item(NAME(m_sync_byte_offset));
save_item(NAME(m_sync_byte_count));
- save_item(NAME(m_sync_bytes));
save_item(NAME(m_status));
save_item(NAME(m_command));
save_item(NAME(m_mode_byte));
@@ -154,12 +153,95 @@ void i8251_device::receive_clock()
}
}
+bool i8251_device::calc_parity(u8 ch)
+{
+ bool data = 0;
+ for (u8 b = 0; b < 8; b++)
+ data ^= BIT(ch, b);
+ return data;
+}
+
+void i8251_device::sync1_rxc()
+{
+ // is rx enabled?
+ if (!BIT(m_command, 2))
+ return;
+
+ // if ext sync, and syndet low, quit
+ // Todo: what should happen here?
+ if (m_syndet_pin && !m_ext_syn_set)
+ return;
+
+ u8 need_parity = BIT(m_mode_byte, 4);
+
+ // see about parity
+ if (need_parity && (m_rxd_bits == m_data_bits_count))
+ {
+ if (calc_parity(m_sync1) != m_rxd)
+ m_status |= I8251_STATUS_PARITY_ERROR;
+ // and then continue on as if everything was ok
+ }
+ else
+ {
+ // add bit to byte
+ m_sync1 = (m_sync1 >> 1) | (m_rxd << (m_data_bits_count-1));
+ }
+
+ // if we are in hunt mode, the byte loaded has to
+ // be the sync byte. If not, go around again.
+ // if we leave hunt mode now, the sync byte must not go to the receive buffer
+ bool was_in_hunt_mode = false;
+ if (m_hunt_on)
+ {
+ if (m_sync1 == m_sync8)
+ {
+ m_rxd_bits = m_data_bits_count;
+ m_hunt_on = false;
+ was_in_hunt_mode = true;
+ }
+ else
+ return;
+ }
+
+ // is byte complete? if not, quit
+ m_rxd_bits++;
+ if (m_rxd_bits < (m_data_bits_count + need_parity))
+ return;
+
+ // now we have a synchronised byte, and parity has been dealt with
+
+ // copy byte to rx buffer
+ if (!was_in_hunt_mode)
+ receive_character(m_sync1);
+
+ // Is it a sync byte? syndet gets indicated whenever
+ // a sync byte passes by, regardless of hunt_mode status.
+ if (m_sync1 == m_sync8)
+ update_syndet(true);
+
+ m_rxd_bits = 0;
+ m_sync1 = 0;
+}
+
+void i8251_device::sync2_rxc()
+{
+ // is rx enabled?
+ if (!BIT(m_command, 2))
+ return;
+
+ // if ext sync, and syndet low, quit
+ if (m_syndet_pin && !m_ext_syn_set)
+ return;
+
+ // remainder yet to be written
+}
+
/*-------------------------------------------------
is_tx_enabled
-------------------------------------------------*/
bool i8251_device::is_tx_enabled() const
{
- return BIT(m_command , 0) && !m_cts;
+ return BIT(m_command, 0) && !m_cts;
}
/*-------------------------------------------------
@@ -196,7 +278,7 @@ void i8251_device::transmit_clock()
if (is_transmit_register_empty())
{
- if ((m_status & I8251_STATUS_TX_READY) == 0 && (is_tx_enabled() || (m_flags & I8251_DELAYED_TX_EN) != 0))
+ if ((m_status & I8251_STATUS_TX_READY) == 0 && (is_tx_enabled() || m_delayed_tx_en))
start_tx();
else
m_status |= I8251_STATUS_TX_EMPTY;
@@ -211,33 +293,6 @@ void i8251_device::transmit_clock()
uint8_t data = transmit_register_get_data_bit();
m_txd_handler(data);
}
-
-#if 0
- /* hunt mode? */
- /* after each bit has been shifted in, it is compared against the current sync byte */
- if (BIT(m_command, 7))
- {
- /* data matches sync byte? */
- if (m_data == m_sync_bytes[m_sync_byte_offset])
- {
- /* sync byte matches */
- /* update for next sync byte? */
- m_sync_byte_offset++;
-
- /* do all sync bytes match? */
- if (m_sync_byte_offset == m_sync_byte_count)
- {
- /* ent hunt mode */
- m_command &= ~(1<<7);
- }
- }
- else
- {
- /* if there is no match, reset */
- m_sync_byte_offset = 0;
- }
- }
-#endif
}
@@ -281,6 +336,32 @@ void i8251_device::update_tx_empty()
+/*---------------------------------------------------
+ update_syndet - indicates that a sync
+ character string has been received
+ 1 = valid sync; 0 = hunt mode on, or status read
+-----------------------------------------------------*/
+
+void i8251_device::update_syndet(bool voltage)
+{
+ LOG("I8251: Syndet %d\n",voltage);
+ // Sanity check
+ if (voltage && m_hunt_on)
+ printf("I8251: Syndet - invalid parameters\n");
+
+ // Adjust status register
+ if (voltage)
+ m_status |= 0x40;
+ else
+ m_status &= ~0x40;
+
+ // If syndet is set as an output pin, indicate new status
+ if (!m_syndet_pin)
+ m_syndet_handler(voltage);
+}
+
+
+
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
@@ -301,11 +382,8 @@ void i8251_device::device_reset()
transmit_register_reset();
receive_register_reset();
- m_flags = 0;
/* expecting mode byte */
- m_flags |= I8251_EXPECTING_MODE;
- /* not expecting a sync byte */
- m_flags &= ~I8251_EXPECTING_SYNC_BYTE;
+ m_flags = I8251_NEXT_MODE;
/* no character to read by cpu */
/* transmitter is ready and is empty */
@@ -401,9 +479,20 @@ void i8251_device::command_w(uint8_t data)
// datasheet says "returns to mode format", not
// completely resets the chip. behavior of DEC Rainbow
// backs this up.
- m_flags |= I8251_EXPECTING_MODE;
+ m_flags = I8251_NEXT_MODE;
}
+ // Hunt mode
+ m_hunt_on = false;
+ update_syndet(false);
+ if (m_sync_byte_count)
+ m_hunt_on = BIT(data, 7);
+ if (m_hunt_on)
+ m_ext_syn_set = false;
+
+ if (BIT(data, 3))
+ m_txd_handler(0);
+
check_for_tx_start();
update_rx_ready();
update_tx_ready();
@@ -412,13 +501,10 @@ void i8251_device::command_w(uint8_t data)
void i8251_device::mode_w(uint8_t data)
{
- LOG("I8251: Mode byte = %X\n", data);
+ LOG("I8251: Mode byte = %02X\n", data);
m_mode_byte = data;
- /* Synchronous or Asynchronous? */
- if ((data & 0x03) != 0)
- {
/* Asynchronous
bit 7,6: stop bit length
@@ -442,159 +528,144 @@ void i8251_device::mode_w(uint8_t data)
1 = x1
2 = x16
3 = x64
- */
-
- LOG("I8251: Asynchronous operation\n");
-
- const int data_bits_count = ((data >> 2) & 0x03) + 5;
- LOG("Character length: %d\n", data_bits_count);
-
- parity_t parity;
- if (BIT(data, 4))
- {
- if (BIT(data, 5))
- {
- LOG("enable parity checking (even parity)\n");
- parity = PARITY_EVEN;
- }
- else
- {
- LOG("enable parity checking (odd parity)\n");
- parity = PARITY_ODD;
- }
- }
- else
- {
- LOG("parity check disabled\n");
- parity = PARITY_NONE;
- }
+
+ Synchronous
+
+ bit 7: Number of sync characters
+ 0 = 1 character
+ 1 = 2 character
+ bit 6: Synchronous mode
+ 0 = Internal synchronisation
+ 1 = External synchronisation
+ bit 5: parity type
+ 0 = parity odd
+ 1 = parity even
+ bit 4: parity test enable
+ 0 = disable
+ 1 = enable
+ bit 3,2: character length
+ 0 = 5 bits
+ 1 = 6 bits
+ 2 = 7 bits
+ 3 = 8 bits
+ bit 1,0 = 0
+ */
- stop_bits_t stop_bits;
- switch ((data >> 6) & 0x03)
- {
- case 0:
- default:
- stop_bits = STOP_BITS_0;
- LOG("stop bit: inhibit\n");
- break;
+ m_data_bits_count = ((data >> 2) & 0x03) + 5;
+ LOG("Character length: %d\n", m_data_bits_count);
- case 1:
- stop_bits = STOP_BITS_1;
- LOG("stop bit: 1 bit\n");
+ parity_t parity = PARITY_NONE;
+ switch (data & 0x30)
+ {
+ case 0x10:
+ LOG("Enable ODD parity checking.\n");
+ parity = PARITY_ODD;
break;
- case 2:
- stop_bits = STOP_BITS_1_5;
- LOG("stop bit: 1.5 bits\n");
+ case 0x30:
+ LOG("Enable EVEN parity checking.\n");
+ parity = PARITY_EVEN;
break;
- case 3:
- stop_bits = STOP_BITS_2;
- LOG("stop bit: 2 bits\n");
- break;
- }
+ default:
+ LOG("Disable parity check.\n");
+ }
+ stop_bits_t stop_bits = STOP_BITS_0;
+ m_br_factor = 1;
+ m_flags = I8251_NEXT_COMMAND;
+ m_sync_byte_count = 0;
+ m_syndet_pin = false;
- set_data_frame(1, data_bits_count, parity, stop_bits);
- receive_register_reset();
+ /* Synchronous or Asynchronous? */
+ if (data & 0x03)
+ {
+ LOG("I8251: Asynchronous operation\n");
- switch (data & 0x03)
+ switch (data & 0xc0)
{
- case 1: m_br_factor = 1; break;
- case 2: m_br_factor = 16; break;
- case 3: m_br_factor = 64; break;
+ case 0x40:
+ stop_bits = STOP_BITS_1;
+ LOG("stop bit: 1 bit\n");
+ break;
+
+ case 0x80:
+ stop_bits = STOP_BITS_1_5;
+ LOG("stop bit: 1.5 bits\n");
+ break;
+
+ case 0xc0:
+ stop_bits = STOP_BITS_2;
+ LOG("stop bit: 2 bits\n");
+ break;
+
+ default:
+ LOG("stop bit: inhibit\n");
+ break;
}
- m_txc_count = 0;
-
-#if 0
- /* data bits */
- m_receive_char_length = (((data >> 2) & 0x03) + 5);
+ set_data_frame(1, m_data_bits_count, parity, stop_bits);
- if (BIT(data, 4))
+ switch (data & 0x03)
{
- /* parity */
- m_receive_char_length++;
- }
+ case 2:
+ m_br_factor = 16;
+ break;
- /* stop bits */
- m_receive_char_length++;
-
- m_receive_flags &= ~I8251_TRANSFER_RECEIVE_SYNCHRONISED;
- m_receive_flags |= I8251_TRANSFER_RECEIVE_WAITING_FOR_START_BIT;
-#endif
- /* not expecting mode byte now */
- m_flags &= ~I8251_EXPECTING_MODE;
- // m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY;
+ case 3:
+ m_br_factor = 64;
+ break;
+ }
}
else
{
- /* bit 7: Number of sync characters
- 0 = 1 character
- 1 = 2 character
- bit 6: Synchronous mode
- 0 = Internal synchronisation
- 1 = External synchronisation
- bit 5: parity type
- 0 = parity odd
- 1 = parity even
- bit 4: parity test enable
- 0 = disable
- 1 = enable
- bit 3,2: character length
- 0 = 5 bits
- 1 = 6 bits
- 2 = 7 bits
- 3 = 8 bits
- bit 1,0 = 0
- */
LOG("I8251: Synchronous operation\n");
/* setup for sync byte(s) */
- m_flags |= I8251_EXPECTING_SYNC_BYTE;
- m_sync_byte_offset = 0;
- if (BIT(data, 7))
- {
- m_sync_byte_count = 1;
- }
- else
- {
- m_sync_byte_count = 2;
- }
-
+ m_flags = BIT(data, 7) ? I8251_NEXT_SYNC2 : I8251_NEXT_SYNC1;
+ m_sync_byte_count = BIT(data, 7) ? 1 : 2;
+ set_data_frame(0, m_data_bits_count, parity, stop_bits);
+ m_syndet_pin = BIT(data, 6);
+ m_sync8 = 0;
+ m_sync16 = 0;
+ m_rxd_bits = 0;
+ m_sync1 = 0;
}
+
+ receive_register_reset();
+ m_txc_count = 0;
+
+ // m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY;
+}
+
+void i8251_device::sync1_w(uint8_t data)
+{
+ m_sync16 = (data << 8);
+ m_flags = I8251_NEXT_SYNC2;
+}
+
+void i8251_device::sync2_w(uint8_t data)
+{
+ if (m_sync_byte_count == 2)
+ m_sync16 |= data;
+ else
+ m_sync8 = data;
+
+ m_flags = I8251_NEXT_COMMAND;
}
void i8251_device::control_w(uint8_t data)
{
- if (m_flags & I8251_EXPECTING_MODE)
- {
- if (m_flags & I8251_EXPECTING_SYNC_BYTE)
- {
- LOG("I8251: Sync byte\n");
-
- LOG("Sync byte: %02x\n", data);
- /* store sync byte written */
- m_sync_bytes[m_sync_byte_offset] = data;
- m_sync_byte_offset++;
-
- if (m_sync_byte_offset == m_sync_byte_count)
- {
- /* finished transfering sync bytes, now expecting command */
- m_flags &= ~(I8251_EXPECTING_MODE | I8251_EXPECTING_SYNC_BYTE);
- m_sync_byte_offset = 0;
- // m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY;
- }
- }
- else
- {
- mode_w(data);
- }
- }
+ if (m_flags == I8251_NEXT_SYNC1)
+ sync1_w(data);
+ else
+ if (m_flags == I8251_NEXT_SYNC2)
+ sync2_w(data);
+ else
+ if (m_flags == I8251_NEXT_MODE)
+ mode_w(data);
else
- {
command_w(data);
- }
}
@@ -608,6 +679,9 @@ uint8_t i8251_device::status_r()
uint8_t status = (m_dsr << 7) | m_status;
LOG("status: %02x\n", status);
+
+ // Syndet always goes off after status read
+ update_syndet(false);
return status;
}
@@ -621,20 +695,15 @@ void i8251_device::data_w(uint8_t data)
{
m_tx_data = data;
- LOG("data_w %02x\n" , data);
+ LOG("data_w %02x\n", data);
/* writing clears */
m_status &=~I8251_STATUS_TX_READY;
update_tx_ready();
- // Store state of tx enable when writing to DB buffer
- if (is_tx_enabled()) {
- m_flags |= I8251_DELAYED_TX_EN;
- } else {
- m_flags &= ~I8251_DELAYED_TX_EN;
- }
-
- check_for_tx_start();
+ // Store state of tx enable when writing to DB buffer
+ m_delayed_tx_en = is_tx_enabled();
+ check_for_tx_start();
/* if transmitter is active, then tx empty will be signalled */
@@ -685,7 +754,7 @@ uint8_t i8251_device::data_r()
uint8_t i8251_device::read(offs_t offset)
{
- if (BIT(offset, 0))
+ if (offset)
return status_r();
else
return data_r();
@@ -693,7 +762,7 @@ uint8_t i8251_device::read(offs_t offset)
void i8251_device::write(offs_t offset, uint8_t data)
{
- if (BIT(offset, 0))
+ if (offset)
control_w(data);
else
data_w(data);
@@ -722,13 +791,18 @@ WRITE_LINE_MEMBER(i8251_device::write_dsr)
WRITE_LINE_MEMBER(i8251_device::write_rxc)
{
- if (m_rxc != state)
+ if (!m_rxc && state)
{
- m_rxc = state;
-
- if (m_rxc)
+ if (m_sync_byte_count == 1)
+ sync1_rxc();
+ else
+ if (m_sync_byte_count == 2)
+ sync2_rxc();
+ else
receive_clock();
}
+
+ m_rxc = state;
}
WRITE_LINE_MEMBER(i8251_device::write_txc)
@@ -742,6 +816,17 @@ WRITE_LINE_MEMBER(i8251_device::write_txc)
}
}
+// forcibly kill hunt mode
+WRITE_LINE_MEMBER(i8251_device::write_syn)
+{
+ if (m_syndet_pin && state) // must be set as input
+ {
+ m_ext_syn_set = true;
+ m_hunt_on = false;
+ update_syndet(true);
+ }
+}
+
READ_LINE_MEMBER(i8251_device::txrdy_r)
{
return is_tx_enabled() && (m_status & I8251_STATUS_TX_READY) != 0;