diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3809ead73..bfa582e33 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,7 +20,8 @@ endif() add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c dma.c ddma.c nmi.c pic.c pit.c pit_fast.c port_6x.c port_92.c ppi.c pci.c - mca.c usb.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c ini.c) + mca.c usb.c fifo.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c + machine_status.c ini.c) if(CMAKE_SYSTEM_NAME MATCHES "Linux") add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1) diff --git a/src/device/serial.c b/src/device/serial.c index 3a5b237c2..5dd5d8420 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -35,17 +35,20 @@ #include <86box/pic.h> #include <86box/mem.h> #include <86box/rom.h> +#include <86box/fifo.h> #include <86box/serial.h> #include <86box/mouse.h> serial_port_t com_ports[SERIAL_MAX]; enum { - SERIAL_INT_LSR = 1, - SERIAL_INT_RECEIVE = 2, - SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8, - SERIAL_INT_TIMEOUT = 16 + SERIAL_INT_LSR = 1, + SERIAL_INT_TIMEOUT = 2, + SERIAL_INT_RECEIVE = 4, + SERIAL_INT_TRANSMIT = 8, + SERIAL_INT_MSR = 16, + SERIAL_INT_RX_DMA_TC = 32, + SERIAL_INT_TX_DMA_TC = 64 }; void serial_update_ints(serial_t *dev); @@ -53,7 +56,7 @@ void serial_update_ints(serial_t *dev); static int next_inst = 0; static serial_device_t serial_devices[SERIAL_MAX]; -// #define ENABLE_SERIAL_CONSOLE 1 +static void serial_xmit_d_empty_evt(void *priv); #ifdef ENABLE_SERIAL_LOG int serial_do_log = ENABLE_SERIAL_LOG; @@ -76,16 +79,23 @@ serial_log(const char *fmt, ...) void serial_reset_port(serial_t *dev) { + if (dev->type >= SERIAL_16550) { + if (dev->fifo_enabled) + fifo_reset_evt(dev->xmit_fifo); + else + fifo_reset(dev->xmit_fifo); + } + dev->lsr = 0x60; /* Mark that both THR/FIFO and TXSR are empty. */ dev->iir = dev->ier = dev->lcr = dev->fcr = 0; + dev->fifo_enabled = 0; - dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; - dev->xmit_fifo_end = dev->rcvr_fifo_end = 0; - dev->rcvr_fifo_full = 0; - dev->baud_cycles = 0; - dev->out_new = 0xffff; - memset(dev->xmit_fifo, 0, 16); - memset(dev->rcvr_fifo, 0, 16); + dev->baud_cycles = 0; + dev->out_new = 0xffff; + + dev->txsr_empty = 1; + dev->thr_empty = 1; + serial_update_ints(dev); dev->irq_state = 0; } @@ -120,33 +130,22 @@ serial_do_irq(serial_t *dev, int set) void serial_update_ints(serial_t *dev) { - int stat = 0; + /* TODO: The IRQ priorities are 6 - we need to find a way to treat timeout and receive + as equal and still somehow distinguish them. */ + uint8_t ier_map[7] = { 0x04, 0x01, 0x01, 0x02, 0x08, 0x40, 0x80 }; + uint8_t iir_map[7] = { 0x06, 0x0c, 0x04, 0x02, 0x00, 0x0e, 0x0a }; + int i; - dev->iir = 1; + dev->iir = (dev->iir & 0xf0) | 0x01; - if ((dev->ier & 4) && (dev->int_status & SERIAL_INT_LSR)) { - /* 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; - dev->iir = 4; - } else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) { - /* Transmit data empty */ - stat = 1; - dev->iir = 2; - } else if ((dev->ier & 8) && (dev->int_status & SERIAL_INT_MSR)) { - /* Modem status interrupt */ - stat = 1; - dev->iir = 0; + for (i = 0; i < 7; i++) { + if ((dev->ier & ier_map[i]) && (dev->int_status & (1 << i))) { + dev->iir = (dev->iir & 0xf0) | iir_map[i]; + break; + } } - serial_do_irq(dev, stat && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))); + serial_do_irq(dev, !(dev->iir & 0x01) && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))); } static void @@ -163,60 +162,46 @@ serial_receive_timer(void *priv) { serial_t *dev = (serial_t *) priv; -#if 0 serial_log("serial_receive_timer()\n"); -#endif timer_on_auto(&dev->receive_timer, /* dev->bits * */ dev->transmit_period); - if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) { + if (dev->fifo_enabled) { /* FIFO mode. */ - if (dev->out_new != 0xffff) { /* We have received a byte into the RSR. */ /* Clear FIFO timeout. */ serial_clear_timeout(dev); - if (dev->rcvr_fifo_full) { - /* Overrun - just discard the byte in the RSR. */ - serial_log("FIFO overrun\n"); + fifo_write_evt((uint8_t) (dev->out_new & 0xff), dev->rcvr_fifo); + dev->out_new = 0xffff; + + /* pclog("serial_receive_timer(): lsr = %02X, ier = %02X, iir = %02X, int_status = %02X\n", + dev->lsr, dev->ier, dev->iir, dev->int_status); */ + + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + } + } else { + /* Non-FIFO mode. */ + if (dev->out_new != 0xffff) { + /* We have received a byte into the RSR. */ + serial_log("Byte received: %04X\n", dev->out_new); + + /* Indicate overrun. */ + if (dev->lsr & 0x01) dev->lsr |= 0x02; - } else { - /* We can input data into the FIFO. */ - dev->rcvr_fifo[dev->rcvr_fifo_end] = (uint8_t) (dev->out_new & 0xff); -#if 0 - dev->rcvr_fifo_end = (dev->rcvr_fifo_end + 1) & 0x0f; -#endif - /* Do not wrap around, makes sure it still triggers the interrupt - at 16 bytes. */ - dev->rcvr_fifo_end++; - serial_log("To FIFO: %02X (%i, %i, %i)\n", (uint8_t) (dev->out_new & 0xff), - abs(dev->rcvr_fifo_end - dev->rcvr_fifo_pos), - dev->rcvr_fifo_end, dev->rcvr_fifo_pos); - dev->out_new = 0xffff; + dev->dat = (uint8_t) (dev->out_new & 0xff); + dev->out_new = 0xffff; - if (abs(dev->rcvr_fifo_end - dev->rcvr_fifo_pos) >= dev->rcvr_fifo_len) { - /* We have >= trigger level bytes, raise Data Ready interrupt. */ - serial_log("We have >= %i bytes in the FIFO, data ready!\n", dev->rcvr_fifo_len); - dev->lsr |= 0x01; - dev->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(dev); - } + /* Raise Data Ready interrupt. */ + dev->lsr |= 0x01; + dev->int_status |= SERIAL_INT_RECEIVE; - /* Now wrap around. */ - dev->rcvr_fifo_end &= 0x0f; - - if (dev->rcvr_fifo_end == dev->rcvr_fifo_pos) - dev->rcvr_fifo_full = 1; - - timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); - } + serial_update_ints(dev); } } - - serial_update_ints(dev); } static void @@ -224,26 +209,8 @@ write_fifo(serial_t *dev, uint8_t dat) { serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_16550) && dev->fifo_enabled, - ((dev->type >= SERIAL_16550) && dev->fifo_enabled) ? (dev->rcvr_fifo_pos % dev->rcvr_fifo_len) : 0); - - if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) { - /* FIFO mode. */ - - /* This is the first phase, we are sending the data to the RSR (Receiver Shift - Register), from where it's going to get dispatched to the FIFO. */ - } else { - /* Non-FIFO mode. */ - - /* Indicate overrun. */ - if (dev->lsr & 0x01) - dev->lsr |= 0x02; - - /* Raise Data Ready interrupt. */ - serial_log("To RHR: %02X\n", dat); - dev->lsr |= 0x01; - dev->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(dev); - } + ((dev->type >= SERIAL_16550) && dev->fifo_enabled) ? + fifo_get_count(dev->rcvr_fifo) : 0); /* Do this here, because in non-FIFO mode, this is read directly. */ dev->out_new = (uint16_t) dat; @@ -252,7 +219,10 @@ write_fifo(serial_t *dev, uint8_t dat) 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_16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + serial_log("serial_write_fifo(%08X, %02X, %i, %i)\n", dev, dat, + (dev->type >= SERIAL_16550) && dev->fifo_enabled, + ((dev->type >= SERIAL_16550) && dev->fifo_enabled) ? + fifo_get_count(dev->rcvr_fifo) : 0); if (!(dev->mctrl & 0x10)) write_fifo(dev, dat); @@ -265,48 +235,43 @@ serial_transmit(serial_t *dev, uint8_t val) write_fifo(dev, val); else if (dev->sd->dev_write) dev->sd->dev_write(dev, dev->sd->priv, val); + #ifdef ENABLE_SERIAL_CONSOLE if ((val >= ' ' && val <= '~') || val == '\r' || val == '\n') { fputc(val, stdout); if (val == '\n') fflush(stdout); - } else { + } else fprintf(stdout, "[%02X]", val); - } #endif } static void serial_move_to_txsr(serial_t *dev) { - if (dev->fifo_enabled) { - dev->txsr = dev->xmit_fifo[0]; - if (dev->xmit_fifo_pos > 0) { - /* Move the entire fifo forward by one byte. */ - for (uint8_t i = 1; i < 16; i++) - dev->xmit_fifo[i - 1] = dev->xmit_fifo[i]; - /* Decrease FIFO position. */ - dev->xmit_fifo_pos--; - } - } else { + dev->txsr_empty = 0; + if (dev->fifo_enabled) + dev->txsr = fifo_read_evt(dev->xmit_fifo); + else { dev->txsr = dev->thr; dev->thr = 0; + dev->thr_empty = 1; + serial_xmit_d_empty_evt(dev); } 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); + serial_log("serial_move_to_txsr(): FIFO %sabled, FIFO pos = %i\n", dev->fifo_enabled ? "en" : "dis", + fifo_get_count(dev->xmit_fifo) & 0x0f); - if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) { + if (!dev->fifo_enabled || (fifo_get_count(dev->xmit_fifo) == 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); } if (dev->transmit_enabled & 2) dev->baud_cycles++; else dev->baud_cycles = 0; /* If not moving while transmitting, reset BAUDOUT cycle count. */ - if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) + if (!dev->fifo_enabled || (fifo_get_count(dev->xmit_fifo) == 0x0)) dev->transmit_enabled &= ~1; /* Stop moving. */ dev->transmit_enabled |= 2; /* Start transmitting. */ } @@ -317,20 +282,18 @@ 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; + dev->txsr_empty = 1; + serial_xmit_d_empty_evt(dev); /* 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->xmit_fifo_pos != 0x0)) + if (dev->fifo_enabled && (fifo_get_count(dev->xmit_fifo) != 0x0)) 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; + /* Both FIFO/THR and TXSR are empty. */ + else dev->transmit_enabled &= ~2; - } - dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); } @@ -370,9 +333,7 @@ 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; @@ -384,9 +345,7 @@ serial_device_timeout(void *priv) { serial_t *dev = (serial_t *) priv; -#ifdef ENABLE_SERIAL_LOG serial_log("serial_device_timeout()\n"); -#endif if (!dev->fifo_enabled) { dev->lsr |= 0x10; @@ -398,6 +357,7 @@ serial_device_timeout(void *priv) static void serial_update_speed(serial_t *dev) { + serial_log("serial_update_speed(%lf)\n", dev->transmit_period); timer_on_auto(&dev->receive_timer, /* dev->bits * */ dev->transmit_period); if (dev->transmit_enabled & 3) @@ -410,11 +370,10 @@ serial_update_speed(serial_t *dev) 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; + fifo_reset_evt(dev->xmit_fifo); + fifo_reset_evt(dev->rcvr_fifo); + serial_update_ints(dev); - dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; - dev->rcvr_fifo_full = 0; } void @@ -490,7 +449,6 @@ serial_write(uint16_t addr, uint8_t val, void *p) uint8_t new_msr; uint8_t old; - // serial_log("UART: Write %02X to port %02X\n", val, addr); serial_log("UART: [%04X:%08X] Write %02X to port %02X\n", CS, cpu_state.pc, val, addr); cycles -= ISA_CYCLES(8); @@ -504,21 +462,22 @@ serial_write(uint16_t addr, uint8_t val, void *p) return; } - /* Indicate FIFO/THR is no longer empty. */ - dev->lsr &= 0x9f; - dev->int_status &= ~SERIAL_INT_TRANSMIT; - serial_update_ints(dev); - - if ((dev->type >= SERIAL_16550) && dev->fifo_enabled && (dev->xmit_fifo_pos < 16)) { + if (dev->fifo_enabled && (fifo_get_count(dev->xmit_fifo) < 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; - } else { + fifo_write_evt(val, dev->xmit_fifo); + } else if (!dev->fifo_enabled) { + /* Indicate THR is no longer empty. */ + dev->lsr &= 0x9f; + dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + /* Non-FIFO mode, begin transmitting. */ timer_on_auto(&dev->transmit_timer, dev->transmit_period); dev->transmit_enabled |= 1; /* Start moving. */ dev->thr = val; + dev->thr_empty = 0; } break; case 1: @@ -539,42 +498,42 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_reset_fifo(dev); dev->fcr = val & 0xf9; dev->fifo_enabled = val & 0x01; + /* TODO: When switching modes, shouldn't we reset the LSR + based on the new conditions? */ if (!dev->fifo_enabled) { - memset(dev->rcvr_fifo, 0, 14); - memset(dev->xmit_fifo, 0, 16); - dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; - dev->rcvr_fifo_full = 0; - dev->rcvr_fifo_len = 1; + fifo_reset(dev->xmit_fifo); + fifo_reset(dev->rcvr_fifo); break; } if (val & 0x02) { - memset(dev->rcvr_fifo, 0, 14); - dev->rcvr_fifo_pos = 0; - dev->rcvr_fifo_end = 0; - dev->rcvr_fifo_full = 0; + if (dev->fifo_enabled) + fifo_reset_evt(dev->rcvr_fifo); + else + fifo_reset(dev->rcvr_fifo); } if (val & 0x04) { - memset(dev->xmit_fifo, 0, 16); - dev->xmit_fifo_pos = 0; + if (dev->fifo_enabled) + fifo_reset_evt(dev->xmit_fifo); + else + fifo_reset(dev->xmit_fifo); } switch ((val >> 6) & 0x03) { case 0: - dev->rcvr_fifo_len = 1; + fifo_set_trigger_len(dev->rcvr_fifo, 1); break; case 1: - dev->rcvr_fifo_len = 4; + fifo_set_trigger_len(dev->rcvr_fifo, 4); break; case 2: - dev->rcvr_fifo_len = 8; + fifo_set_trigger_len(dev->rcvr_fifo, 8); break; case 3: - dev->rcvr_fifo_len = 14; - break; - default: + fifo_set_trigger_len(dev->rcvr_fifo, 14); break; } + fifo_set_trigger_len(dev->xmit_fifo, 16); dev->out_new = 0xffff; - serial_log("FIFO now %sabled, receive FIFO length = %i\n", dev->fifo_enabled ? "en" : "dis", dev->rcvr_fifo_len); + serial_log("FIFO now %sabled\n", dev->fifo_enabled ? "en" : "dis"); } break; case 3: @@ -600,8 +559,10 @@ serial_write(uint16_t addr, uint8_t val, void *p) break; case 4: if ((val & 2) && !(dev->mctrl & 2)) { - if (dev->sd && dev->sd->rcr_callback) + if (dev->sd && dev->sd->rcr_callback) { + serial_log("RTS toggle callback\n"); dev->sd->rcr_callback(dev, dev->sd->priv); + } } if (!(val & 8) && (dev->mctrl & 8)) serial_do_irq(dev, 0); @@ -624,8 +585,9 @@ 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; + /* TODO: Why reset the FIFO's here?! */ + fifo_reset(dev->xmit_fifo); + fifo_reset(dev->rcvr_fifo); } break; case 5: @@ -674,41 +636,16 @@ serial_read(uint16_t addr, void *p) break; } - /* Clear timeout. */ - serial_clear_timeout(dev); - - if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) { + if (dev->fifo_enabled) { /* FIFO mode. */ + serial_clear_timeout(dev); + ret = fifo_read_evt(dev->rcvr_fifo); - if (dev->rcvr_fifo_full || (dev->rcvr_fifo_pos != dev->rcvr_fifo_end)) { - /* There is data in the FIFO. */ - ret = dev->rcvr_fifo[dev->rcvr_fifo_pos]; - dev->rcvr_fifo_pos = (dev->rcvr_fifo_pos + 1) & 0x0f; - - /* Make sure to clear the FIFO full condition. */ - dev->rcvr_fifo_full = 0; - - if (abs(dev->rcvr_fifo_pos - dev->rcvr_fifo_end) < dev->rcvr_fifo_len) { - /* Amount of data in the FIFO below trigger level, - clear Data Ready interrupt. */ - dev->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(dev); - } - - /* Make sure the Data Ready bit of the LSR is set if we still have - bytes left in the FIFO. */ - if (dev->rcvr_fifo_pos != dev->rcvr_fifo_end) { - dev->lsr |= 0x01; - /* There are bytes left in the FIFO, activate the FIFO Timeout timer. */ - timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); - } else - dev->lsr &= 0xfe; - } + if (dev->lsr & 0x01) + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); } else { /* Non-FIFO mode. */ - - ret = (uint8_t) (dev->out_new & 0xffff); - dev->out_new = 0xffff; + ret = dev->dat; /* Always clear Data Ready interrupt. */ dev->lsr &= 0xfe; @@ -716,7 +653,7 @@ serial_read(uint16_t addr, void *p) serial_update_ints(dev); } - // serial_log("Read data: %02X\n", ret); + serial_log("Read data: %02X\n", ret); break; case 1: if (dev->lcr & 0x80) @@ -759,7 +696,6 @@ serial_read(uint16_t addr, void *p) break; } - // serial_log("UART: Read %02X from port %02X\n", ret, addr); serial_log("UART: [%04X:%08X] Read %02X from port %02X\n", CS, cpu_state.pc, ret, addr); return ret; } @@ -801,6 +737,42 @@ serial_setup(serial_t *dev, uint16_t addr, uint8_t irq) dev->irq = irq; } +static void +serial_rcvr_d_empty_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->lsr = (dev->lsr & 0xfe) | !fifo_get_empty(dev->rcvr_fifo); +} + +static void +serial_rcvr_d_overrun_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->lsr = (dev->lsr & 0xfd) | (fifo_get_overrun(dev->rcvr_fifo) << 1); +} + +static void +serial_rcvr_d_ready_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | + (fifo_get_ready(dev->rcvr_fifo) ? SERIAL_INT_RECEIVE : 0); + serial_update_ints(dev); +} + +static void +serial_xmit_d_empty_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + uint8_t is_empty = dev->fifo_enabled ? fifo_get_empty(dev->xmit_fifo) : dev->thr_empty; + + dev->lsr = (dev->lsr & 0x9f) | (is_empty << 5) | ((dev->txsr_empty && is_empty) << 6); + dev->int_status = (dev->int_status & ~SERIAL_INT_TRANSMIT) | (is_empty ? SERIAL_INT_TRANSMIT : 0); +} + serial_t * serial_attach_ex(int port, void (*rcr_callback)(struct serial_s *serial, void *p), @@ -835,6 +807,9 @@ serial_close(void *priv) next_inst--; + if (com_ports[dev->inst].enabled) + fifo_close(dev->rcvr_fifo); + free(dev); } @@ -843,27 +818,33 @@ serial_reset(void *priv) { serial_t *dev = (serial_t *) priv; - timer_disable(&dev->transmit_timer); - timer_disable(&dev->timeout_timer); - timer_disable(&dev->receive_timer); + if (com_ports[dev->inst].enabled) { + timer_disable(&dev->transmit_timer); + timer_disable(&dev->timeout_timer); + timer_disable(&dev->receive_timer); - dev->lsr = dev->thr = dev->mctrl = dev->rcr = 0x00; - dev->iir = dev->ier = dev->lcr = dev->msr = 0x00; - dev->dat = dev->int_status = dev->scratch = dev->fcr = 0x00; - dev->fifo_enabled = dev->rcvr_fifo_len = dev->bits = dev->data_bits = 0x00; - dev->baud_cycles = dev->rcvr_fifo_full = dev->txsr = dev->out = 0x00; + dev->lsr = dev->thr = dev->mctrl = dev->rcr = 0x00; + dev->iir = dev->ier = dev->lcr = dev->msr = 0x00; + dev->dat = dev->int_status = dev->scratch = dev->fcr = 0x00; + dev->fifo_enabled = dev->bits = 0x000; + dev->data_bits = dev->baud_cycles = 0x00; + dev->txsr = 0x00; + dev->txsr_empty = 0x01; + dev->thr_empty = 0x0001; - dev->dlab = dev->out_new = 0x0000; + dev->dlab = dev->out_new = 0x0000; - dev->rcvr_fifo_pos = dev->xmit_fifo_pos = dev->rcvr_fifo_end = dev->xmit_fifo_end = 0x00; + if (dev->rcvr_fifo != NULL) + fifo_reset(dev->rcvr_fifo); - serial_reset_port(dev); + serial_reset_port(dev); - dev->dlab = 96; - dev->fcr = 0x06; + dev->dlab = 96; + dev->fcr = 0x06; - serial_transmit_period(dev); - serial_update_speed(dev); + serial_transmit_period(dev); + serial_update_speed(dev); + } } static void * @@ -880,7 +861,6 @@ serial_init(const device_t *info) memset(&(serial_devices[next_inst]), 0, sizeof(serial_device_t)); dev->sd = &(serial_devices[next_inst]); dev->sd->serial = dev; - serial_reset_port(dev); if (next_inst == 3) serial_setup(dev, COM4_ADDR, COM4_IRQ); else if (next_inst == 2) @@ -902,6 +882,22 @@ serial_init(const device_t *info) timer_add(&dev->receive_timer, serial_receive_timer, dev, 0); serial_transmit_period(dev); serial_update_speed(dev); + + dev->rcvr_fifo = fifo64_init(); + fifo_set_priv(dev->rcvr_fifo, dev); + fifo_set_d_empty_evt(dev->rcvr_fifo, serial_rcvr_d_empty_evt); + fifo_set_d_overrun_evt(dev->rcvr_fifo, serial_rcvr_d_overrun_evt); + fifo_set_d_ready_evt(dev->rcvr_fifo, serial_rcvr_d_ready_evt); + fifo_reset_evt(dev->rcvr_fifo); + fifo_set_len(dev->rcvr_fifo, 16); + + dev->xmit_fifo = fifo64_init(); + fifo_set_priv(dev->xmit_fifo, dev); + fifo_set_d_empty_evt(dev->xmit_fifo, serial_xmit_d_empty_evt); + fifo_reset_evt(dev->xmit_fifo); + fifo_set_len(dev->xmit_fifo, 16); + + serial_reset_port(dev); } next_inst++; diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index b703cd67c..1b1c5e3bf 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -25,6 +25,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include <86box/fifo.h> #include <86box/timer.h> #include <86box/serial.h> #include <86box/serial_passthrough.h> @@ -78,7 +79,7 @@ host_to_serial_cb(void *priv) * can never fetch the bytes in time, so check if the fifo is full if in * fifo mode or if lsr has bit 0 set if not in fifo mode */ if ((dev->serial->type >= SERIAL_16550) && dev->serial->fifo_enabled) { - if (dev->serial->rcvr_fifo_full) { + if (fifo_get_full(dev->serial->rcvr_fifo)) { goto no_write_to_machine; } } else { diff --git a/src/fifo.c b/src/fifo.c new file mode 100644 index 000000000..e852fda31 --- /dev/null +++ b/src/fifo.c @@ -0,0 +1,582 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * FIFO infrastructure. + * + * Authors: Miran Grca, + * + * Copyright 2023 Miran Grca. + */ +#include +#include +#include +#include +#include +#ifdef FIFO_STANDALONE +#define fatal printf +#define pclog_ex printf +#define pclog printf +#include "include/86box/fifo.h" +#else +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/fifo.h> +#endif + +#ifdef ENABLE_FIFO_LOG +int fifo_do_log = ENABLE_FIFO_LOG; + +static void +fifo_log(const char *fmt, ...) +{ + va_list ap; + + if (fifo_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define fifo_log(fmt, ...) +#endif + +int +fifo_get_count(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + int ret = fifo->len; + + if (fifo->end == fifo->start) + ret = fifo->full ? fifo->len : 0; + else + ret = abs(fifo->end - fifo->start); + + return ret; +} + +void +fifo_write(uint8_t val, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = fifo->d_overrun = 0; + + if (fifo->full) + fifo->overrun = 1; + else { + fifo->buf[fifo->end] = val; + fifo->end = (fifo->end + 1) & 0x0f; + + if (fifo->end == fifo->start) + fifo->full = 1; + + fifo->empty = 0; + + if (fifo_get_count(fifo) >= fifo->trigger_len) + fifo->ready = 1; + } +} + +void +fifo_write_evt(uint8_t val, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = fifo->d_overrun = 0; + + if (fifo->full) { + fifo->d_overrun = (fifo->overrun != 1); + fifo->overrun = 1; + if (fifo->d_overrun && (fifo->d_overrun_evt != NULL)) + fifo->d_overrun_evt(fifo->priv); + } else { + fifo->buf[fifo->end] = val; + fifo->end = (fifo->end + 1) & 0x0f; + + if (fifo->end == fifo->start) { + fifo->d_full = (fifo->full != 1); + fifo->full = 1; + if (fifo->d_full && (fifo->d_full_evt != NULL)) + fifo->d_full_evt(fifo->priv); + } + + fifo->d_empty = (fifo->empty != 0); + fifo->empty = 0; + if (fifo->d_empty && (fifo->d_empty_evt != NULL)) + fifo->d_empty_evt(fifo->priv); + + if (fifo_get_count(fifo) >= fifo->trigger_len) { + fifo->d_ready = (fifo->ready != 1); + fifo->ready = 1; + if (fifo->d_ready && (fifo->d_ready_evt != NULL)) + fifo->d_ready_evt(fifo->priv); + } + } +} + +uint8_t +fifo_read(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + uint8_t ret = 0x00; + int count; + + if (!fifo->empty) { + ret = fifo->buf[fifo->start]; + fifo->start = (fifo->start + 1) & 0x0f; + + fifo->full = 0; + + count = fifo_get_count(fifo); + + if (count < fifo->trigger_len) { + fifo->ready = 0; + + if (count == 0) + fifo->empty = 1; + } + } + + return ret; +} + +uint8_t +fifo_read_evt(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + uint8_t ret = 0x00; + int count; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = 0; + + if (!fifo->empty) { + ret = fifo->buf[fifo->start]; + fifo->start = (fifo->start + 1) & 0x0f; + + fifo->d_full = (fifo->full != 0); + fifo->full = 0; + if (fifo->d_full && (fifo->d_full_evt != NULL)) + fifo->d_full_evt(fifo->priv); + + count = fifo_get_count(fifo); + + if (count < fifo->trigger_len) { + fifo->d_ready = (fifo->ready != 0); + fifo->ready = 0; + if (fifo->d_ready && (fifo->d_ready_evt != NULL)) + fifo->d_ready_evt(fifo->priv); + + if (count == 0) { + fifo->d_empty = (fifo->empty != 1); + fifo->empty = 1; + if (fifo->d_empty && (fifo->d_empty_evt != NULL)) + fifo->d_empty_evt(fifo->priv); + } + } + } + + return ret; +} + +void +fifo_clear_overrun(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_overrun = (fifo->overrun != 0); + fifo->overrun = 0; +} + +int +fifo_get_full(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + return fifo->full; +} + +int +fifo_get_d_full(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + int ret = fifo->d_full; + + fifo->d_full = 0; + return ret; +} + +int +fifo_get_empty(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + return fifo->empty; +} + +int +fifo_get_d_empty(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + int ret = fifo->d_empty; + + fifo->d_empty = 0; + return ret; +} + +int +fifo_get_overrun(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + return fifo->overrun; +} + +int +fifo_get_d_overrun(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + int ret = fifo->d_overrun; + + fifo->d_overrun = 0; + return ret; +} + +int +fifo_get_ready(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + return fifo->ready; +} + +int +fifo_get_d_ready(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + int ret = fifo->d_ready; + + fifo->d_ready = 0; + return ret; +} + +int +fifo_get_trigger_len(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + return fifo->trigger_len; +} + +void +fifo_set_trigger_len(void *priv, int trigger_len) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->trigger_len = trigger_len; +} + +void +fifo_set_len(void *priv, int len) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->len = len; +} + +void +fifo_set_d_full_evt(void *priv, void (*d_full_evt)(void *)) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_full_evt = d_full_evt; +} + +void +fifo_set_d_empty_evt(void *priv, void (*d_empty_evt)(void *)) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_empty_evt = d_empty_evt; +} + +void +fifo_set_d_overrun_evt(void *priv, void (*d_overrun_evt)(void *)) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_overrun_evt = d_overrun_evt; +} + +void +fifo_set_d_ready_evt(void *priv, void (*d_ready_evt)(void *)) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_ready_evt = d_ready_evt; +} + +void +fifo_set_priv(void *priv, void *sub_priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->priv = sub_priv; +} + +void +fifo_reset(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->start = fifo->end = 0; + fifo->full = fifo->overrun = 0; + fifo->empty = 1; + fifo->ready = 0; +} + +void +fifo_reset_evt(void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->start = fifo->end = 0; + fifo->full = fifo->overrun = 0; + fifo->empty = 1; + fifo->ready = 0; + fifo->d_full = fifo->d_overrun = 0; + fifo->d_empty = fifo->d_ready = 0; + + if (fifo->d_full_evt != NULL) + fifo->d_full_evt(fifo->priv); + + if (fifo->d_overrun_evt != NULL) + fifo->d_overrun_evt(fifo->priv); + + if (fifo->d_empty_evt != NULL) + fifo->d_empty_evt(fifo->priv); + + if (fifo->d_ready_evt != NULL) + fifo->d_ready_evt(fifo->priv); +} + +void +fifo_close(void *priv) +{ + free(priv); +} + +void * +fifo_init(int len) +{ + void *fifo = NULL; + + if (len == 64) + fifo = (void *) calloc(1, sizeof(fifo64_t)); + else if (len == 16) + fifo = (void *) calloc(1, sizeof(fifo16_t)); + else { + fatal("FIFO : Invalid FIFO length: %i\n", len); + return NULL; + } + + if (fifo == NULL) + fatal("FIFO%i: Failed to allocate memory for the FIFO\n", len); + else + ((fifo_t *) fifo)->len = len; + + return fifo; +} + +#ifdef FIFO_STANDALONE +enum { + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8, + SERIAL_INT_TIMEOUT = 16 +}; + +typedef struct +{ + uint8_t lsr, int_status, tsr, tsr_empty; + + fifo16_t *rcvr_fifo, *xmit_fifo; +} serial_t; + +static void +serial_receive_timer(fifo16_t *f16, uint8_t val) +{ + fifo_write_evt(val, f16); + + printf("Write %02X to FIFO [F: %i, E: %i, O: %i, R: %i]\n", val, + fifo_get_full(f16), fifo_get_empty(f16), + fifo_get_overrun(f16), fifo_get_ready(f16)); + + /* + if (fifo_get_d_overrun(f16)) + dev->lsr = (dev->lsr & 0xfd) | (fifo_get_overrun(f16) << 1); + */ + if (fifo_get_d_overrun(f16)) printf(" FIFO overrun state changed: %i -> %i\n", + !fifo_get_overrun(f16), fifo_get_overrun(f16)); + + /* + if (fifo_get_d_empty(f16)) { + dev->lsr = (dev->lsr & 0xfe) | !fifo_get_empty(f16); + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + } + */ + if (fifo_get_d_empty(f16)) printf(" FIFO empty state changed: %i -> %i\n", + !fifo_get_empty(f16), fifo_get_empty(f16)); + + /* + if (fifo_get_d_ready(f16)) { + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | + (fifo_get_ready(f16) ? SERIAL_INT_RECEIVE : 0); + serial_update_ints(); + } + */ + if (fifo_get_d_ready(f16)) printf(" FIFO ready state changed: %i -> %i\n", + !fifo_get_ready(f16), fifo_get_ready(f16)); +} + +static uint8_t +serial_read(fifo16_t *f16) +{ + uint8_t ret; + + ret = fifo_read_evt(f16); + + printf("Read %02X from FIFO [F: %i, E: %i, O: %i, R: %i]\n", ret, + fifo_get_full(f16), fifo_get_empty(f16), + fifo_get_overrun(f16), fifo_get_ready(f16)); + + /* + if (fifo_get_d_ready(f16)) { + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | + (fifo_get_ready(f16) ? SERIAL_INT_RECEIVE : 0); + serial_update_ints(); + } + */ + if (fifo_get_d_ready(f16)) printf(" FIFO ready state changed: %i -> %i\n", + !fifo_get_ready(f16), fifo_get_ready(f16)); + + /* + if (fifo_get_d_empty(f16)) { + dev->lsr = (dev->lsr & 0xfe) | !fifo_get_empty(f16); + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + } + */ + if (fifo_get_d_empty(f16)) printf(" FIFO empty state changed: %i -> %i\n", + !fifo_get_empty(f16), fifo_get_empty(f16)); + + return ret; +} + +static void +serial_xmit_d_empty_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->lsr = (dev->lsr & 0x9f) | (fifo_get_empty(dev->xmit_fifo) << 5) | + ((dev->tsr_empty && fifo_get_empty(dev->xmit_fifo)) << 6); + dev->int_status = (dev->int_status & ~SERIAL_INT_TRANSMIT) | + (fifo_get_empty(dev->xmit_fifo) ? SERIAL_INT_TRANSMIT : 0); + // serial_update_ints(); + + printf("NS16550: serial_xmit_d_empty_evt(%08X): dev->lsr = %02X\n", priv, dev->lsr); + printf("NS16550: serial_xmit_d_empty_evt(%08X): dev->int_status = %02X\n", priv, dev->int_status); +} + +static void +serial_rcvr_d_empty_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->lsr = (dev->lsr & 0xfe) | !fifo_get_empty(dev->rcvr_fifo); + // timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + + printf("NS16550: serial_rcvr_d_empty_evt(%08X): dev->lsr = %02X\n", priv, dev->lsr); +} + +static void +serial_rcvr_d_overrun_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->lsr = (dev->lsr & 0xfd) | (fifo_get_overrun(dev->rcvr_fifo) << 1); + + printf("NS16550: serial_rcvr_d_overrun_evt(%08X): dev->lsr = %02X\n", priv, dev->lsr); +} + +static void +serial_rcvr_d_ready_evt(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | + (fifo_get_ready(dev->rcvr_fifo) ? SERIAL_INT_RECEIVE : 0); + // serial_update_ints(); + + printf("NS16550: serial_rcvr_d_ready_evt(%08X): dev->int_status = %02X\n", priv, dev->int_status); +} + +int +main(int argc, char *argv[]) +{ + uint8_t val, ret; + + printf("Initializing serial...\n"); + serial_t *dev = (serial_t *) calloc(1, sizeof(serial_t)); + dev->tsr_empty = 1; + + printf("Initializing dev->xmit_fifo...\n"); + dev->xmit_fifo = fifo16_init(); + fifo_set_trigger_len(dev->xmit_fifo, 255); + + fifo_set_priv(dev->xmit_fifo, dev); + fifo_set_d_empty_evt(dev->xmit_fifo, serial_xmit_d_empty_evt); + + printf("\nResetting dev->xmit_fifo...\n"); + fifo_reset_evt(dev->xmit_fifo); + + printf("\nInitializing dev->rcvr_fifo...\n"); + dev->rcvr_fifo = fifo16_init(); + fifo_set_trigger_len(dev->rcvr_fifo, 4); + + fifo_set_priv(dev->rcvr_fifo, dev); + fifo_set_d_empty_evt(dev->rcvr_fifo, serial_rcvr_d_empty_evt); + fifo_set_d_overrun_evt(dev->rcvr_fifo, serial_rcvr_d_overrun_evt); + fifo_set_d_ready_evt(dev->rcvr_fifo, serial_rcvr_d_ready_evt); + + printf("\nResetting dev->rcvr_fifo...\n"); + fifo_reset_evt(dev->rcvr_fifo); + + printf("\nSending/receiving data...\n"); + serial_receive_timer(dev->rcvr_fifo, '8'); + serial_receive_timer(dev->rcvr_fifo, '6'); + ret = serial_read(dev->rcvr_fifo); + serial_receive_timer(dev->rcvr_fifo, 'B'); + ret = serial_read(dev->rcvr_fifo); + serial_receive_timer(dev->rcvr_fifo, 'o'); + ret = serial_read(dev->rcvr_fifo); + serial_receive_timer(dev->rcvr_fifo, 'x'); + ret = serial_read(dev->rcvr_fifo); + ret = serial_read(dev->rcvr_fifo); + + fifo_close(dev->rcvr_fifo); + fifo_close(dev->xmit_fifo); + + free(dev); + + return 0; +} +#endif diff --git a/src/gdbstub.c b/src/gdbstub.c index 97bf82fc9..30785eeac 100644 --- a/src/gdbstub.c +++ b/src/gdbstub.c @@ -75,8 +75,10 @@ enum { GDB_REG_ES, GDB_REG_FS, GDB_REG_GS, +#if 0 GDB_REG_FS_BASE, GDB_REG_GS_BASE, +#endif GDB_REG_CR0, GDB_REG_CR2, GDB_REG_CR3, @@ -678,9 +680,11 @@ gdbstub_client_read_reg(int index, uint8_t *buf) *((uint16_t *) buf) = segment_regs[index - GDB_REG_CS]->seg; break; +#if 0 case GDB_REG_FS_BASE ... GDB_REG_GS_BASE: *((uint32_t *) buf) = segment_regs[(index - 16) + (GDB_REG_FS - GDB_REG_CS)]->base; break; +#endif case GDB_REG_CR0 ... GDB_REG_CR4: *((uint32_t *) buf) = *cr_regs[index - GDB_REG_CR0]; diff --git a/src/include/86box/fifo.h b/src/include/86box/fifo.h new file mode 100644 index 000000000..71a40b0ce --- /dev/null +++ b/src/include/86box/fifo.h @@ -0,0 +1,68 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * FIFO infrastructure header. + * + * Authors: Miran Grca, + * + * Copyright 2023 Miran Grca. + */ +#define FIFO(size) \ + typedef struct \ + { \ + int start, end, \ + trigger_len, len, \ + empty, overrun, \ + full, ready, \ + d_empty, d_overrun, \ + d_full, d_ready; \ + \ + void *priv; \ + \ + void (*d_empty_evt)(void *); \ + void (*d_overrun_evt)(void *); \ + void (*d_full_evt)(void *); \ + void (*d_ready_evt)(void *); \ + \ + uint8_t buf[size]; \ + } fifo## size ##_t; + +FIFO() + +FIFO(16) +#define fifo16_init() fifo_init(16) + +FIFO(64) +#define fifo64_init() fifo_init(64) + +extern int fifo_get_count(void *priv); +extern void fifo_write(uint8_t val, void *priv); +extern void fifo_write_evt(uint8_t val, void *priv); +extern uint8_t fifo_read(void *priv); +extern uint8_t fifo_read_evt(void *priv); +extern void fifo_clear_overrun(void *priv); +extern int fifo_get_full(void *priv); +extern int fifo_get_d_full(void *priv); +extern int fifo_get_empty(void *priv); +extern int fifo_get_d_empty(void *priv); +extern int fifo_get_overrun(void *priv); +extern int fifo_get_d_overrun(void *priv); +extern int fifo_get_ready(void *priv); +extern int fifo_get_d_ready(void *priv); +extern int fifo_get_trigger_len(void *priv); +extern void fifo_set_trigger_len(void *priv, int trigger_len); +extern void fifo_set_len(void *priv, int len); +extern void fifo_set_d_full_evt(void *priv, void (*d_full_evt)(void *)); +extern void fifo_set_d_empty_evt(void *priv, void (*d_empty_evt)(void *)); +extern void fifo_set_d_overrun_evt(void *priv, void (*d_overrun_evt)(void *)); +extern void fifo_set_d_ready_evt(void *priv, void (*d_ready_evt)(void *)); +extern void fifo_set_priv(void *priv, void *sub_priv); +extern void fifo_reset(void *priv); +extern void fifo_reset_evt(void *priv); +extern void fifo_close(void *priv); +extern void * fifo_init(int len); diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index 2b31a153b..724f2f90f 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -65,29 +65,21 @@ typedef struct serial_s { uint8_t inst; uint8_t transmit_enabled; uint8_t fifo_enabled; - uint8_t rcvr_fifo_len; uint8_t bits; uint8_t data_bits; uint8_t baud_cycles; - uint8_t rcvr_fifo_full; uint8_t txsr; - uint8_t out; + uint8_t txsr_empty; uint8_t msr_set; - uint8_t pad; uint8_t irq_state; - uint8_t pad0; uint16_t dlab; uint16_t base_address; uint16_t out_new; - uint16_t pad1; + uint16_t thr_empty; - uint8_t rcvr_fifo_pos; - uint8_t xmit_fifo_pos; - uint8_t rcvr_fifo_end; - uint8_t xmit_fifo_end; - uint8_t rcvr_fifo[SERIAL_FIFO_SIZE]; - uint8_t xmit_fifo[SERIAL_FIFO_SIZE]; + void *rcvr_fifo; + void *xmit_fifo; pc_timer_t transmit_timer; pc_timer_t timeout_timer; diff --git a/src/mem/mem.c b/src/mem/mem.c index 088d15f51..af80365e8 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2695,6 +2695,7 @@ mem_reset(void) } memset(ram, 0x00, ram_size); ram2_size = m - (1 << 30); + /* Allocate 16 extra bytes of RAM to mitigate some dynarec recompiler memory access quirks. */ ram2 = (uint8_t *) plat_mmap(ram2_size + 16, 0); /* allocate and clear the RAM block above 1 GB */ if (ram2 == NULL) { if (config_changed == 2) @@ -2703,17 +2704,18 @@ mem_reset(void) fatal("Failed to allocate secondary RAM block. Make sure you have enough RAM available.\n"); return; } - memset(ram2, 0x00, ram2_size); + memset(ram2, 0x00, ram2_size + 16); } else #endif { ram_size = m; + /* Allocate 16 extra bytes of RAM to mitigate some dynarec recompiler memory access quirks. */ ram = (uint8_t *) plat_mmap(ram_size + 16, 0); /* allocate and clear the RAM block */ if (ram == NULL) { fatal("Failed to allocate RAM block. Make sure you have enough RAM available.\n"); return; } - memset(ram, 0x00, ram_size); + memset(ram, 0x00, ram_size + 16); if (mem_size > 1048576) ram2 = &(ram[1 << 30]); } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9275d1ebf..b5cbfd9f7 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -564,8 +564,8 @@ CFLAGS += -Werror=implicit-int -Werror=implicit-function-declaration \ # Create the (final) list of objects to build. # ######################################################################### MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o pit_fast.o port_6x.o port_92.o ppi.o pci.o mca.o fifo8.o \ - usb.o device.o nvr.o nvr_at.o nvr_ps2.o machine_status.o ini.o \ + nmi.o pic.o pit.o pit_fast.o port_6x.o port_92.o ppi.o pci.o mca.o fifo.o \ + fifo8.o usb.o device.o nvr.o nvr_at.o nvr_ps2.o machine_status.o ini.o \ $(VNCOBJ) MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o mmu_2386.o rom.o row.o \