From 39a635d6e1a410560fbdbfe270959e596159aa9e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Oct 2019 01:27:34 +0100 Subject: [PATCH 1/8] Fixed S3 through the plane PIX_TRANS reads. --- src/video/vid_s3.c | 53 +++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index b8fd1b868..c0d0d0b03 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8,13 +8,13 @@ * * S3 emulation. * - * Version: @(#)vid_s3.c 1.0.26 2019/01/12 + * Version: @(#)vid_s3.c 1.0.27 2019/10/30 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -2379,23 +2379,6 @@ int s3_data_len(s3_t *s3) return 4; } -void s3_data_swap(s3_t *s3) -{ - uint8_t i, temp_array[4]; - uint8_t c = s3_data_len(s3); - - for (i = 0; i < 4; i++) - temp_array[i] = s3->accel.pix_trans[i]; - - if (s3_data_len(s3) < 2) - return; - - if (s3->accel.cmd & 0x1000) { - for (i = 0; i < c; i++) - s3->accel.pix_trans[i] = temp_array[i ^ (c - 1)]; - } -} - void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) { svga_t *svga = &s3->svga; @@ -2645,7 +2628,17 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + if (s3_cpu_dest(s3) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x00)) + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + else if (s3_cpu_dest(s3) && vram_mask) { + /* Mix data = current video memory value. */ + READ_SRC(s3->accel.dest + s3->accel.cx, mix_dat); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (s3_cpu_dest(s3)) { + READ_SRC(s3->accel.dest + s3->accel.cx, src_dat); + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; @@ -2657,11 +2650,11 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - if (s3_cpu_dest(s3)) { - READ_SRC(s3->accel.dest + s3->accel.cx, src_dat); + if (s3_cpu_dest(s3)) dest_dat = 0xffffffff; - } else + else { READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); + } MIX @@ -2700,28 +2693,22 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.sy--; if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) { - if (s3_cpu_dest(s3)) { + if (s3_cpu_dest(s3)) s3->data_available = 1; - s3_data_swap(s3); - } return; } if (s3->accel.sy < 0) { s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; - if (s3_cpu_dest(s3)) { + if (s3_cpu_dest(s3)) s3->data_available = 1; - s3_data_swap(s3); - } return; } } - if (s3_cpu_dest(s3) && s3->data_available) { - s3_data_swap(s3); + if (s3_cpu_dest(s3) && s3->data_available) return; - } } break; From 13402ff207859c99b27b44688b4f11ad019dfe3c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Oct 2019 01:28:36 +0100 Subject: [PATCH 2/8] Serial port fixes, fixes Windows NT 3.1 1991 builds hanging. --- src/serial.c | 130 ++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 58 deletions(-) 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; } From ddbecb039a1f6350f0c7edcf88e1492e4cd00ce5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Oct 2019 04:26:36 +0100 Subject: [PATCH 3/8] PCI PIRQ's are now always level when PCI IRQ steering is present, and MIRQ's are now edge/level according to the device that issues them, per the Intel datasheets, fixes annoyingly long wait at POST on PCI Pentium AMI BIOS'es because of secondary IDE. --- src/disk/hdc_ide_sff8038i.c | 10 +++++----- src/pci.c | 36 ++++++++++++++++-------------------- src/pci.h | 12 ++++++------ 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index ffa6a8a0c..bf712bcc8 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -10,13 +10,13 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * Version: @(#)hdc_ide_sff8038i.c 1.0.0 2019/05/12 + * Version: @(#)hdc_ide_sff8038i.c 1.0.1 2019/10/30 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -371,12 +371,12 @@ sff_bus_master_set_irq(int channel, void *priv) channel &= 0x01; if (dev->status & 0x04) { if (channel && pci_use_mirq(0)) - pci_set_mirq(0); + pci_set_mirq(0, 0); else picint(1 << (14 + channel)); } else { if ((channel & 1) && pci_use_mirq(0)) - pci_clear_mirq(0); + pci_clear_mirq(0, 0); else picintc(1 << (14 + channel)); } diff --git a/src/pci.c b/src/pci.c index ccfc4d312..b26dc203a 100644 --- a/src/pci.c +++ b/src/pci.c @@ -8,15 +8,15 @@ * * Implementation the PCI bus. * - * Version: @(#)pci.c 1.0.1 2018/11/05 + * Version: @(#)pci.c 1.0.2 2019/10/30 * * Authors: Miran Grca, * Fred N. van Kempen, * Sarah Walker, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. */ #include #include @@ -321,10 +321,9 @@ pci_use_mirq(uint8_t mirq) void -pci_set_mirq(uint8_t mirq) +pci_set_mirq(uint8_t mirq, int level) { uint8_t irq_line = 0; - uint8_t level = 0; if (! pci_mirqs[mirq].enabled) { pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); @@ -339,20 +338,21 @@ pci_set_mirq(uint8_t mirq) irq_line = pci_mirqs[mirq].irq_line; pci_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - if (pci_irq_is_level(irq_line) && - (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + if (level && (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { /* IRQ already held, do nothing. */ pci_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); return; } pci_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq); - level = pci_irq_is_level(irq_line); if (!level || !pci_irq_hold[irq_line]) { pci_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ - picintlevel(1 << irq_line); + if (level) + picintlevel(1 << irq_line); + else + picint(1 << irq_line); } else if (level && pci_irq_hold[irq_line]) { pci_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq); } @@ -376,7 +376,6 @@ pci_set_irq(uint8_t card, uint8_t pci_int) uint8_t irq_line = 0; uint8_t level = 0; - if (! last_pci_card) { pci_log("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); return; @@ -418,9 +417,9 @@ pci_set_irq(uint8_t card, uint8_t pci_int) pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); if (pci_type & PCI_NO_IRQ_STEERING) - level = 0; + level = 0; /* PCI without IRQ steering - IRQ always edge. */ else - level = pci_irq_is_level(irq_line); + level = 1; /* PCI with IRQ steering - IRQ always level per the Intel datasheets. */ if (!level || !pci_irq_hold[irq_line]) { pci_log("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); @@ -444,10 +443,9 @@ pci_set_irq(uint8_t card, uint8_t pci_int) void -pci_clear_mirq(uint8_t mirq) +pci_clear_mirq(uint8_t mirq, int level) { uint8_t irq_line = 0; - uint8_t level = 0; if (mirq > 1) { pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); @@ -467,14 +465,12 @@ pci_clear_mirq(uint8_t mirq) irq_line = pci_mirqs[mirq].irq_line; pci_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - if (pci_irq_is_level(irq_line) && - !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + if (level && !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { /* IRQ not held, do nothing. */ pci_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); return; } - level = pci_irq_is_level(irq_line); if (level) { pci_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq); pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); @@ -543,9 +539,9 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) } if (pci_type & PCI_NO_IRQ_STEERING) - level = 0; + level = 0; /* PCI without IRQ steering - IRQ always edge. */ else - level = pci_irq_is_level(irq_line); + level = 1; /* PCI with IRQ steering - IRQ always level per the Intel datasheets. */ if (level) { pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); pci_irq_hold[irq_line] &= ~(1 << card); diff --git a/src/pci.h b/src/pci.h index 4476a970c..be7347757 100644 --- a/src/pci.h +++ b/src/pci.h @@ -8,15 +8,15 @@ * * Definitions for the PCI handler module. * - * Version: @(#)pci.h 1.0.0 2018/10/21 + * Version: @(#)pci.h 1.0.1 2019/10/30 * * Authors: Miran Grca, * Fred N. van Kempen, * Sarah Walker, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. */ #ifndef EMU_PCI_H # define EMU_PCI_H @@ -76,9 +76,9 @@ extern uint8_t pci_use_mirq(uint8_t mirq); extern int pci_irq_is_level(int irq); -extern void pci_set_mirq(uint8_t mirq); +extern void pci_set_mirq(uint8_t mirq, int level); extern void pci_set_irq(uint8_t card, uint8_t pci_int); -extern void pci_clear_mirq(uint8_t mirq); +extern void pci_clear_mirq(uint8_t mirq, int level); extern void pci_clear_irq(uint8_t card, uint8_t pci_int); extern void pci_reset(void); From c06ff7f76cf0caf7ac4586dcb5f068a828f2932b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Oct 2019 18:01:23 +0100 Subject: [PATCH 4/8] Fixed for the array sizes in snd_dbopl.cc. --- src/sound/snd_dbopl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc index e2a0e079b..2ccc9e56c 100644 --- a/src/sound/snd_dbopl.cc +++ b/src/sound/snd_dbopl.cc @@ -153,7 +153,7 @@ uint8_t opl_read(int nr, uint16_t addr) void opl2_update(int nr, int16_t *buffer, int samples) { int c; - Bit32s buffer_32[SOUNDBUFLEN]; + Bit32s buffer_32[samples]; if (opl_type) { @@ -171,7 +171,7 @@ void opl2_update(int nr, int16_t *buffer, int samples) void opl3_update(int nr, int16_t *buffer, int samples) { int c; - Bit32s buffer_32[SOUNDBUFLEN*2]; + Bit32s buffer_32[samples*2]; if (opl_type) { From 84adef4c258b5369454664724031f7b358067142 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Oct 2019 18:08:35 +0100 Subject: [PATCH 5/8] PCI TRC hard resets now also reset the AT keyboard controller. --- src/keyboard.h | 3 ++- src/keyboard_at.c | 11 ++++++++++- src/pci.c | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/keyboard.h b/src/keyboard.h index 607136757..78cd50a86 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -8,7 +8,7 @@ * * Definitions for the keyboard interface. * - * Version: @(#)keyboard.h 1.0.18 2019/03/05 + * Version: @(#)keyboard.h 1.0.19 2019/10/30 * * Authors: Sarah Walker, * Miran Grca, @@ -103,6 +103,7 @@ extern void keyboard_at_adddata_mouse(uint8_t val); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); +extern void keyboard_at_reset(void); #ifdef __cplusplus } diff --git a/src/keyboard_at.c b/src/keyboard_at.c index dfe28a53b..34b8cbcd5 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,7 +8,7 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.43 2019/03/05 + * Version: @(#)keyboard_at.c 1.0.44 2019/10/30 * * Authors: Sarah Walker, * Miran Grca, @@ -2298,6 +2298,15 @@ kbd_reset(void *priv) } +/* Reset the AT keyboard - this is needed for the PCI TRC and is done + until a better solution is found. */ +void +keyboard_at_reset(void) +{ + kbd_reset(SavedKbd); +} + + static void kbd_close(void *priv) { diff --git a/src/pci.c b/src/pci.c index b26dc203a..1e27becdf 100644 --- a/src/pci.c +++ b/src/pci.c @@ -8,7 +8,7 @@ * * Implementation the PCI bus. * - * Version: @(#)pci.c 1.0.2 2019/10/30 + * Version: @(#)pci.c 1.0.3 2019/10/30 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -620,6 +620,7 @@ trc_reset(uint8_t val) flushmmucache(); pci_reset(); + keyboard_at_reset(); } resetx86(); From 1b67c97481cf882a922e852ff66af30a1c72e31e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 31 Oct 2019 05:20:40 +0100 Subject: [PATCH 6/8] Numerous serial port bug fixes, now it passes all AMIDIAG tests. --- src/serial.c | 190 ++++++++++++++++++++++++++++++++++++--------------- src/serial.h | 11 +-- 2 files changed, 141 insertions(+), 60 deletions(-) diff --git a/src/serial.c b/src/serial.c index f8f77bea1..51297a64b 100644 --- a/src/serial.c +++ b/src/serial.c @@ -8,7 +8,9 @@ * * NS8250/16450/16550 UART emulation. * - * Version: @(#)serial.h 1.0.12 2019/10/29 + * Now passes all the AMIDIAG tests. + * + * Version: @(#)serial.h 1.0.13 2019/10/31 * * Author: Sarah Walker, * Miran Grca, @@ -42,7 +44,8 @@ enum SERIAL_INT_LSR = 1, SERIAL_INT_RECEIVE = 2, SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8 + SERIAL_INT_MSR = 8, + SERIAL_INT_TIMEOUT = 16 }; @@ -77,8 +80,8 @@ serial_reset_port(serial_t *dev) dev->iir = dev->ier = dev->lcr = dev->fcr = 0; dev->fifo_enabled = 0; dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; dev->baud_cycles = 0; - dev->bytes_transmitted = 0; memset(dev->xmit_fifo, 0, 16); memset(dev->rcvr_fifo, 0, 14); } @@ -107,6 +110,10 @@ serial_update_ints(serial_t *dev) /* Line status interrupt */ stat = 1; dev->iir = 6; + } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_TIMEOUT)) { + /* Received data available */ + stat = 1; + dev->iir = 0x0c; } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) { /* Received data available */ stat = 1; @@ -131,37 +138,69 @@ serial_update_ints(serial_t *dev) } -void -serial_write_fifo(serial_t *dev, uint8_t dat) +static void +serial_clear_timeout(serial_t *dev) { - serial_log("serial_write_fifo(%08X, %02X, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled); + /* Disable timeout timer and clear timeout condition. */ + timer_disable(&dev->timeout_timer); + dev->int_status &= ~SERIAL_INT_TIMEOUT; + serial_update_ints(dev); +} + + +static void +write_fifo(serial_t *dev, uint8_t dat) +{ + serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ - dev->rcvr_fifo[dev->rcvr_fifo_pos++] = dat; - dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; + timer_disable(&dev->timeout_timer); + /* Indicate overrun. */ + if (dev->rcvr_fifo_full) + dev->lsr |= 0x02; + else + dev->rcvr_fifo[dev->rcvr_fifo_pos] = dat; dev->lsr &= 0xfe; - dev->lsr |= (!dev->rcvr_fifo_pos); dev->int_status &= ~SERIAL_INT_RECEIVE; - if (!dev->rcvr_fifo_pos) { + if (dev->rcvr_fifo_pos == (dev->rcvr_fifo_len - 1)) { + dev->lsr |= 0x01; dev->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(dev); } + if (dev->rcvr_fifo_pos < 15) + dev->rcvr_fifo_pos++; + else + dev->rcvr_fifo_full = 1; + serial_update_ints(dev); + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); } else { /* Non-FIFO mode. */ + /* Indicate overrun. */ + if (dev->lsr & 0x01) + dev->lsr |= 0x02; dev->dat = dat; - dev->lsr |= 1; + dev->lsr |= 0x01; dev->int_status |= SERIAL_INT_RECEIVE; serial_update_ints(dev); } } +void +serial_write_fifo(serial_t *dev, uint8_t dat) +{ + serial_log("serial_write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + + if (!(dev->mctrl & 0x10)) + write_fifo(dev, dat); +} + + void serial_transmit(serial_t *dev, uint8_t val) { if (dev->mctrl & 0x10) - serial_write_fifo(dev, val); + write_fifo(dev, val); else if (dev->sd->dev_write) dev->sd->dev_write(dev, dev->sd->priv, val); } @@ -170,19 +209,27 @@ serial_transmit(serial_t *dev, uint8_t val) static void serial_move_to_txsr(serial_t *dev) { + int i = 0; + if (dev->fifo_enabled) { - dev->txsr = dev->xmit_fifo[dev->xmit_fifo_pos]; - dev->xmit_fifo[dev->xmit_fifo_pos++] = 0; + dev->txsr = dev->xmit_fifo[0]; + if (dev->xmit_fifo_pos > 0) { + /* Move the entire fifo forward by one byte. */ + for (i = 1; i < 16; i++) + dev->xmit_fifo[i - 1] = dev->xmit_fifo[i]; + /* Decrease FIFO position. */ + dev->xmit_fifo_pos--; + } } else { dev->txsr = dev->thr; dev->thr = 0; } - dev->bytes_transmitted++; + dev->lsr &= ~0x40; + serial_log("serial_move_to_txsr(): FIFO %sabled, FIFO pos = %i\n", dev->fifo_enabled ? "en" : "dis", dev->xmit_fifo_pos & 0x0f); - if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 16)) { - /* Update interrupts to signal THRE. */ - dev->xmit_fifo_pos = 0; + if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) { + /* Update interrupts to signal THRE and that TXSR is no longer empty. */ dev->lsr |= 0x20; dev->int_status |= SERIAL_INT_TRANSMIT; serial_update_ints(dev); @@ -191,7 +238,8 @@ serial_move_to_txsr(serial_t *dev) dev->baud_cycles++; else dev->baud_cycles = 0; /* If not moving while transmitting, reset BAUDOUT cycle count. */ - dev->transmit_enabled &= ~1; /* Stop moving. */ + if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) + dev->transmit_enabled &= ~1; /* Stop moving. */ dev->transmit_enabled |= 2; /* Start transmitting. */ } @@ -199,13 +247,14 @@ serial_move_to_txsr(serial_t *dev) static void serial_process_txsr(serial_t *dev) { + serial_log("serial_process_txsr(): FIFO %sabled\n", dev->fifo_enabled ? "en" : "dis"); 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)) + if (dev->fifo_enabled && (dev->xmit_fifo_pos != 0x0)) dev->transmit_enabled |= 1; else { /* Both FIFO/THR and TXSR are empty. */ @@ -213,7 +262,6 @@ serial_process_txsr(serial_t *dev) 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); @@ -247,18 +295,45 @@ serial_transmit_timer(void *priv) timer_on_auto(&dev->transmit_timer, dev->transmit_period); } else { dev->baud_cycles = 0; - dev->bytes_transmitted = 0; return; } } +static void +serial_timeout_timer(void *priv) +{ + serial_t *dev = (serial_t *) priv; + +#ifdef ENABLE_SERIAL_LOG + serial_log("serial_timeout_timer()\n"); +#endif + + dev->lsr |= 0x01; + dev->int_status |= SERIAL_INT_TIMEOUT; + serial_update_ints(dev); +} + + static void serial_update_speed(serial_t *dev) { - if (dev->transmit_enabled & 3) { + if (dev->transmit_enabled & 3) timer_on_auto(&dev->transmit_timer, dev->transmit_period); - } + + if (timer_is_enabled(&dev->timeout_timer)) + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); +} + + +static void +serial_reset_fifo(serial_t *dev) +{ + dev->lsr = (dev->lsr & 0xfe) | 0x60; + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; } @@ -286,20 +361,13 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->int_status &= ~SERIAL_INT_TRANSMIT; serial_update_ints(dev); - if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { - /* FIFO mode. */ + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled && (dev->xmit_fifo_pos < 16)) { + /* FIFO mode, begin transmitting. */ + timer_on_auto(&dev->transmit_timer, dev->transmit_period); + dev->transmit_enabled |= 1; /* Start moving. */ dev->xmit_fifo[dev->xmit_fifo_pos++] = val; - dev->xmit_fifo_pos &= 0x0f; - - if (dev->xmit_fifo_pos == 0) { - /* FIFO full, begin transmitting. */ - 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_on_auto(&dev->transmit_timer, dev->transmit_period); dev->transmit_enabled |= 1; /* Start moving. */ dev->thr = val; @@ -312,25 +380,29 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_update_speed(dev); return; } + if ((val & 2) && (dev->lsr & 0x20)) + dev->int_status |= SERIAL_INT_TRANSMIT; dev->ier = val & 0xf; serial_update_ints(dev); break; case 2: if (dev->type >= SERIAL_NS16550) { - if ((val ^ dev->fcr) & 0x04) - dev->lsr |= 0x60; + if ((val ^ dev->fcr) & 0x01) + serial_reset_fifo(dev); dev->fcr = val & 0xf9; dev->fifo_enabled = val & 0x01; if (!dev->fifo_enabled) { memset(dev->rcvr_fifo, 0, 14); memset(dev->xmit_fifo, 0, 16); - dev->rcvr_fifo_pos = dev->xmit_fifo_pos = 0; + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; dev->rcvr_fifo_len = 1; break; } if (val & 0x02) { memset(dev->rcvr_fifo, 0, 14); dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; } if (val & 0x04) { memset(dev->xmit_fifo, 0, 16); @@ -350,6 +422,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->rcvr_fifo_len = 14; break; } + serial_log("FIFO now %sabled, receive FIFO length = %i\n", dev->fifo_enabled ? "en" : "dis", dev->rcvr_fifo_len); } break; case 3: @@ -375,6 +448,10 @@ serial_write(uint16_t addr, uint8_t val, void *p) if (dev->sd->rcr_callback) dev->sd->rcr_callback(dev, dev->sd->priv); } + if (!(val & 8) && (dev->mctrl & 8)) + picintc(1 << dev->irq); + if ((val ^ dev->mctrl) & 0x10) + serial_reset_fifo(dev); dev->mctrl = val; if (val & 0x10) { new_msr = (val & 0x0c) << 4; @@ -393,6 +470,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->msr = new_msr; dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; } break; case 5: @@ -423,7 +501,7 @@ uint8_t serial_read(uint16_t addr, void *p) { serial_t *dev = (serial_t *)p; - uint8_t ret = 0; + uint8_t i, ret = 0; sub_cycles(ISA_CYCLES(8)); @@ -436,22 +514,23 @@ serial_read(uint16_t addr, void *p) if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ - if (dev->mctrl & 0x10) { - ret = dev->xmit_fifo[dev->xmit_fifo_pos++]; - dev->xmit_fifo_pos %= 16; - if (!dev->xmit_fifo_pos) { - dev->lsr &= 0xfe; - dev->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(dev); - } + + serial_clear_timeout(dev); + + ret = dev->rcvr_fifo[0]; + dev->rcvr_fifo_full = 0; + if (dev->rcvr_fifo_pos > 0) { + for (i = 1; i < 16; i++) + dev->rcvr_fifo[i - 1] = dev->rcvr_fifo[i]; + serial_log("FIFO position %i: read %02X, next %02X\n", dev->rcvr_fifo_pos, ret, dev->rcvr_fifo[0]); + dev->rcvr_fifo_pos--; + /* At least one byte remains to be read, start the timeout + timer so that a timeout is indicated in case of no read. */ + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); } else { - ret = dev->rcvr_fifo[dev->rcvr_fifo_pos++]; - dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; - if (!dev->rcvr_fifo_pos) { - dev->lsr &= 0xfe; - dev->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(dev); - } + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); } } else { ret = dev->dat; @@ -599,6 +678,7 @@ serial_init(const device_t *info) dev->fcr = 0x06; serial_transmit_period(dev); timer_add(&dev->transmit_timer, serial_transmit_timer, dev, 0); + timer_add(&dev->timeout_timer, serial_timeout_timer, dev, 0); } next_inst++; diff --git a/src/serial.h b/src/serial.h index 2cfca14cd..73238c87b 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,7 +8,7 @@ * * Definitions for the NS8250/16450/16550 UART emulation. * - * Version: @(#)serial.h 1.0.11 2019/10/11 + * Version: @(#)serial.h 1.0.12 2019/10/31 * * Author: Sarah Walker, * Miran Grca, @@ -44,14 +44,15 @@ typedef struct serial_s dat, int_status, scratch, fcr, irq, type, inst, transmit_enabled, fifo_enabled, rcvr_fifo_len, bits, data_bits, - baud_cycles, bytes_transmitted, txsr, pad; + baud_cycles, rcvr_fifo_full, txsr, pad; uint16_t dlab, base_address; - uint8_t rcvr_fifo_pos, rcvr_fifo[14]; - uint8_t xmit_fifo_pos, xmit_fifo[16]; + uint8_t rcvr_fifo_pos, xmit_fifo_pos, + pad0, pad1, + rcvr_fifo[16], xmit_fifo[16]; - pc_timer_t transmit_timer; + pc_timer_t transmit_timer, timeout_timer; double transmit_period; struct serial_device_s *sd; From eae3c77044cfa9af641b41bccffcca0eb3eab5e2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 31 Oct 2019 05:21:51 +0100 Subject: [PATCH 7/8] Converted the serial mouse code to my advanced timer API, which makes the code a bit cleaner (less casts and multiplications with TIMER_USEC). --- src/mouse_serial.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mouse_serial.c b/src/mouse_serial.c index f2038c368..c96a7598d 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.28 2019/03/23 + * Version: @(#)mouse_serial.c 1.0.29 2019/10/31 * * Author: Fred N. van Kempen, */ @@ -112,10 +112,7 @@ sermouse_timer_on(mouse_t *dev, double period, int report) enabled = &dev->command_enabled; } - if (*enabled) - timer_advance_u64(timer, (uint64_t) (period * (double)TIMER_USEC)); - else - timer_set_delay_u64(timer, (uint64_t) (period * (double)TIMER_USEC)); + timer_on_auto(timer, period); *enabled = 1; } @@ -175,7 +172,7 @@ sermouse_callback(struct serial_s *serial, void *priv) if (dev->id[0] != 'H') dev->format = 7; dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); - timer_disable(&dev->command_timer); + timer_stop(&dev->command_timer); sub_cycles(ISA_CYCLES(8)); #ifdef USE_NEW_DYNAREC sermouse_timer_on(dev, 5000.0, 0); @@ -367,7 +364,7 @@ sermouse_command_pos_check(mouse_t *dev, int len) if (++dev->command_pos == len) sermouse_command_phase_idle(dev); else - timer_advance_u64(&dev->command_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); + timer_on_auto(&dev->command_timer, dev->transmit_period); } @@ -434,6 +431,8 @@ sermouse_update_data(mouse_t *dev) dev->lastb = dev->oldb; + mouse_serial_log("sermouse_update_data(): ret = %i\n", ret); + return ret; } @@ -585,8 +584,6 @@ ltsermouse_prompt_mode(mouse_t *dev, int prompt) dev->status &= 0xBF; if (prompt) dev->status |= 0x40; - /* timer_disable(&dev->report_timer); - dev->report_enabled = 0; */ } @@ -595,7 +592,7 @@ ltsermouse_command_phase(mouse_t *dev, int phase) { dev->command_pos = 0; dev->command_phase = phase; - timer_disable(&dev->command_timer); + timer_stop(&dev->command_timer); sermouse_timer_on(dev, dev->transmit_period, 0); } @@ -604,7 +601,7 @@ static void ltsermouse_set_report_period(mouse_t *dev, int rps) { dev->report_period = sermouse_transmit_period(dev, 9600, rps); - timer_disable(&dev->report_timer); + timer_stop(&dev->report_timer); sermouse_timer_on(dev, dev->report_period, 1); ltsermouse_prompt_mode(dev, 0); dev->report_phase = REPORT_PHASE_PREPARE; @@ -681,7 +678,7 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) case 0x4F: ltsermouse_prompt_mode(dev, 0); dev->report_period = 0; - timer_disable(&dev->report_timer); + timer_stop(&dev->report_timer); dev->report_phase = REPORT_PHASE_PREPARE; sermouse_report_timer((void *) dev); break; @@ -726,7 +723,7 @@ sermouse_speed_changed(void *priv) mouse_t *dev = (mouse_t *)priv; if (dev->report_enabled) { - timer_disable(&dev->report_timer); + timer_stop(&dev->report_timer); if (dev->report_phase == REPORT_PHASE_TRANSMIT) sermouse_timer_on(dev, dev->transmit_period, 1); else @@ -734,7 +731,7 @@ sermouse_speed_changed(void *priv) } if (dev->command_enabled) { - timer_disable(&dev->command_timer); + timer_stop(&dev->command_timer); sermouse_timer_on(dev, dev->transmit_period, 0); } } From 353329e394471ac70da7c082bb76f2d0918bd4e2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 31 Oct 2019 05:25:03 +0100 Subject: [PATCH 8/8] 86Box v2.03 Stable/Final release. --- src/86box.h | 6 +++--- src/win/86Box.rc | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/86box.h b/src/86box.h index e9fa19a25..a85123e48 100644 --- a/src/86box.h +++ b/src/86box.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)86box.h 1.0.30 2019/10/23 + * Version: @(#)86box.h 1.0.31 2019/10/31 * * Authors: Miran Grca, *f Fred N. van Kempen, @@ -30,8 +30,8 @@ #define EMU_NAME "86Box" #define EMU_NAME_W L"86Box" #ifdef RELEASE_BUILD -#define EMU_VERSION "2.02" -#define EMU_VERSION_W L"2.02" +#define EMU_VERSION "2.03" +#define EMU_VERSION_W L"2.03" #else #define EMU_VERSION "2.10" #define EMU_VERSION_W L"2.10" diff --git a/src/win/86Box.rc b/src/win/86Box.rc index e02942cf5..59c80990f 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.49 2019/10/23 + * Version: @(#)86Box.rc 1.0.50 2019/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -225,7 +225,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,129,94,71,12 ICON 100,IDC_ABOUT_ICON,7,7,20,20 #ifdef RELEASE_BUILD - LTEXT "86Box v2.02 - An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", + LTEXT "86Box v2.03 - An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", IDC_ABOUT_ICON,54,7,146,73 #else LTEXT "86Box v2.10 - An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", @@ -980,8 +980,8 @@ END VS_VERSION_INFO VERSIONINFO #ifdef RELEASE_BUILD - FILEVERSION 2,2,0,0 - PRODUCTVERSION 2,2,0,0 + FILEVERSION 2,3,0,0 + PRODUCTVERSION 2,3,0,0 #else FILEVERSION 2,10,0,0 PRODUCTVERSION 2,10,0,0 @@ -1004,7 +1004,7 @@ BEGIN VALUE "CompanyName", "IRC #SoftHistory\0" VALUE "FileDescription", "86Box - an emulator for X86-based systems\0" #ifdef RELEASE_BUILD - VALUE "FileVersion", "2.02\0" + VALUE "FileVersion", "2.03\0" #else VALUE "FileVersion", "2.10\0" #endif @@ -1015,7 +1015,7 @@ BEGIN VALUE "PrivateBuild", "\0" VALUE "ProductName", "86Box Emulator\0" #ifdef RELEASE_BUILD - VALUE "ProductVersion", "2.02\0" + VALUE "ProductVersion", "2.03\0" #else VALUE "ProductVersion", "2.10\0" #endif