From 0c4003caa3cf3ab7d18aee287f9267e0d3edb157 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 7 Sep 2021 23:41:17 +0200 Subject: [PATCH] Added the C&T 82C100 chipset needed by the Victor V86P. --- src/chipset/82c100.c | 352 ++++++++++++++++++++++++++++++++++++ src/chipset/CMakeLists.txt | 2 +- src/cpu/808x.c | 47 ++++- src/cpu/cpu.h | 3 + src/include/86box/chipset.h | 3 + src/machine/m_v86p.c | 2 + src/nmi.c | 2 +- src/win/Makefile.mingw | 2 +- 8 files changed, 409 insertions(+), 4 deletions(-) create mode 100644 src/chipset/82c100.c diff --git a/src/chipset/82c100.c b/src/chipset/82c100.c new file mode 100644 index 000000000..50f9d81e2 --- /dev/null +++ b/src/chipset/82c100.c @@ -0,0 +1,352 @@ +/* + * 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 Chips&Technology's 82C100 chipset. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include "cpu.h" +#include "x86.h" +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/port_92.h> +#include <86box/rom.h> +#include <86box/chipset.h> + + +typedef struct +{ + int enabled; + uint32_t virt, phys; +} ems_page_t; + + +typedef struct +{ + uint8_t index, access; + uint16_t ems_io_base; + uint32_t ems_window_base; + uint8_t ems_page_regs[4], + regs[256]; + ems_page_t ems_pages[4]; + mem_mapping_t ems_mappings[4]; +} ct_82c100_t; + + +static void +ct_82c100_ems_pages_recalc(ct_82c100_t *dev) +{ + int i; + uint32_t page_base; + + for (i = 0; i < 4; i++) { + page_base = dev->ems_window_base + (i << 14); + if (dev->ems_page_regs[i] & 0x80) { + dev->ems_pages[i].virt = page_base; + dev->ems_pages[i].phys = 0xa0000 + (((uint32_t) (dev->ems_page_regs[4] & 0x7f)) << 14); + mem_mapping_set_addr(&(dev->ems_mappings[i]), dev->ems_pages[i].virt, 0x4000); + mem_mapping_set_exec(&(dev->ems_mappings[i]), &(ram[dev->ems_pages[i].phys])); + mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else { + mem_mapping_disable(&(dev->ems_mappings[i])); + mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + } +} + + +static void +ct_82c100_ems_out(uint16_t port, uint8_t val, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + dev->ems_page_regs[port >> 14] = val; + ct_82c100_ems_pages_recalc(dev); +} + + +static uint8_t +ct_82c100_ems_in(uint16_t port, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + uint8_t ret = 0xff; + + ret = dev->ems_page_regs[port >> 14]; + + return ret; +} + + +static void +ct_82c100_ems_update(ct_82c100_t *dev) +{ + int i; + + for (i = 0; i < 4; i++) { + io_handler(0, dev->ems_io_base + (i << 14), 1, + ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev); + } + + dev->ems_io_base = 0x0208 + (dev->regs[0x4c] & 0xf0); + + for (i = 0; i < 4; i++) { + io_handler(1, dev->ems_io_base + (i << 14), 1, + ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev); + } + + dev->ems_window_base = 0xc0000 + (((uint32_t) (dev->regs[0x4c] & 0x0f)) << 14); + + ct_82c100_ems_pages_recalc(dev); +} + + +static void +ct_82c100_reset(void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + memset(dev->regs, 0x00, sizeof(dev->regs)); + memset(dev->ems_page_regs, 0x00, sizeof(dev->ems_page_regs)); + + dev->index = dev->access = 0x00; + + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + dev->regs[0x40] = 0x01; /* Defaults to 8086/V30 mode. */ + dev->regs[0x43] = 0x30; + dev->regs[0x48] = 0x01; + + use_custom_nmi_vector = 0; + ct_82c100_ems_update(dev); + + /* ADDITIONAL I/O REGISTERS */ +} + + +static void +ct_82c100_out(uint16_t port, uint8_t val, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + if (port == 0x0022) { + dev->index = val; + dev->access = 1; + } else if (port == 0x0023) { + if (dev->access) { + switch (dev->index) { + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + case 0x40: + dev->regs[0x40] = val & 0xc7; + /* TODO: Clock stuff - needs CPU speed change functionality that's + going to be implemented in 86box v4.0. + Bit 0 is 0 for 8088/V20 and 1 for 8086/V30. */ + break; + case 0x41: + dev->regs[0x41] = val & 0xed; + /* TODO: Where is the Software Reset Function that's enabled by + setting bit 6 to 1? */ + break; + case 0x42: + dev->regs[0x42] = val & 0x01; + break; + case 0x43: + dev->regs[0x43] = val; + break; + case 0x44: + dev->regs[0x44] = val; + custom_nmi_vector = (custom_nmi_vector & 0xffffff00) | ((uint32_t) val); + break; + case 0x45: + dev->regs[0x45] = val; + custom_nmi_vector = (custom_nmi_vector & 0xffff00ff) | (((uint32_t) val) << 8); + break; + case 0x46: + dev->regs[0x46] = val; + custom_nmi_vector = (custom_nmi_vector & 0xff00ffff) | (((uint32_t) val) << 16); + break; + case 0x47: + dev->regs[0x47] = val; + custom_nmi_vector = (custom_nmi_vector & 0x00ffffff) | (((uint32_t) val) << 24); + break; + case 0x48: case 0x49: + dev->regs[dev->index] = val; + break; + case 0x4b: + dev->regs[0x4b] = val; + use_custom_nmi_vector = !!(val & 0x40); + break; + case 0x4c: + dev->regs[0x4c] = val; + ct_82c100_ems_update(dev); + break; + } + dev->access = 0; + } + } else if (port == 0x72) + dev->regs[0x72] = val & 0x7e; + else if (port == 0x7e) + dev->regs[0x7e] = val; + else if (port == 0x7f) { + /* Bit 3 is Software Controlled Reset, asserted if set. Will be + done in the feature/machine_and_kb branch using hardresetx86(). */ + dev->regs[0x7f] = val; + if ((dev->regs[0x41] & 0x40) && (val & 0x08)) { + softresetx86(); + cpu_set_edx(); + ct_82c100_reset(dev); + } + } +} + + +static uint8_t +ct_82c100_in(uint16_t port, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + uint8_t ret = 0xff; + + if (port == 0x0022) + ret = dev->index; + else if (port == 0x0023) { + if (dev->access) { + switch (dev->index) { + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + case 0x40 ... 0x49: + case 0x4b: case 0x4c: + ret = dev->regs[dev->index]; + break; + } + dev->access = 0; + } + } else if (port == 0x72) + ret = dev->regs[0x72]; + else if (port == 0x7e) + ret = dev->regs[0x7e]; + else if (port == 0x7f) + ret = dev->regs[0x7f]; + + return ret; +} + + +static uint8_t +mem_read_emsb(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + uint8_t val = 0xff; + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static uint16_t +mem_read_emsw(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + uint16_t val = 0xffff; + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_emsb(uint32_t addr, uint8_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_emsw(uint32_t addr, uint16_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +ct_82c100_close(void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + free(dev); +} + + +static void * +ct_82c100_init(const device_t *info) +{ + ct_82c100_t *dev; + uint32_t i; + + dev = (ct_82c100_t *)malloc(sizeof(ct_82c100_t)); + memset(dev, 0x00, sizeof(ct_82c100_t)); + + ct_82c100_reset(dev); + + io_sethandler(0x0022, 2, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + io_sethandler(0x0072, 1, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + io_sethandler(0x007e, 2, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + + for (i = 0; i < 4; i++) { + mem_mapping_add(&(dev->ems_mappings[i]), (i + 28) << 14, 0x04000, + mem_read_emsb, mem_read_emsw, NULL, + mem_write_emsb, mem_write_emsw, NULL, + ram + 0xa0000 + (i << 14), MEM_MAPPING_INTERNAL, &dev->ems_pages[i]); + mem_mapping_disable(&(dev->ems_mappings[i])); + } + + mem_mapping_disable(&ram_mid_mapping); + + device_add(&port_92_device); + + return(dev); +} + + +const device_t ct_82c100_device = { + "C&T 82C100", + 0, + 0, + ct_82c100_init, ct_82c100_close, ct_82c100_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 76cf45db0..12006a878 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,7 +13,7 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c et6000.c headland.c +add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c et6000.c headland.c intel_82335.c cs4031.c intel_420ex.c intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c sis_5598.c diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 3fbcfb0ed..900286580 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -38,6 +38,10 @@ /* Is the CPU 8088 or 8086. */ int is8086 = 0; +uint8_t use_custom_nmi_vector = 0; +uint32_t custom_nmi_vector = 0x00000000; + + /* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ static uint8_t pfq[6]; @@ -578,6 +582,9 @@ reset_808x(int hard) prefetching = 1; cpu_alu_op = 0; + + use_custom_nmi_vector = 0x00; + custom_nmi_vector = 0x00000000; } @@ -943,6 +950,41 @@ interrupt(uint16_t addr) } +static void +custom_nmi(void) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + cpu_state.eaaddr = 0x0002; + old_cs = CS; + access(5, 16); + (void) readmemw(0, cpu_state.eaaddr); + new_ip = custom_nmi_vector & 0xffff; + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + (void) readmemw(0, cpu_state.eaaddr); + new_cs = custom_nmi_vector >> 16; + prefetching = 0; + pfq_clear(); + ovr_seg = NULL; + access(39, 16); + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + load_cs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); +} + + static int irq_pending(void) { @@ -967,7 +1009,10 @@ check_interrupts(void) } if (nmi && nmi_enable && nmi_mask) { nmi_enable = 0; - interrupt(2); + if (use_custom_nmi_vector) + custom_nmi(); + else + interrupt(2); #ifndef OLD_NMI_BEHAVIOR nmi = 0; #endif diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 83664828c..b28934951 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -715,6 +715,9 @@ extern int reset_on_hlt, hlt_reset_pending; extern cyrix_t cyrix; +extern uint8_t use_custom_nmi_vector; +extern uint32_t custom_nmi_vector; + extern void (*cpu_exec)(int cycs); extern uint8_t do_translate, do_translate2; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 6e9b04d24..0c0e36299 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -37,6 +37,7 @@ extern const device_t ali6117d_device; extern const device_t amd640_device; /* C&T */ +extern const device_t ct_82c100_device; extern const device_t neat_device; extern const device_t scat_device; extern const device_t scat_4_device; @@ -65,6 +66,7 @@ extern const device_t i420zx_device; extern const device_t i430lx_device; extern const device_t i430nx_device; extern const device_t i430fx_device; +extern const device_t i430fx_old_device; extern const device_t i430fx_rev02_device; extern const device_t i430hx_device; extern const device_t i430vx_device; @@ -84,6 +86,7 @@ extern const device_t sio_device; extern const device_t sio_zb_device; extern const device_t piix_device; +extern const device_t piix_old_device; extern const device_t piix_rev02_device; extern const device_t piix3_device; extern const device_t piix4_device; diff --git a/src/machine/m_v86p.c b/src/machine/m_v86p.c index 6aa30985a..0ca26629d 100644 --- a/src/machine/m_v86p.c +++ b/src/machine/m_v86p.c @@ -43,6 +43,7 @@ #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/keyboard.h> +#include <86box/chipset.h> #include <86box/sio.h> #include <86box/video.h> @@ -69,6 +70,7 @@ machine_v86p_init(const machine_t *model) machine_common_init(model); + device_add(&ct_82c100_device); device_add(&f82c606_device); device_add(&keyboard_xt_device); diff --git a/src/nmi.c b/src/nmi.c index 07742cefe..1e820a82a 100644 --- a/src/nmi.c +++ b/src/nmi.c @@ -20,6 +20,6 @@ void nmi_write(uint16_t port, uint8_t val, void *p) void nmi_init(void) { - io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); + io_sethandler(0x00a0, 0x000f, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); nmi_mask = 0; } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index d51c3aa30..d86099219 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -620,7 +620,7 @@ CPUOBJ := $(DYNARECOBJ) \ 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \ x86seg.o x87.o x87_timings.o -CHIPSETOBJ := acc2168.o cs8230.o ali1217.o ali1429.o ali1489.o et6000.o headland.o intel_82335.o cs4031.o \ +CHIPSETOBJ := 82c100.o acc2168.o cs8230.o ali1217.o ali1429.o ali1489.o et6000.o headland.o intel_82335.o cs4031.o \ intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o opti495.o opti822.o opti895.o opti5x7.o scamp.o scat.o via_vt82c49x.o via_vt82c505.o \ gc100.o \