diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 3f1449aaa..0fb6e17d9 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -29,6 +29,7 @@ #include <86box/keyboard.h> #include <86box/chipset.h> #include <86box/spd.h> +#include <86box/machine.h> enum @@ -442,9 +443,13 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case INTEL_440BX: case INTEL_440ZX: regs[0x51] = (regs[0x50] & 0x70) | (val & 0x8f); +#if defined(DEV_BRANCH) && defined(USE_VIRTUALPC) + if (!strcmp(machines[machine].internal_name, "vpc2007")) + regs[0x51] |= 0x10; /* Virtual PC 2007 BIOS requires a reserved bus speed bit to be set */ +#endif break; case INTEL_440GX: - regs[0x51] = (regs[0x50] & 0x88) | (val & 0x08); + regs[0x51] = (regs[0x50] & 0x88) | (val & 0x08); /*regs[0x51] = (regs[0x50] & 0x88) | (val & 0x77);*/ break; } @@ -1551,6 +1556,10 @@ static void regs[0x51] |= 0x20; else if ((cpu_busspeed > 66666667) && (cpu_busspeed <= 100000000)) regs[0x51] |= 0x00; +#if defined(DEV_BRANCH) && defined(USE_VIRTUALPC) + if (!strcmp(machines[machine].internal_name, "vpc2007")) + regs[0x51] |= 0x10; /* Virtual PC 2007 BIOS requires a reserved bus speed bit to be set */ +#endif regs[0x57] = 0x28; /* 4 DIMMs, SDRAM */ regs[0x58] = 0x03; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x01; diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index bf14981fc..30b02aab0 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -618,7 +618,7 @@ stpc_serial_handlers(uint8_t val) uart1_io = 0x2f8; } - if ((uart0_io & 0x0f00) < 0x300) { + if (uart0_io < 0x300) { /* The address for UART0 defines the IRQs for both ports. */ uart0_irq = 3; uart1_irq = 4; @@ -719,8 +719,9 @@ stpc_reg_read(uint16_t addr, void *priv) if (addr == 0x22) ret = dev->reg_offset; else if (dev->reg_offset >= 0xc0) - return 0xff; /* Cyrix CPU registers: let the CPU code handle those */ + return 0xff; /* Cyrix CPU registers: let the CPU code handle these */ else if ((dev->reg_offset == 0x56) || (dev->reg_offset == 0x57)) { + /* ELCR is in here, not in port 4D0h. */ ret = elcr_read(dev->reg_offset, NULL); if (dev->reg_offset == 0x57) ret |= (dev->regs[dev->reg_offset] & 0x01); @@ -743,7 +744,7 @@ stpc_reset(void *priv) dev->regs[0x7b] = 0xff; if (device_get_priv(&stpc_lpt_device)) dev->regs[0x4c] |= 0x80; /* LPT strap */ - if (stpc_serial_handlers(0)) + if (stpc_serial_handlers(0x00)) dev->regs[0x4c] |= 0x03; /* UART straps */ } @@ -977,7 +978,7 @@ stpc_serial_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - /* Initialization is performed by stpc_reset. */ + /* Initialization is performed by stpc_reset */ return dev; } @@ -1035,18 +1036,19 @@ stpc_lpt_write(uint16_t addr, uint8_t val, void *priv) stpc_lpt_t *dev = (stpc_lpt_t *) priv; if (dev->unlocked < 2) { - if (addr == 0x3f0) { - if (val == 0x55) - dev->unlocked++; - else - dev->unlocked = 0; - } + /* Cheat a little bit: in reality, any write to any + I/O port is supposed to reset the unlock counter. */ + if ((addr == 0x3f0) && (val == 0x55)) + dev->unlocked++; + else + dev->unlocked = 0; } else if (addr == 0x3f0) { if (val == 0xaa) dev->unlocked = 0; else dev->offset = val; } else if (dev->offset == 1) { + /* dev->reg1 is set by stpc_lpt_handlers */ stpc_lpt_handlers(dev, val); } else if (dev->offset == 4) { dev->reg4 = (val & 0x03); diff --git a/src/device/vpc2007.c b/src/device/vpc2007.c new file mode 100644 index 000000000..7dd9ba1e0 --- /dev/null +++ b/src/device/vpc2007.c @@ -0,0 +1,186 @@ +/* + * 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 port 440h device from Virtual PC 2007. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/mem.h> +#include "cpu.h" + + +typedef struct { + uint8_t port440, port440read, port442, port443, port444; +} vpc2007_t; + + +#ifdef ENABLE_VPC2007_LOG +int vpc2007_do_log = ENABLE_VPC2007_LOG; + + +static void +vpc2007_log(const char *fmt, ...) +{ + va_list ap; + + if (vpc2007_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +int vpc2007_do_log = 0; + +#define vpc2007_log(fmt, ...) +#endif + + +static uint8_t +vpc2007_read(uint16_t port, void *priv) +{ + vpc2007_t *dev = (vpc2007_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x440: + ret = dev->port440read; + dev->port440read = 0x02; + break; + + case 0x445: + if ((dev->port440 == 0x1e) && (dev->port442 == 0x48) && (dev->port444 == 0xa7)) { + switch (dev->port443) { + case 0x0b: + ret = 0x00; + break; + + case 0x1b: case 0x05: + ret = 0x01; + break; + + case 0x02: + ret = 0x02; + break; + + case 0x11: + ret = 0x04; + break; + + case 0x12: + ret = 0x06; + break; + + case 0x04: case 0x0d: + ret = 0x08; + break; + + case 0x03: case 0x09: + ret = 0x0b; + break; + + case 0x15: + ret = 0x12; + break; + + case 0x17: + ret = 0x40; + break; + } + } + + if (ret == 0xff) + vpc2007_log("VPC2007: unknown combination %02X %02X %02X %02X\n", dev->port440, dev->port442, dev->port443, dev->port444); + + break; + + default: + vpc2007_log("VPC2007: read from unknown port %02X\n", port); + break; + } + + return ret; +} + + +static void +vpc2007_write(uint16_t port, uint8_t val, void *priv) +{ + vpc2007_t *dev = (vpc2007_t *) priv; + + switch (port) { + case 0x440: + dev->port440 = val; + dev->port440read = 0x03; + break; + + case 0x442: + dev->port442 = val; + break; + + case 0x443: + dev->port443 = val; + break; + + case 0x444: + dev->port444 = val; + break; + } +} + + +static void * +vpc2007_init(const device_t *info) +{ + vpc2007_t *dev = (vpc2007_t *) malloc(sizeof(vpc2007_t)); + memset(dev, 0, sizeof(vpc2007_t)); + + io_sethandler(0x440, 6, + vpc2007_read, NULL, NULL, vpc2007_write, NULL, NULL, dev); + + return dev; +} + + +static void +vpc2007_close(void *priv) +{ + vpc2007_t *dev = (vpc2007_t *) priv; + + io_removehandler(0x440, 6, + vpc2007_read, NULL, NULL, vpc2007_write, NULL, NULL, dev); + + free(dev); +} + + +const device_t vpc2007_device = { + "Virtual PC 2007 Port 440h Device", + DEVICE_ISA, + 0, + vpc2007_init, vpc2007_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 2e95dda02..a5cf6e3ab 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -71,6 +71,7 @@ extern const device_t piix4e_device; extern const device_t slc90e66_device; extern const device_t ioapic_device; +extern const device_t vpc2007_device; /* OPTi */ extern const device_t opti283_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 32b338854..4f5d60c2a 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -418,6 +418,9 @@ extern int machine_at_ax6bc_init(const machine_t *); extern int machine_at_atc6310bxii_init(const machine_t *); extern int machine_at_tsunamiatx_init(const machine_t *); extern int machine_at_p6sba_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_VIRTUALPC) +extern int machine_at_vpc2007_init(const machine_t *); +#endif #ifdef EMU_DEVICE_H extern const device_t *at_tsunamiatx_get_device(void); diff --git a/src/ioapic.c b/src/ioapic.c index a45ad14c7..498787582 100644 --- a/src/ioapic.c +++ b/src/ioapic.c @@ -7,7 +7,7 @@ * This file is part of the 86Box distribution. * * Skeleton I/O APIC implementation, currently housing the MPS - * table patcher for machines that require it. + * table patcher for machines that require it. * * * diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 9236b459e..e161f7b1b 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -480,7 +480,7 @@ machine_at_p6sba_init(const machine_t *model) machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ hwm_set_values(machine_hwm); device_add(&w83781d_device); - + return ret; } @@ -528,3 +528,41 @@ at_tsunamiatx_get_device(void) { return &es1371_onboard_device; } + + +#if defined(DEV_BRANCH) && defined(USE_VIRTUALPC) +int +machine_at_vpc2007_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/vpc2007/13500.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&w83977tf_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + device_add(&vpc2007_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); /* real VPC provides invalid SPD data */ + + return ret; +} +#endif diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 1122434f7..8c2c81a69 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -355,6 +355,9 @@ const machine_t machines[] = { { "[i440BX] A-Trend ATC6310BXII", "atc6310bxii", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_atc6310bxii_init, NULL }, { "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_SOUND, 8, 1024, 8, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device }, { "[i440BX] SuperMicro Super P6SBA", "p6sba", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_p6sba_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_VIRTUALPC) + { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_vpc2007_init, NULL }, +#endif /* Slot 2 machines(Including Slot 1/2 Hybrids) */ /* 440GX */ diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index b50cdec49..b30c0c10e 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -84,6 +84,9 @@ ifeq ($(DEV_BUILD), y) ifndef VGAWONDER VGAWONDER := y endif + ifndef VIRTUALPC + VIRTUALPC := y + endif ifndef VNC VNC := y endif @@ -160,6 +163,9 @@ else ifndef VGAWONDER VGAWONDER := n endif + ifndef VIRTUALPC + VIRTUALPC := y + endif ifndef VNC VNC := n endif @@ -554,7 +560,7 @@ endif ifeq ($(STPC), y) OPTS += -DUSE_STPC -STPCOBJ := stpc.o +DEVBROBJ += stpc.o endif ifeq ($(596B), y) @@ -565,6 +571,11 @@ ifeq ($(VGAWONDER), y) OPTS += -DUSE_VGAWONDER endif +ifeq ($(VIRTUALPC), y) +OPTS += -DUSE_VIRTUALPC +DEVBROBJ += vpc2007.o +endif + ifeq ($(WIN471), y) OPTS += -DUSE_WIN471 endif @@ -617,7 +628,7 @@ CPUOBJ := cpu.o cpu_table.o \ CHIPSETOBJ := acc2168.o cs8230.o ali1429.o headland.o i82335.o cs4031.o \ intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o opti495.o opti895.o opti5x7.o scamp.o scat.o via_vt82c49x.o via_vt82c505.o \ - sis_85c310.o sis_85c471.o sis_85c496.o opti283.o opti291.o $(STPCOBJ) \ + sis_85c310.o sis_85c471.o sis_85c496.o opti283.o opti291.o \ via_apollo.o via_vpx.o via_vt82c586b.o via_vt82c596b.o wd76c10.o vl82c480.o \ amd640.o