Serial port fixes, fixes Windows NT 3.1 1991 builds hanging.

This commit is contained in:
OBattler
2019-10-30 01:28:36 +01:00
parent 39a635d6e1
commit 13402ff207

View File

@@ -8,7 +8,7 @@
*
* NS8250/16450/16550 UART emulation.
*
* Version: @(#)serial.h 1.0.11 2019/10/11
* Version: @(#)serial.h 1.0.12 2019/10/29
*
* Author: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -167,6 +167,59 @@ serial_transmit(serial_t *dev, uint8_t val)
}
static void
serial_move_to_txsr(serial_t *dev)
{
if (dev->fifo_enabled) {
dev->txsr = dev->xmit_fifo[dev->xmit_fifo_pos];
dev->xmit_fifo[dev->xmit_fifo_pos++] = 0;
} else {
dev->txsr = dev->thr;
dev->thr = 0;
}
dev->bytes_transmitted++;
if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 16)) {
/* Update interrupts to signal THRE. */
dev->xmit_fifo_pos = 0;
dev->lsr |= 0x20;
dev->int_status |= SERIAL_INT_TRANSMIT;
serial_update_ints(dev);
}
if (dev->transmit_enabled & 2)
dev->baud_cycles++;
else
dev->baud_cycles = 0; /* If not moving while transmitting, reset BAUDOUT cycle count. */
dev->transmit_enabled &= ~1; /* Stop moving. */
dev->transmit_enabled |= 2; /* Start transmitting. */
}
static void
serial_process_txsr(serial_t *dev)
{
serial_transmit(dev, dev->txsr);
dev->txsr = 0;
/* Reset BAUDOUT cycle count. */
dev->baud_cycles = 0;
/* If FIFO is enabled and there are bytes left to transmit,
continue with the FIFO, otherwise stop. */
if (dev->fifo_enabled && (dev->bytes_transmitted < 16))
dev->transmit_enabled |= 1;
else {
/* Both FIFO/THR and TXSR are empty. */
/* If bit 5 is set, also set bit 6 to mark both THR and shift register as empty. */
if (dev->lsr & 0x20)
dev->lsr |= 0x40;
dev->transmit_enabled &= ~2;
dev->bytes_transmitted = 0;
}
dev->int_status &= ~SERIAL_INT_TRANSMIT;
serial_update_ints(dev);
}
/* Transmit_enable flags:
Bit 0 = Do move if set;
Bit 1 = Do transmit if set. */
@@ -176,62 +229,26 @@ serial_transmit_timer(void *priv)
serial_t *dev = (serial_t *) priv;
int delay = 8; /* STOP to THRE delay is 8 BAUDOUT cycles. */
if ((dev->transmit_enabled & 1) && (dev->transmit_enabled & 2))
delay = dev->data_bits; /* Delay by less if already transmitting. */
if (dev->transmit_enabled & 3) {
if ((dev->transmit_enabled & 1) && (dev->transmit_enabled & 2))
delay = dev->data_bits; /* Delay by less if already transmitting. */
if ((dev->baud_cycles == delay) && (dev->transmit_enabled & 1)) {
/* We have processed (data bits) BAUDOUT cycles. */
if (dev->fifo_enabled) {
dev->txsr = dev->xmit_fifo[dev->xmit_fifo_pos];
dev->xmit_fifo[dev->xmit_fifo_pos++] = 0;
} else {
dev->txsr = dev->thr;
dev->thr = 0;
}
dev->bytes_transmitted++;
if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 16)) {
/* Update interrupts to signal THRE. */
dev->xmit_fifo_pos = 0;
dev->lsr |= 0x20;
dev->int_status |= SERIAL_INT_TRANSMIT;
serial_update_ints(dev);
}
if (dev->transmit_enabled & 2)
dev->baud_cycles++;
else
dev->baud_cycles = 0; /* If not moving while transmitting, reset BAUDOUT cycle count. */
dev->transmit_enabled &= ~1; /* Stop moving. */
dev->transmit_enabled |= 2; /* Start transmitting. */
timer_advance_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
} else if ((dev->baud_cycles == dev->bits) && (dev->transmit_enabled & 2)) {
/* We have processed (total bits) BAUDOUT cycles, transmit the byte. */
serial_transmit(dev, dev->txsr);
dev->txsr = 0;
/* Reset BAUDOUT cycle count. */
dev->baud_cycles = 0;
/* If FIFO is enabled and there are bytes left to transmit,
continue with the FIFO, otherwise stop. */
if (dev->fifo_enabled && (dev->bytes_transmitted == 16)) {
dev->transmit_enabled |= 1;
timer_advance_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
} else {
/* Both FIFO/THR and TXSR are empty. */
/* If bit 5 is set, also set bit 6 to mark both THR and shift register as empty. */
if (dev->lsr & 0x20)
dev->lsr |= 0x40;
dev->transmit_enabled &= ~2;
dev->bytes_transmitted = 0;
}
dev->int_status &= ~SERIAL_INT_TRANSMIT;
serial_update_ints(dev);
} else if (dev->transmit_enabled & 3) {
dev->baud_cycles++;
timer_advance_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
/* We have processed (total bits) BAUDOUT cycles, transmit the byte. */
if ((dev->baud_cycles == dev->bits) && (dev->transmit_enabled & 2))
serial_process_txsr(dev);
/* We have processed (data bits) BAUDOUT cycles. */
if ((dev->baud_cycles == delay) && (dev->transmit_enabled & 1))
serial_move_to_txsr(dev);
if (dev->transmit_enabled & 3)
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
} else {
dev->baud_cycles = 0;
dev->bytes_transmitted = 0;
return;
}
}
@@ -240,8 +257,7 @@ static void
serial_update_speed(serial_t *dev)
{
if (dev->transmit_enabled & 3) {
timer_disable(&dev->transmit_timer);
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
}
}
@@ -277,16 +293,14 @@ serial_write(uint16_t addr, uint8_t val, void *p)
if (dev->xmit_fifo_pos == 0) {
/* FIFO full, begin transmitting. */
timer_disable(&dev->transmit_timer);
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
dev->bytes_transmitted = 0;
dev->transmit_enabled |= 1; /* Start moving. */
}
} else {
/* Non-FIFO mode, begin transmitting. */
dev->bytes_transmitted = 0;
timer_disable(&dev->transmit_timer);
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
dev->transmit_enabled |= 1; /* Start moving. */
dev->thr = val;
}