Serial port fixes, fixes Windows NT 3.1 1991 builds hanging.
This commit is contained in:
130
src/serial.c
130
src/serial.c
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* NS8250/16450/16550 UART emulation.
|
* 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/>
|
* Author: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* 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:
|
/* Transmit_enable flags:
|
||||||
Bit 0 = Do move if set;
|
Bit 0 = Do move if set;
|
||||||
Bit 1 = Do transmit if set. */
|
Bit 1 = Do transmit if set. */
|
||||||
@@ -176,62 +229,26 @@ serial_transmit_timer(void *priv)
|
|||||||
serial_t *dev = (serial_t *) priv;
|
serial_t *dev = (serial_t *) priv;
|
||||||
int delay = 8; /* STOP to THRE delay is 8 BAUDOUT cycles. */
|
int delay = 8; /* STOP to THRE delay is 8 BAUDOUT cycles. */
|
||||||
|
|
||||||
if ((dev->transmit_enabled & 1) && (dev->transmit_enabled & 2))
|
if (dev->transmit_enabled & 3) {
|
||||||
delay = dev->data_bits; /* Delay by less if already transmitting. */
|
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++;
|
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 {
|
} else {
|
||||||
dev->baud_cycles = 0;
|
dev->baud_cycles = 0;
|
||||||
dev->bytes_transmitted = 0;
|
dev->bytes_transmitted = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +257,7 @@ static void
|
|||||||
serial_update_speed(serial_t *dev)
|
serial_update_speed(serial_t *dev)
|
||||||
{
|
{
|
||||||
if (dev->transmit_enabled & 3) {
|
if (dev->transmit_enabled & 3) {
|
||||||
timer_disable(&dev->transmit_timer);
|
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
|
||||||
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,16 +293,14 @@ serial_write(uint16_t addr, uint8_t val, void *p)
|
|||||||
|
|
||||||
if (dev->xmit_fifo_pos == 0) {
|
if (dev->xmit_fifo_pos == 0) {
|
||||||
/* FIFO full, begin transmitting. */
|
/* FIFO full, begin transmitting. */
|
||||||
timer_disable(&dev->transmit_timer);
|
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
|
||||||
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
|
|
||||||
dev->bytes_transmitted = 0;
|
dev->bytes_transmitted = 0;
|
||||||
dev->transmit_enabled |= 1; /* Start moving. */
|
dev->transmit_enabled |= 1; /* Start moving. */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Non-FIFO mode, begin transmitting. */
|
/* Non-FIFO mode, begin transmitting. */
|
||||||
dev->bytes_transmitted = 0;
|
dev->bytes_transmitted = 0;
|
||||||
timer_disable(&dev->transmit_timer);
|
timer_on_auto(&dev->transmit_timer, dev->transmit_period);
|
||||||
timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC));
|
|
||||||
dev->transmit_enabled |= 1; /* Start moving. */
|
dev->transmit_enabled |= 1; /* Start moving. */
|
||||||
dev->thr = val;
|
dev->thr = val;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user