From 09ffa05f89195dbaeb88b3f8e63ec7299eab5c12 Mon Sep 17 00:00:00 2001 From: nerd73 Date: Tue, 23 Jun 2020 15:04:10 -0600 Subject: [PATCH] Improvements to the OPTi 597 machine. - Add emulation of the FDC37C661 Super I/O - Fix Pentium VLB timing (was running VLB at 2x bus speed instead of 1/2 bus speed) - Fix the cache register on the OPTi 5x7 chipset - The actual minimum RAM amount is 2 MB, not 1 MB. - Fix chipset naming consistency --- src/chipset/opti5x7.c | 10 +- src/include/86box/sio.h | 1 + src/machine/m_at_socket4_5.c | 2 +- src/machine/machine_table.c | 4 +- src/pit.c | 2 +- src/sio/sio_fdc37c661.c | 278 +++++++++++++++++++++++++++++++++++ src/win/Makefile.mingw | 2 +- 7 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 src/sio/sio_fdc37c661.c diff --git a/src/chipset/opti5x7.c b/src/chipset/opti5x7.c index 4a83ed98d..6f13edccf 100644 --- a/src/chipset/opti5x7.c +++ b/src/chipset/opti5x7.c @@ -23,7 +23,7 @@ The earlier 596/597 appears to be register compatible with the 546/547 from test typedef struct { uint8_t cur_reg, - regs[64]; + regs[16]; port_92_t *port_92; } opti5x7_t; @@ -61,12 +61,10 @@ opti5x7_write(uint16_t addr, uint8_t val, void *priv) break; case 0x24: dev->regs[dev->cur_reg] = val; - if (dev->cur_reg == 0x02) { - cpu_cache_ext_enabled = val & 0x10; - } - if (dev->cur_reg == 0x06) { + if (dev->regs[0x02] & 0x0c) + cpu_cache_ext_enabled = 1; + if (dev->cur_reg == 0x06) opti5x7_recalcmapping(dev); - } break; } } diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 6e64742b6..9723a184a 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -17,6 +17,7 @@ extern const device_t acc3221_device; extern const device_t f82c710_device; +extern const device_t fdc37c661_device; extern const device_t fdc37c663_device; extern const device_t fdc37c665_device; extern const device_t fdc37c666_device; diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket4_5.c index 8137397f9..0f21ca67a 100644 --- a/src/machine/m_at_socket4_5.c +++ b/src/machine/m_at_socket4_5.c @@ -54,7 +54,7 @@ machine_at_excalibur_init(const machine_t *model) device_add(&ide_vlb_device); device_add(&opti5x7_device); - device_add(&fdc37c663_device); + device_add(&fdc37c661_device); device_add(&keyboard_at_ami_device); return ret; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index da2153335..1649c3d91 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -179,7 +179,7 @@ const machine_t machines[] = { /* 386DX machines */ { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 16384, 128, 127, machine_at_acc386_init, NULL }, - { "[SiS Rabbit] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, + { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, { "[ISA] Micronics 386 clone", "micronics386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 1, 16, 1, 127, machine_at_ecs386_init, NULL }, @@ -229,7 +229,7 @@ const machine_t machines[] = { /* Socket 4 machines */ /* OPTi 596/597 */ - { "[OPTi Python] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_excalibur_init, NULL }, + { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 2, 64, 2, 127, machine_at_excalibur_init, NULL }, /* 430LX */ { "[i430LX] IBM Ambra DP60 PCI", "ambradp60", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp60_init, NULL }, diff --git a/src/pit.c b/src/pit.c index 7c6c1923d..b33adbc1a 100644 --- a/src/pit.c +++ b/src/pit.c @@ -1030,7 +1030,7 @@ pit_set_clock(int clock) isa_timing = (cpuclock / (double)8000000.0); if (cpu_64bitbus) - bus_timing = (cpuclock / ((double)cpu_busspeed) / 2); + bus_timing = (cpuclock / ((double)cpu_busspeed / 2)); else bus_timing = (cpuclock / (double)cpu_busspeed); pci_timing = (cpuclock / (double)cpu_pci_speed); diff --git a/src/sio/sio_fdc37c661.c b/src/sio/sio_fdc37c661.c new file mode 100644 index 000000000..6936dff7c --- /dev/null +++ b/src/sio/sio_fdc37c661.c @@ -0,0 +1,278 @@ +/* + * 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. + * + * Implementation of the SMC FDC37C661 Super + * I/O Chip. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 plant/nerd73. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/pci.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + + +typedef struct { + uint8_t lock[2], + regs[4]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c661_t; + + +static void +write_lock(fdc37c661_t *dev, uint8_t val) +{ + if (val == 0x55 && dev->lock[1] == 0x55) + fdc_3f1_enable(dev->fdc, 0); + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55) && (val != 0x55)) + fdc_3f1_enable(dev->fdc, 1); + + dev->lock[0] = dev->lock[1]; + dev->lock[1] = val; +} + + +static void +set_com34_addr(fdc37c661_t *dev) +{ + switch (dev->regs[1] & 0x60) { + case 0x00: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 0x20: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e8; + break; + case 0x40: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e0; + break; + case 0x60: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; + } +} + + +static void +set_serial_addr(fdc37c661_t *dev, int port) +{ + uint8_t shift = (port << 4); + + if (dev->regs[2] & (4 << shift)) { + switch (dev->regs[2] & (3 << shift)) { + case 0: + serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); + break; + case 1: + serial_setup(dev->uart[port], SERIAL2_ADDR, SERIAL2_IRQ); + break; + case 2: + serial_setup(dev->uart[port], dev->com3_addr, 4); + break; + case 3: + serial_setup(dev->uart[port], dev->com4_addr, 3); + break; + } + } +} + + +static void +lpt1_handler(fdc37c661_t *dev) +{ + lpt1_remove(); + switch (dev->regs[1] & 3) { + case 1: + lpt1_init(0x3bc); + lpt1_irq(7); + break; + case 2: + lpt1_init(0x378); + lpt1_irq(5); + break; + case 3: + lpt1_init(0x278); + lpt1_irq(5); + break; + } +} + + +static void +fdc_handler(fdc37c661_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0] & 0x10) + fdc_set_base(dev->fdc, 0x03f0); +} + + +static void +fdc37c661_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c661_t *dev = (fdc37c661_t *) priv; + uint8_t valxor = 0; + + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f0) { + if (val == 0xaa) + write_lock(dev, val); + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > 4) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 0: + if (valxor & 0x10) + fdc_handler(dev); + + break; + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + } + break; + case 2: + if (valxor & 7) { + serial_remove(dev->uart[0]); + set_serial_addr(dev, 0); + } + if (valxor & 0x70) { + serial_remove(dev->uart[1]); + set_serial_addr(dev, 1); + } + break; + case 3: + if (valxor & 4) + fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 4) ? 1 : 0); + break; + } + } + } else { + if (port == 0x3f0) + write_lock(dev, val); + } +} + + +static uint8_t +fdc37c661_read(uint16_t port, void *priv) +{ + fdc37c661_t *dev = (fdc37c661_t *) priv; + uint8_t ret = 0xff; + + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +static void +fdc37c661_reset(fdc37c661_t *dev) +{ + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + + fdc_reset(dev->fdc); + + memset(dev->lock, 0, 2); + memset(dev->regs, 0, 16); + + dev->regs[0x0] = 0x3f; + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + dev->regs[0x3] = 0x78; +} + + +static void +fdc37c661_close(void *priv) +{ + fdc37c661_t *dev = (fdc37c661_t *) priv; + + free(dev); +} + + +static void * +fdc37c661_init(const device_t *info) +{ + fdc37c661_t *dev = (fdc37c661_t *) malloc(sizeof(fdc37c661_t)); + memset(dev, 0, sizeof(fdc37c661_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(0x03f0, 0x0002, + fdc37c661_read, NULL, NULL, fdc37c661_write, NULL, NULL, dev); + + fdc37c661_reset(dev); + + return dev; +} + +const device_t fdc37c661_device = { + "SMC FDC37C661 Super I/O", + 0, + 0, + fdc37c661_init, fdc37c661_close, NULL, + NULL, NULL, NULL, + NULL +}; + diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index ec28ed158..122ed8daf 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -592,7 +592,7 @@ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt SIOOBJ := sio_acc3221.o \ sio_f82c710.o \ - sio_fdc37c66x.o sio_fdc37c669.o \ + sio_fdc37c661.o sio_fdc37c66x.o sio_fdc37c669.o \ sio_fdc37c93x.o \ sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87332.o \ sio_w83787f.o \