diff --git a/src/serial.c b/src/serial.c
index 6761c04d3..f8f77bea1 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -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,
* Miran Grca,
@@ -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;
}