diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 7d17b9983..7a8233003 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(chipset OBJECT 82c100.c acc2168.c + cs8220.c cs8230.c ali1429.c ali1435.c diff --git a/src/chipset/cs8220.c b/src/chipset/cs8220.c new file mode 100644 index 000000000..4c08ecef5 --- /dev/null +++ b/src/chipset/cs8220.c @@ -0,0 +1,289 @@ +/* + * 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. + * + * Emulation of C&T CS8220 ("PC/AT") chipset. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/chipset.h> + +typedef struct { + uint32_t virt; + uint32_t phys; + + uint32_t size; + + mem_mapping_t mapping; +} ram_bank_t; + +typedef struct { + uint8_t regs[3]; + + ram_bank_t ram_banks[3]; +} cs8220_t; + +static uint8_t +cs8220_mem_read(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint8_t ret = 0xff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = ram[addr]; + + return ret; +} + +static uint16_t +cs8220_mem_readw(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint16_t ret = 0xffff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = *(uint16_t *) &(ram[addr]); + + return ret; +} + +static void +cs8220_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ram[addr] = val; +} + +static void +cs8220_mem_writew(uint32_t addr, uint16_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + *(uint16_t *) &(ram[addr]) = val; +} + +static uint8_t +cs8220_in(uint16_t port, void *priv) { + cs8220_t *dev = (cs8220_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x00a4 ... 0x00a5: + ret = dev->regs[port & 0x0001]; + break; + case 0x00ab: + ret = dev->regs[2]; + break; + } + + return ret; +} + +static void +cs8220_out(uint16_t port, uint8_t val, void *priv) { + cs8220_t *dev = (cs8220_t *) priv; + + switch (port) { + case 0x00a4: + dev->regs[0] = val; + mem_a20_alt = val & 0x40; + mem_a20_recalc(); + break; + case 0x00a5: + dev->regs[1] = val; + if (val & 0x01) { + mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, 0x000040000); + mem_mapping_disable(&dev->ram_banks[1].mapping); + mem_mapping_disable(&dev->ram_banks[2].mapping); + } else { + mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, dev->ram_banks[0].size); + mem_mapping_enable(&dev->ram_banks[1].mapping); + mem_mapping_enable(&dev->ram_banks[2].mapping); + } + break; + case 0x00ab: + dev->regs[2] = val; + break; + } +} + +static void +cs8220_close(void *priv) +{ + cs8220_t *dev = (cs8220_t *) priv; + + free(dev); +} + +static void * +cs8220_init(UNUSED(const device_t *info)) +{ + cs8220_t *dev = (cs8220_t *) calloc(1, sizeof(cs8220_t)); + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + /* + Dell System 200: 640 kB soldered on-board, any other RAM is expansion. + */ + if (!strcmp(machine_get_internal_name(), "dells200")) switch (mem_size) { + default: + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x000a0000; + dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000; + fallthrough; + case 640: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + break; + /* + We are limited to steps of equal size, so we have to simulate some + memory expansions to work around the chipset's limits. + */ + } else switch (mem_size) { + case 256: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00020000; + dev->ram_banks[1].virt = 0x00020000; + dev->ram_banks[1].phys = 0x00020000; + dev->ram_banks[1].size = 0x00020000; + break; + case 384: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00020000; + /* Pretend there's a 128k expansion. */ + dev->ram_banks[2].virt = 0x00020000; + dev->ram_banks[2].phys = 0x00020000; + dev->ram_banks[2].size = 0x00040000; + break; + case 512: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + break; + default: + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x000a0000; + dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000; + fallthrough; + case 640: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + break; + case 768: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + /* Pretend there's a 128k expansion. */ + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x00080000; + dev->ram_banks[2].size = 0x00020000; + break; + case 896: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + /* Pretend there's a 256k expansion. */ + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x00080000; + dev->ram_banks[2].size = 0x00040000; + break; + case 1024: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00100000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00080000; + break; + } + + if (dev->ram_banks[0].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[0].mapping, dev->ram_banks[0].virt, dev->ram_banks[0].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[0].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[0])); + + if (dev->ram_banks[1].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[1].mapping, dev->ram_banks[1].virt, dev->ram_banks[1].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[1].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[1])); + + if (dev->ram_banks[2].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[2].mapping, dev->ram_banks[2].virt, dev->ram_banks[2].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[2].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[2])); + + io_sethandler(0x00a4, 0x0002, + cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev); + io_sethandler(0x00ab, 0x0001, + cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev); + + return dev; +} + +const device_t cs8220_device = { + .name = "C&T CS8220 (PC/AT)", + .internal_name = "cs8220", + .flags = 0, + .local = 0, + .init = cs8220_init, + .close = cs8220_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 688a5fecb..e11af5e4d 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -55,6 +55,7 @@ extern const device_t neat_sx_device; extern const device_t scat_device; extern const device_t scat_4_device; extern const device_t scat_sx_device; +extern const device_t cs8220_device; extern const device_t cs8230_device; extern const device_t cs4031_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ac26f7a50..137880a11 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -211,6 +211,7 @@ enum { MACHINE_CHIPSET_SCAT_SX, MACHINE_CHIPSET_NEAT, MACHINE_CHIPSET_NEAT_SX, + MACHINE_CHIPSET_CT_AT, MACHINE_CHIPSET_CT_386, MACHINE_CHIPSET_CT_CS4031, MACHINE_CHIPSET_CONTAQ_82C596, diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 8400e4ae8..2b181c499 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -273,8 +273,14 @@ machine_at_dells200_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); - device_add(&keyboard_at_device); + machine_at_common_init(model); + + device_add(&cs8220_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&keyboard_at_phoenix_device); return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d2ef357e1..4b5f82f5d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -117,11 +117,12 @@ const machine_filter_t machine_chipsets[] = { { "ALi ALADDiN IV+", MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS }, { "ALi ALADDiN V", MACHINE_CHIPSET_ALI_ALADDIN_V }, { "ALi ALADDiN-PRO II", MACHINE_CHIPSET_ALI_ALADDIN_PRO_II }, + { "C&T PC/AT", MACHINE_CHIPSET_CT_AT }, + { "C&T 386/AT", MACHINE_CHIPSET_CT_386 }, { "C&T 82C235 SCAT", MACHINE_CHIPSET_SCAT }, { "C&T 82C236 SCATsx", MACHINE_CHIPSET_SCAT_SX }, { "C&T CS8221 NEAT", MACHINE_CHIPSET_NEAT }, { "C&T CS8281 NEATsx", MACHINE_CHIPSET_NEAT_SX }, - { "C&T 386", MACHINE_CHIPSET_CT_386 }, { "C&T CS4031", MACHINE_CHIPSET_CT_CS4031 }, { "Contaq 82C596", MACHINE_CHIPSET_CONTAQ_82C596 }, { "Contaq 82C597", MACHINE_CHIPSET_CONTAQ_82C597 }, @@ -2975,47 +2976,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC - firmware. */ - { - .name = "[ISA] Dell System 200", - .internal_name = "dells200", - .type = MACHINE_TYPE_286, - .chipset = MACHINE_CHIPSET_PROPRIETARY, - .init = machine_at_dells200_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_286, - .block = CPU_BLOCK_NONE, - .min_bus = 6000000, - .max_bus = 12000000, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_AT, - .flags = MACHINE_FLAGS_NONE, - .ram = { - .min = 640, - .max = 16384, - .step = 128 - }, - .nvrmask = 127, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* Has IBM AT KBC firmware. */ { .name = "[ISA] MR BIOS 286 clone", @@ -3460,6 +3420,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC + firmware. */ + { + .name = "[C&T PC/AT] Dell System 200", + .internal_name = "dells200", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_CT_AT, + .init = machine_at_dells200_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 12000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has Quadtel KBC firmware. */ { .name = "[GC103] Quadtel 286 clone", @@ -5280,7 +5281,7 @@ const machine_t machines[] = { }, /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { - .name = "[C&T 386] ECS 386/32", + .name = "[C&T 386/AT] ECS 386/32", .internal_name = "ecs386", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_CT_386, @@ -5320,7 +5321,7 @@ const machine_t machines[] = { }, /* Has IBM AT KBC firmware. */ { - .name = "[C&T 386] Samsung SPC-6000A", + .name = "[C&T 386/AT] Samsung SPC-6000A", .internal_name = "spc6000a", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_CT_386,