From 8837d5d882dd92ee47d561db781656f7d8fafe43 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 14 Jun 2020 21:59:45 +0200 Subject: [PATCH] Implemented the National Semiconductors PC87307, PC87309, PC87332, and PC97307 Super I/O chips, fixed a number of bugs, and removed two machines from the Dev branch due to them now having the correct Super I/O chips. --- src/cdrom/cdrom.c | 5 + src/device/serial.c | 6 + src/disk/mo.c | 3 + src/disk/zip.c | 3 + src/include/86box/machine.h | 6 - src/include/86box/scsi_device.h | 1 + src/include/86box/scsi_ncr53c8xx.h | 1 + src/include/86box/sio.h | 4 + src/machine/m_at_386dx_486.c | 7 +- src/machine/m_at_slot1.c | 4 +- src/machine/m_at_socket7_s7.c | 4 + src/machine/machine_table.c | 4 - src/mem/mem.c | 6 +- src/mem/rom.c | 10 +- src/pc.c | 2 + src/pci.c | 1 + src/scsi/scsi.c | 31 +- src/scsi/scsi_device.c | 15 + src/scsi/scsi_disk.c | 2 + src/scsi/scsi_ncr53c8xx.c | 17 +- src/sio/sio_pc87306.c | 36 +- src/sio/sio_pc87307.c | 570 +++++++++++++++++++++++++++++ src/sio/sio_pc87309.c | 478 ++++++++++++++++++++++++ src/sio/sio_pc87332.c | 313 ++++++++++++++++ src/win/Makefile.mingw | 2 +- 25 files changed, 1472 insertions(+), 59 deletions(-) create mode 100644 src/sio/sio_pc87307.c create mode 100644 src/sio/sio_pc87309.c create mode 100644 src/sio/sio_pc87332.c diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index a6f57afbf..891606606 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -27,12 +27,14 @@ #include <86box/cdrom.h> #include <86box/cdrom_image.h> #include <86box/plat.h> +#include <86box/scsi_device.h> #include <86box/sound.h> /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#undef MSFtoLBA #define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) #define RAW_SECTOR_SIZE 2352 @@ -1171,6 +1173,9 @@ cdrom_close(void) for (i = 0; i < CDROM_NUM; i++) { dev = &cdrom[i]; + if (dev->bus_type == CDROM_BUS_SCSI) + memset(&scsi_devices[dev->scsi_device_id], 0x00, sizeof(scsi_device_t)); + if (dev->close) dev->close(dev->priv); diff --git a/src/device/serial.c b/src/device/serial.c index a5f673026..e5490d763 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -597,6 +597,9 @@ serial_read(uint16_t addr, void *p) void serial_remove(serial_t *dev) { + if (dev == NULL) + return; + if (!serial_enabled[dev->inst]) return; @@ -616,6 +619,9 @@ serial_setup(serial_t *dev, uint16_t addr, int irq) { serial_log("Adding serial port %i at %04X...\n", dev->inst, addr); + if (dev == NULL) + return; + if (!serial_enabled[dev->inst]) return; if (dev->base_address != 0x0000) diff --git a/src/disk/mo.c b/src/disk/mo.c index 4e1d134b7..59bf031f8 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -2139,6 +2139,9 @@ mo_close(void) int c; for (c = 0; c < MO_NUM; c++) { + if (mo_drives[c].bus_type == MO_BUS_SCSI) + memset(&scsi_devices[mo_drives[c].scsi_device_id], 0x00, sizeof(scsi_device_t)); + dev = (mo_t *) mo_drives[c].priv; if (dev) { diff --git a/src/disk/zip.c b/src/disk/zip.c index b47b31833..5156ce95e 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -2418,6 +2418,9 @@ zip_close(void) int c; for (c = 0; c < ZIP_NUM; c++) { + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) + memset(&scsi_devices[zip_drives[c].scsi_device_id], 0x00, sizeof(scsi_device_t)); + dev = (zip_t *) zip_drives[c].priv; if (dev) { diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 8efced08b..78d629288 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -238,9 +238,7 @@ extern int machine_at_r418_init(const machine_t *); extern int machine_at_ls486e_init(const machine_t *); extern int machine_at_4dps_init(const machine_t *); extern int machine_at_alfredo_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(NO_SIO) extern int machine_at_486sp3g_init(const machine_t *); -#endif extern int machine_at_486ap4_init(const machine_t *); /* m_at_commodore.c */ @@ -347,16 +345,12 @@ extern int machine_at_p2bls_init(const machine_t *); extern int machine_at_p3bf_init(const machine_t *); extern int machine_at_bf6_init(const machine_t *); extern int machine_at_atc6310bxii_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(NO_SIO) extern int machine_at_tsunamiatx_init(const machine_t *); -#endif extern int machine_at_p6sba_init(const machine_t *); #ifdef EMU_DEVICE_H -#if defined(DEV_BRANCH) && defined(NO_SIO) extern const device_t *at_tsunamiatx_get_device(void); #endif -#endif /* m_at_slot2.c */ extern int machine_at_6gxu_init(const machine_t *); diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index b5ae837c1..d9b39ffe2 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -379,5 +379,6 @@ extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); extern void scsi_device_command_phase1(scsi_device_t *dev); extern void scsi_device_command_stop(scsi_device_t *dev); extern void scsi_device_close_all(void); +extern void scsi_device_init(void); #endif /*SCSI_DEVICE_H*/ diff --git a/src/include/86box/scsi_ncr53c8xx.h b/src/include/86box/scsi_ncr53c8xx.h index f0cc4c5ec..423f8648e 100644 --- a/src/include/86box/scsi_ncr53c8xx.h +++ b/src/include/86box/scsi_ncr53c8xx.h @@ -26,6 +26,7 @@ extern const device_t ncr53c810_pci_device; +extern const device_t ncr53c810_onboard_pci_device; extern const device_t ncr53c825a_pci_device; extern const device_t ncr53c860_pci_device; extern const device_t ncr53c875_pci_device; diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index b618bfe1e..6e64742b6 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -25,6 +25,10 @@ extern const device_t fdc37c932fr_device; extern const device_t fdc37c932qf_device; extern const device_t fdc37c935_device; extern const device_t pc87306_device; +extern const device_t pc87307_device; +extern const device_t pc87309_device; +extern const device_t pc87332_device; +extern const device_t pc97307_device; extern const device_t sio_detect_device; extern const device_t um8669f_device; extern const device_t w83787f_device; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index e34b58fda..1e54c17df 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -445,7 +445,7 @@ machine_at_alfredo_init(const machine_t *model) return ret; } -#if defined(DEV_BRANCH) && defined(NO_SIO) + int machine_at_486sp3g_init(const machine_t *model) { @@ -471,15 +471,14 @@ machine_at_486sp3g_init(const machine_t *model) pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */ device_add(&sio_device); /* Site says it has a ZB, but the BIOS is designed for an IB. */ - device_add(&pc87306_device); /*PC87332*/ + device_add(&pc87332_device); device_add(&sst_flash_29ee010_device); device_add(&i420zx_device); - device_add(&ncr53c810_pci_device); + device_add(&ncr53c810_onboard_pci_device); return ret; } -#endif int diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index bac1b81a0..8fc5a6a5d 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -428,7 +428,6 @@ machine_at_p6sba_init(const machine_t *model) return ret; } -#if defined(DEV_BRANCH) && defined(NO_SIO) int machine_at_tsunamiatx_init(const machine_t *model) { @@ -458,7 +457,7 @@ machine_at_tsunamiatx_init(const machine_t *model) if (sound_card_current == SOUND_INTERNAL) device_add(&es1371_onboard_device); - device_add(&pc87306_device); /* PC87309 */ + device_add(&pc87309_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); @@ -471,4 +470,3 @@ at_tsunamiatx_get_device(void) { return &es1371_onboard_device; } -#endif diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c index 762219a98..aef798c34 100644 --- a/src/machine/m_at_socket7_s7.c +++ b/src/machine/m_at_socket7_s7.c @@ -813,6 +813,7 @@ machine_at_ym430tx_init(const machine_t *model) return ret; } + int machine_at_mb540n_init(const machine_t *model) { @@ -843,6 +844,7 @@ machine_at_mb540n_init(const machine_t *model) return ret; } + int machine_at_p5mms98_init(const machine_t *model) { @@ -908,6 +910,7 @@ machine_at_p5mms98_init(const machine_t *model) return ret; } + int machine_at_ficva502_init(const machine_t *model) { @@ -937,6 +940,7 @@ machine_at_ficva502_init(const machine_t *model) return ret; } + int machine_at_ficpa2012_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b1cb3736f..97db59b1d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -199,9 +199,7 @@ const machine_t machines[] = { /* 486 machines which utilize the PCI bus */ { "[486 PCI] ASUS PVI-486AP4", "486ap4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_486ap4_init, NULL }, -#if defined(DEV_BRANCH) && defined(NO_SIO) { "[486 PCI] ASUS PCI/I-486SP3G", "486sp3g", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_486sp3g_init, NULL }, -#endif { "[486 PCI] Intel Classic/PCI", "alfredo", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, { "[486 PCI] Lucky Star LS-486E", "ls486e", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_ls486e_init, NULL }, { "[486 PCI] Rise Computer R418", "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, @@ -307,9 +305,7 @@ const machine_t machines[] = { { "[Slot 1 BX] ASUS P3B-F", "p3bf", {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_p3bf_init, NULL }, { "[Slot 1 BX] ABit BF6", "bf6", {{"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_bf6_init, NULL }, { "[Slot 1 BX] A-Trend ATC6310BXII", "atc6310bxii", {{"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 }, -#if defined(DEV_BRANCH) && defined(NO_SIO) { "[Slot 1 BX] Tyan Tsunami ATX", "tsunamiatx", {{"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 }, -#endif { "[Slot 1 BX] Supermicro P6SBA", "p6sba", {{"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 }, /* Slot 2 machines */ diff --git a/src/mem/mem.c b/src/mem/mem.c index f83aee0fa..5ad097631 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2129,7 +2129,8 @@ mem_mapping_read_allowed(uint32_t flags, uint32_t state, int exec) break; default: - fatal("mem_mapping_read_allowed : bad state %x\n", state); + if (state_masked != MEM_READ_DISABLED) + fatal("mem_mapping_read_allowed : bad state %x\n", state_masked); break; } @@ -2176,7 +2177,8 @@ mem_mapping_write_allowed(uint32_t flags, uint32_t state) break; default: - fatal("mem_mapping_write_allowed : bad state %x\n", state); + if (state_masked != MEM_WRITE_DISABLED) + fatal("mem_mapping_write_allowed : bad state %x\n", state_masked); break; } diff --git a/src/mem/rom.c b/src/mem/rom.c index f8c4586ce..d05f69ae5 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -382,11 +382,11 @@ bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn { uint8_t ret = 0; - ret = bios_load_linear(fn3, 0x000f0000, 262144, 128); - ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, 128); - ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, 128); - ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, 128); - ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 128); + ret = bios_load_linear(fn3, 0x000f0000, 262144, off); + ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, off); + ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, off); + ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, off); + ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, off); return ret; } diff --git a/src/pc.c b/src/pc.c index 6b08fae3f..b2886b183 100644 --- a/src/pc.c +++ b/src/pc.c @@ -731,6 +731,8 @@ pc_reset_hard_init(void) sound_reset(); + scsi_device_init(); + /* Initialize the actual machine and its basic modules. */ machine_init(); diff --git a/src/pci.c b/src/pci.c index 4f5b40f66..a17a3e748 100644 --- a/src/pci.c +++ b/src/pci.c @@ -71,6 +71,7 @@ static int pci_type, static int trc_reg = 0, elcr_enabled = 1; +#define ENABLE_PCI_LOG 1 #ifdef ENABLE_PCI_LOG int pci_do_log = ENABLE_PCI_LOG; diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index c22d41fa9..829e273c1 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -84,7 +84,8 @@ static SCSI_CARD scsi_cards[] = { }; -int scsi_card_available(int card) +int +scsi_card_available(int card) { if (scsi_cards[card].device) return(device_available(scsi_cards[card].device)); @@ -93,19 +94,22 @@ int scsi_card_available(int card) } -char *scsi_card_getname(int card) +char * +scsi_card_getname(int card) { return((char *) scsi_cards[card].name); } -const device_t *scsi_card_getdevice(int card) +const device_t * +scsi_card_getdevice(int card) { return(scsi_cards[card].device); } -int scsi_card_has_config(int card) +int +scsi_card_has_config(int card) { if (! scsi_cards[card].device) return(0); @@ -113,13 +117,15 @@ int scsi_card_has_config(int card) } -char *scsi_card_get_internal_name(int card) +char * +scsi_card_get_internal_name(int card) { return((char *) scsi_cards[card].internal_name); } -int scsi_card_get_from_internal_name(char *s) +int +scsi_card_get_from_internal_name(char *s) { int c = 0; @@ -133,21 +139,12 @@ int scsi_card_get_from_internal_name(char *s) } -void scsi_card_init(void) +void +scsi_card_init(void) { - int i; - scsi_device_t *dev; - if (!scsi_cards[scsi_card_current].device) return; - for (i = 0; i < SCSI_ID_MAX; i++) { - dev = &(scsi_devices[i]); - - memset(dev, 0, sizeof(scsi_device_t)); - dev->type = SCSI_NONE; - } - device_add(scsi_cards[scsi_card_current].device); scsi_card_last = scsi_card_current; diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 19093c0ab..f4dc555c0 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -170,3 +170,18 @@ scsi_device_close_all(void) dev->command_stop(dev->sc); } } + + +void +scsi_device_init(void) +{ + int i; + scsi_device_t *dev; + + for (i = 0; i < SCSI_ID_MAX; i++) { + dev = &(scsi_devices[i]); + + memset(dev, 0, sizeof(scsi_device_t)); + dev->type = SCSI_NONE; + } +} diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index b4b7f6601..19d87bfa6 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -1261,6 +1261,8 @@ scsi_disk_close(void) for (c = 0; c < HDD_NUM; c++) { if (hdd[c].bus == HDD_BUS_SCSI) { + memset(&scsi_devices[hdd[c].scsi_id], 0x00, sizeof(scsi_device_t)); + hdd_image_close(c); dev = hdd[c].priv; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index 49ddef4ce..d9c06a33f 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -2646,14 +2646,17 @@ ncr53c8xx_init(const device_t *info) ncr53c8xx_pci_bar[0].addr_regs[0] = 1; ncr53c8xx_pci_bar[1].addr_regs[0] = 0; - dev->chip = info->local; + dev->chip = info->local & 0xff; ncr53c8xx_pci_regs[0x04] = 3; ncr53c8xx_mem_init(dev, 0x0fffff00); ncr53c8xx_mem_disable(dev); - dev->has_bios = device_get_config_int("bios"); + if (info->local & 0x8000) + dev->has_bios = 0; + else + dev->has_bios = device_get_config_int("bios"); if (dev->has_bios) rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (dev->chip >= CHIP_825) { @@ -2730,6 +2733,16 @@ const device_t ncr53c810_pci_device = ncr53c8xx_pci_config }; +const device_t ncr53c810_onboard_pci_device = +{ + "NCR 53c810 (SCSI) On-Board", + DEVICE_PCI, + 0x8001, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + NULL +}; + const device_t ncr53c825a_pci_device = { "NCR 53c825A (SCSI)", diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index 5f3b625f8..604567395 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -226,42 +226,40 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) case 0: if (valxor & 1) { lpt1_remove(); - if (val & 1) + if ((val & 1) && !(dev->regs[2] & 1)) lpt1_handler(dev); } if (valxor & 2) { serial_remove(dev->uart[0]); - if (val & 2) + if ((val & 2) && !(dev->regs[2] & 1)) serial_handler(dev, 0); } if (valxor & 4) { serial_remove(dev->uart[1]); - if (val & 4) + if ((val & 4) && !(dev->regs[2] & 1)) serial_handler(dev, 1); } if (valxor & 0x28) { fdc_remove(dev->fdc); - if (val & 8) + if ((val & 8) && !(dev->regs[2] & 1)) fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); } break; case 1: if (valxor & 3) { lpt1_remove(); - if (dev->regs[0] & 1) + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) lpt1_handler(dev); } if (valxor & 0xcc) { - if (dev->regs[0] & 2) + serial_remove(dev->uart[0]); + if ((dev->regs[0] & 2) && !(dev->regs[2] & 1)) serial_handler(dev, 0); - else - serial_remove(dev->uart[0]); } if (valxor & 0xf0) { - if (dev->regs[0] & 4) + serial_remove(dev->uart[1]); + if ((dev->regs[0] & 4) && !(dev->regs[2] & 1)) serial_handler(dev, 1); - else - serial_remove(dev->uart[1]); } break; case 2: @@ -282,6 +280,11 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); } } + if (valxor & 8) { + lpt1_remove(); + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) + lpt1_handler(dev); + } break; case 9: if (valxor & 0x44) { @@ -300,7 +303,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) case 0x19: if (valxor) { lpt1_remove(); - if (dev->regs[0] & 1) + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) lpt1_handler(dev); } break; @@ -309,15 +312,18 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) lpt1_remove(); if (!(val & 0x40)) dev->regs[0x19] = 0xEF; - if (dev->regs[0] & 1) + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) lpt1_handler(dev); } break; case 0x1C: if (valxor) { - if (dev->regs[0] & 2) + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + + if ((dev->regs[0] & 2) && !(dev->regs[2] & 1)) serial_handler(dev, 0); - if (dev->regs[0] & 4) + if ((dev->regs[0] & 4) && !(dev->regs[2] & 1)) serial_handler(dev, 1); } break; diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c new file mode 100644 index 000000000..c1372aa92 --- /dev/null +++ b/src/sio/sio_pc87307.c @@ -0,0 +1,570 @@ +/* + * 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 the NatSemi PC87307 Super I/O chip. + * + * + * + * Author: Miran Grca, + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/rom.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 id, pm_idx, + regs[48], ld_regs[256][208], + pcregs[16], gpio[8], + pm[8]; + uint16_t gpio_base, pm_base; + int cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} pc87307_t; + + +static void fdc_handler(pc87307_t *dev); +static void lpt1_handler(pc87307_t *dev); +static void serial_handler(pc87307_t *dev, int uart); + + +static void +pc87307_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + + dev->gpio[port & 7] = val; +} + + +uint8_t +pc87307_gpio_read(uint16_t port, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + + return dev->gpio[port & 7]; +} + + +static void +pc87307_gpio_remove(pc87307_t *dev) +{ + if (dev->gpio_base != 0xffff) { + io_removehandler(dev->gpio_base, 0x0008, + pc87307_gpio_read, NULL, NULL, pc87307_gpio_write, NULL, NULL, dev); + dev->gpio_base = 0xffff; + } +} + + +static void +pc87307_gpio_init(pc87307_t *dev, uint16_t addr) +{ + dev->gpio_base = addr; + + io_sethandler(dev->gpio_base, 0x0008, + pc87307_gpio_read, NULL, NULL, pc87307_gpio_write, NULL, NULL, dev); +} + + +static void +pc87307_pm_write(uint16_t port, uint8_t val, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + + if (port & 1) + dev->pm[dev->pm_idx] = val; + else { + dev->pm_idx = val & 0x07; + switch (dev->pm_idx) { + case 0x00: + fdc_handler(dev); + lpt1_handler(dev); + serial_handler(dev, 1); + serial_handler(dev, 0); + break; + } + } +} + + +uint8_t +pc87307_pm_read(uint16_t port, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + + if (port & 1) + return dev->pm[dev->pm_idx]; + else + return dev->pm_idx; +} + + +static void +pc87307_pm_remove(pc87307_t *dev) +{ + if (dev->pm_base != 0xffff) { + io_removehandler(dev->pm_base, 0x0008, + pc87307_pm_read, NULL, NULL, pc87307_pm_write, NULL, NULL, dev); + dev->pm_base = 0xffff; + } +} + + +static void +pc87307_pm_init(pc87307_t *dev, uint16_t addr) +{ + dev->pm_base = addr; + + io_sethandler(dev->pm_base, 0x0008, + pc87307_pm_read, NULL, NULL, pc87307_pm_write, NULL, NULL, dev); +} + + +static void +fdc_handler(pc87307_t *dev) +{ + uint8_t irq, active; + uint16_t addr; + + fdc_remove(dev->fdc); + + active = (dev->ld_regs[0x03][0x00] & 0x01) && (dev->pm[0x00] & 0x08); + addr = ((dev->ld_regs[0x03][0x30] << 8) | dev->ld_regs[0x00][0x31]) - 0x0002; + irq = (dev->ld_regs[0x03][0x40] & 0x0f); + + if (active) { + fdc_set_base(dev->fdc, addr); + fdc_set_irq(dev->fdc, irq); + } +} + + +static void +lpt1_handler(pc87307_t *dev) +{ + uint8_t irq, active; + uint16_t addr; + + lpt1_remove(); + + active = (dev->ld_regs[0x04][0x00] & 0x01) && (dev->pm[0x00] & 0x10); + addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31]; + irq = (dev->ld_regs[0x04][0x40] & 0x0f); + + if (active) { + lpt1_init(addr); + lpt1_irq(irq); + } +} + + +static void +serial_handler(pc87307_t *dev, int uart) +{ + uint8_t irq, active; + uint16_t addr; + + serial_remove(dev->uart[uart]); + + active = (dev->ld_regs[0x06 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart))); + addr = (dev->ld_regs[0x06 - uart][0x30] << 8) | dev->ld_regs[0x06 - uart][0x31]; + irq = (dev->ld_regs[0x06 - uart][0x40] & 0x0f); + + if (active) + serial_setup(dev->uart[uart], addr, irq); +} + + +static void +gpio_handler(pc87307_t *dev) +{ + uint8_t active; + uint16_t addr; + + pc87307_gpio_remove(dev); + + active = (dev->ld_regs[0x07][0x00] & 0x01); + addr = (dev->ld_regs[0x07][0x30] << 8) | dev->ld_regs[0x07][0x31]; + + if (active) + pc87307_gpio_init(dev, addr); +} + + +static void +pm_handler(pc87307_t *dev) +{ + uint8_t active; + uint16_t addr; + + pc87307_pm_remove(dev); + + active = (dev->ld_regs[0x08][0x00] & 0x01); + addr = (dev->ld_regs[0x08][0x30] << 8) | dev->ld_regs[0x08][0x31]; + + if (active) + pc87307_pm_init(dev, addr); +} + + +static void +pc87307_write(uint16_t port, uint8_t val, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + uint8_t index; + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val; + return; + } else { + switch (dev->cur_reg) { + case 0x00: case 0x02: case 0x03: case 0x06: + case 0x07: case 0x21: + dev->regs[dev->cur_reg] = val; + break; + case 0x22: + dev->regs[dev->cur_reg] = val & 0x7f; + break; + case 0x23: + dev->regs[dev->cur_reg] = val & 0x0f; + break; + case 0x24: + dev->pcregs[dev->regs[0x23]] = val; + break; + default: + if (dev->cur_reg >= 0x30) { + if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10)) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; + } + break; + } + } + + switch(dev->cur_reg) { + case 0x30: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01; + switch (dev->regs[0x07]) { + case 0x03: + fdc_handler(dev); + break; + case 0x04: + lpt1_handler(dev); + break; + case 0x05: + serial_handler(dev, 1); + break; + case 0x06: + serial_handler(dev, 0); + break; + case 0x07: + gpio_handler(dev); + break; + case 0x08: + pm_handler(dev); + break; + } + break; + case 0x60: case 0x62: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07; + if (dev->cur_reg == 0x62) + break; + switch (dev->regs[0x07]) { + case 0x03: + fdc_handler(dev); + break; + case 0x04: + lpt1_handler(dev); + break; + case 0x05: + serial_handler(dev, 1); + break; + case 0x06: + serial_handler(dev, 0); + break; + case 0x07: + gpio_handler(dev); + break; + case 0x08: + pm_handler(dev); + break; + } + break; + case 0x61: + switch (dev->regs[0x07]) { + case 0x00: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfb; + break; + case 0x03: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + fdc_handler(dev); + break; + case 0x04: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc; + lpt1_handler(dev); + break; + case 0x05: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + serial_handler(dev, 1); + break; + case 0x06: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + serial_handler(dev, 0); + break; + case 0x07: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + gpio_handler(dev); + break; + case 0x08: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; + pm_handler(dev); + break; + } + break; + case 0x63: + if (dev->regs[0x07] == 0x00) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfb) | 0x04; + break; + case 0x70: + case 0x74: case 0x75: + switch (dev->regs[0x07]) { + case 0x03: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + fdc_handler(dev); + break; + case 0x04: + lpt1_handler(dev); + break; + case 0x05: + serial_handler(dev, 1); + break; + case 0x06: + serial_handler(dev, 0); + break; + case 0x07: + gpio_handler(dev); + break; + case 0x08: + pm_handler(dev); + break; + } + break; + case 0xf0: + switch (dev->regs[0x07]) { + case 0x00: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1; + break; + case 0x03: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1; + fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0); + fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0); + break; + case 0x04: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3; + lpt1_handler(dev); + break; + case 0x05: case 0x06: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87; + break; + } + break; + case 0xf1: + if (dev->regs[0x07] == 0x03) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f; + break; + } +} + + +uint8_t +pc87307_read(uint16_t port, void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg >= 0x30) + ret = dev->regs[dev->cur_reg]; + else if (dev->cur_reg == 0x24) + ret = dev->pcregs[dev->regs[0x23]]; + else + ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + } + + return ret; +} + + +void +pc87307_reset(pc87307_t *dev) +{ + int i; + + memset(dev->regs, 0x00, 0x30); + for (i = 0; i < 256; i++) + memset(dev->ld_regs[i], 0x00, 0xd0); + memset(dev->pcregs, 0x00, 0x10); + memset(dev->gpio, 0x00, 0x08); + memset(dev->pm, 0x00, 0x08); + + dev->regs[0x20] = dev->id; + dev->regs[0x21] = 0x04; + + dev->ld_regs[0x00][0x01] = 0x01; + dev->ld_regs[0x00][0x31] = 0x60; + dev->ld_regs[0x00][0x33] = 0x64; + dev->ld_regs[0x00][0x40] = 0x01; + dev->ld_regs[0x00][0x41] = 0x02; + dev->ld_regs[0x00][0x44] = 0x04; + dev->ld_regs[0x00][0x45] = 0x04; + dev->ld_regs[0x00][0xc0] = 0x40; + + dev->ld_regs[0x01][0x40] = 0x0c; + dev->ld_regs[0x01][0x41] = 0x02; + dev->ld_regs[0x01][0x44] = 0x04; + dev->ld_regs[0x01][0x45] = 0x04; + + dev->ld_regs[0x02][0x00] = 0x01; + dev->ld_regs[0x02][0x31] = 0x70; + dev->ld_regs[0x02][0x40] = 0x08; + dev->ld_regs[0x02][0x44] = 0x04; + dev->ld_regs[0x02][0x45] = 0x04; + + dev->ld_regs[0x03][0x01] = 0x01; + dev->ld_regs[0x03][0x30] = 0x03; + dev->ld_regs[0x03][0x31] = 0xf2; + dev->ld_regs[0x03][0x40] = 0x06; + dev->ld_regs[0x03][0x41] = 0x03; + dev->ld_regs[0x03][0x44] = 0x02; + dev->ld_regs[0x03][0x45] = 0x04; + dev->ld_regs[0x03][0xc0] = 0x02; + + dev->ld_regs[0x04][0x30] = 0x02; + dev->ld_regs[0x04][0x31] = 0x78; + dev->ld_regs[0x04][0x40] = 0x07; + dev->ld_regs[0x04][0x44] = 0x04; + dev->ld_regs[0x04][0x45] = 0x04; + dev->ld_regs[0x04][0xc0] = 0xf2; + + dev->ld_regs[0x05][0x30] = 0x02; + dev->ld_regs[0x05][0x31] = 0xf8; + dev->ld_regs[0x05][0x40] = 0x03; + dev->ld_regs[0x05][0x41] = 0x03; + dev->ld_regs[0x05][0x44] = 0x04; + dev->ld_regs[0x05][0x45] = 0x04; + dev->ld_regs[0x05][0xc0] = 0x02; + + dev->ld_regs[0x06][0x30] = 0x03; + dev->ld_regs[0x06][0x31] = 0xf8; + dev->ld_regs[0x06][0x40] = 0x04; + dev->ld_regs[0x06][0x41] = 0x03; + dev->ld_regs[0x06][0x44] = 0x04; + dev->ld_regs[0x06][0x45] = 0x04; + dev->ld_regs[0x06][0xc0] = 0x02; + + dev->ld_regs[0x07][0x44] = 0x04; + dev->ld_regs[0x07][0x45] = 0x04; + + dev->ld_regs[0x08][0x44] = 0x04; + dev->ld_regs[0x08][0x45] = 0x04; + + dev->gpio[0] = 0xff; + dev->gpio[1] = 0xfb; + + dev->pm[0] = 0xff; + dev->pm[1] = 0xff; + dev->pm[4] = 0x0e; + dev->pm[7] = 0x01; + + dev->gpio_base = dev->pm_base = 0xffff; + + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + fdc_reset(dev->fdc); +} + + +static void +pc87307_close(void *priv) +{ + pc87307_t *dev = (pc87307_t *) priv; + + free(dev); +} + + +static void * +pc87307_init(const device_t *info) +{ + pc87307_t *dev = (pc87307_t *) malloc(sizeof(pc87307_t)); + memset(dev, 0, sizeof(pc87307_t)); + + dev->id = info->local & 0xff; + + dev->fdc = device_add(&fdc_at_nsc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + pc87307_reset(dev); + + io_sethandler(0x02e, 0x0002, + pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + + return dev; +} + + +const device_t pc87307_device = { + "National Semiconductor PC87307 Super I/O", + 0, + 0xc0, + pc87307_init, pc87307_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t pc97307_device = { + "National Semiconductor PC97307 Super I/O", + 0, + 0xcf, + pc87307_init, pc87307_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c new file mode 100644 index 000000000..683af7089 --- /dev/null +++ b/src/sio/sio_pc87309.c @@ -0,0 +1,478 @@ +/* + * 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 the NatSemi PC87309 Super I/O chip. + * + * + * + * Author: Miran Grca, + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/rom.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 id, pm_idx, + regs[48], ld_regs[256][208], + pm[8]; + uint16_t pm_base; + int cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} pc87309_t; + + +static void fdc_handler(pc87309_t *dev); +static void lpt1_handler(pc87309_t *dev); +static void serial_handler(pc87309_t *dev, int uart); + + +static void +pc87309_pm_write(uint16_t port, uint8_t val, void *priv) +{ + pc87309_t *dev = (pc87309_t *) priv; + + if (port & 1) + dev->pm[dev->pm_idx] = val; + else { + dev->pm_idx = val & 0x07; + switch (dev->pm_idx) { + case 0x00: + fdc_handler(dev); + lpt1_handler(dev); + serial_handler(dev, 1); + serial_handler(dev, 0); + break; + } + } +} + + +uint8_t +pc87309_pm_read(uint16_t port, void *priv) +{ + pc87309_t *dev = (pc87309_t *) priv; + + if (port & 1) + return dev->pm[dev->pm_idx]; + else + return dev->pm_idx; +} + + +static void +pc87309_pm_remove(pc87309_t *dev) +{ + if (dev->pm_base != 0xffff) { + io_removehandler(dev->pm_base, 0x0008, + pc87309_pm_read, NULL, NULL, pc87309_pm_write, NULL, NULL, dev); + dev->pm_base = 0xffff; + } +} + + +static void +pc87309_pm_init(pc87309_t *dev, uint16_t addr) +{ + dev->pm_base = addr; + + io_sethandler(dev->pm_base, 0x0008, + pc87309_pm_read, NULL, NULL, pc87309_pm_write, NULL, NULL, dev); +} + + +static void +fdc_handler(pc87309_t *dev) +{ + uint8_t irq, active; + uint16_t addr; + + fdc_remove(dev->fdc); + + active = (dev->ld_regs[0x00][0x00] & 0x01) && (dev->pm[0x00] & 0x08); + addr = ((dev->ld_regs[0x00][0x30] << 8) | dev->ld_regs[0x00][0x31]) - 0x0002; + irq = (dev->ld_regs[0x00][0x40] & 0x0f); + + if (active) { + fdc_set_base(dev->fdc, addr); + fdc_set_irq(dev->fdc, irq); + } +} + + +static void +lpt1_handler(pc87309_t *dev) +{ + uint8_t irq, active; + uint16_t addr; + + lpt1_remove(); + + active = (dev->ld_regs[0x01][0x00] & 0x01) && (dev->pm[0x00] & 0x10); + addr = (dev->ld_regs[0x01][0x30] << 8) | dev->ld_regs[0x01][0x31]; + irq = (dev->ld_regs[0x01][0x40] & 0x0f); + + if (active) { + lpt1_init(addr); + lpt1_irq(irq); + } +} + + +static void +serial_handler(pc87309_t *dev, int uart) +{ + uint8_t irq, active; + uint16_t addr; + + serial_remove(dev->uart[uart]); + + active = (dev->ld_regs[0x03 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart))); + addr = (dev->ld_regs[0x03 - uart][0x30] << 8) | dev->ld_regs[0x03 - uart][0x31]; + irq = (dev->ld_regs[0x03 - uart][0x40] & 0x0f); + + if (active) + serial_setup(dev->uart[uart], addr, irq); +} + + +static void +pm_handler(pc87309_t *dev) +{ + uint8_t active; + uint16_t addr; + + pc87309_pm_remove(dev); + + active = (dev->ld_regs[0x04][0x00] & 0x01); + addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31]; + + if (active) + pc87309_pm_init(dev, addr); +} + + +static void +pc87309_write(uint16_t port, uint8_t val, void *priv) +{ + pc87309_t *dev = (pc87309_t *) priv; + uint8_t index; + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val; + return; + } else { + switch (dev->cur_reg) { + case 0x00: case 0x02: case 0x03: case 0x06: + case 0x07: case 0x21: + dev->regs[dev->cur_reg] = val; + break; + case 0x22: + dev->regs[dev->cur_reg] = val & 0x7f; + break; + default: + if (dev->cur_reg >= 0x30) { + if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10)) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; + } + break; + } + } + + switch(dev->cur_reg) { + case 0x30: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01; + switch (dev->regs[0x07]) { + case 0x00: + fdc_handler(dev); + break; + case 0x01: + lpt1_handler(dev); + break; + case 0x02: + serial_handler(dev, 1); + break; + case 0x03: + serial_handler(dev, 0); + break; + case 0x04: + pm_handler(dev); + break; + } + break; + case 0x60: case 0x62: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07; + if (dev->cur_reg == 0x62) + break; + switch (dev->regs[0x07]) { + case 0x00: + fdc_handler(dev); + break; + case 0x01: + lpt1_handler(dev); + break; + case 0x02: + serial_handler(dev, 1); + break; + case 0x03: + serial_handler(dev, 0); + break; + case 0x04: + pm_handler(dev); + break; + } + break; + case 0x63: + if (dev->regs[0x07] == 0x06) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xf8) | 0x04; + break; + case 0x61: + switch (dev->regs[0x07]) { + case 0x00: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + fdc_handler(dev); + break; + case 0x01: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc; + lpt1_handler(dev); + break; + case 0x02: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + serial_handler(dev, 1); + break; + case 0x03: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + serial_handler(dev, 0); + break; + case 0x04: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; + pm_handler(dev); + break; + case 0x06: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + break; + } + break; + case 0x70: + case 0x74: case 0x75: + switch (dev->regs[0x07]) { + case 0x00: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + fdc_handler(dev); + break; + case 0x01: + lpt1_handler(dev); + break; + case 0x02: + serial_handler(dev, 1); + break; + case 0x03: + serial_handler(dev, 0); + break; + case 0x04: + pm_handler(dev); + break; + } + break; + case 0xf0: + switch (dev->regs[0x07]) { + case 0x00: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1; + fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0); + fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0); + break; + case 0x01: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3; + lpt1_handler(dev); + break; + case 0x02: case 0x03: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87; + break; + case 0x06: + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1; + break; + } + break; + case 0xf1: + if (dev->regs[0x07] == 0x00) + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f; + break; + } +} + + +uint8_t +pc87309_read(uint16_t port, void *priv) +{ + pc87309_t *dev = (pc87309_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + if (index) + ret = dev->cur_reg & 0x1f; + else { + if (dev->cur_reg == 8) + ret = 0x70; + else if (dev->cur_reg < 28) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +void +pc87309_reset(pc87309_t *dev) +{ + int i; + + memset(dev->regs, 0x00, 0x30); + for (i = 0; i < 256; i++) + memset(dev->ld_regs[i], 0x00, 0xd0); + memset(dev->pm, 0x00, 0x08); + + dev->regs[0x20] = dev->id; + dev->regs[0x21] = 0x04; + + dev->ld_regs[0x00][0x01] = 0x01; + dev->ld_regs[0x00][0x30] = 0x03; + dev->ld_regs[0x00][0x31] = 0xf2; + dev->ld_regs[0x00][0x40] = 0x06; + dev->ld_regs[0x00][0x41] = 0x03; + dev->ld_regs[0x00][0x44] = 0x02; + dev->ld_regs[0x00][0x45] = 0x04; + dev->ld_regs[0x00][0xc0] = 0x02; + + dev->ld_regs[0x01][0x30] = 0x02; + dev->ld_regs[0x01][0x31] = 0x78; + dev->ld_regs[0x01][0x40] = 0x07; + dev->ld_regs[0x01][0x44] = 0x04; + dev->ld_regs[0x01][0x45] = 0x04; + dev->ld_regs[0x01][0xc0] = 0xf2; + + dev->ld_regs[0x02][0x30] = 0x02; + dev->ld_regs[0x02][0x31] = 0xf8; + dev->ld_regs[0x02][0x40] = 0x03; + dev->ld_regs[0x02][0x41] = 0x03; + dev->ld_regs[0x02][0x44] = 0x04; + dev->ld_regs[0x02][0x45] = 0x04; + dev->ld_regs[0x02][0xc0] = 0x02; + + dev->ld_regs[0x03][0x30] = 0x03; + dev->ld_regs[0x03][0x31] = 0xf8; + dev->ld_regs[0x03][0x40] = 0x04; + dev->ld_regs[0x03][0x41] = 0x03; + dev->ld_regs[0x03][0x44] = 0x04; + dev->ld_regs[0x03][0x45] = 0x04; + dev->ld_regs[0x03][0xc0] = 0x02; + + dev->ld_regs[0x04][0x44] = 0x04; + dev->ld_regs[0x04][0x45] = 0x04; + + dev->ld_regs[0x05][0x40] = 0x0c; + dev->ld_regs[0x05][0x41] = 0x02; + dev->ld_regs[0x05][0x44] = 0x04; + dev->ld_regs[0x05][0x45] = 0x04; + + dev->ld_regs[0x06][0x01] = 0x01; + dev->ld_regs[0x06][0x31] = 0x60; + dev->ld_regs[0x06][0x33] = 0x64; + dev->ld_regs[0x06][0x40] = 0x01; + dev->ld_regs[0x06][0x41] = 0x02; + dev->ld_regs[0x06][0x44] = 0x04; + dev->ld_regs[0x06][0x45] = 0x04; + dev->ld_regs[0x06][0xc0] = 0x40; + + dev->regs[0x00] = 0x0B; + dev->regs[0x01] = 0x01; + dev->regs[0x03] = 0x01; + dev->regs[0x05] = 0x0D; + dev->regs[0x08] = 0x70; + dev->regs[0x09] = 0xC0; + dev->regs[0x0b] = 0x80; + dev->regs[0x0f] = 0x1E; + dev->regs[0x12] = 0x30; + dev->regs[0x19] = 0xEF; + + dev->pm[0] = 0xe9; + dev->pm[4] = 0x0e; + + dev->pm_base = 0xffff; + + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + fdc_reset(dev->fdc); +} + + +static void +pc87309_close(void *priv) +{ + pc87309_t *dev = (pc87309_t *) priv; + + free(dev); +} + + +static void * +pc87309_init(const device_t *info) +{ + pc87309_t *dev = (pc87309_t *) malloc(sizeof(pc87309_t)); + memset(dev, 0, sizeof(pc87309_t)); + + dev->id = info->local & 0xff; + + dev->fdc = device_add(&fdc_at_nsc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + pc87309_reset(dev); + + io_sethandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + + return dev; +} + + +const device_t pc87309_device = { + "National Semiconductor PC87309 Super I/O", + 0, + 0xe0, + pc87309_init, pc87309_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c new file mode 100644 index 000000000..3a9b04785 --- /dev/null +++ b/src/sio/sio_pc87332.c @@ -0,0 +1,313 @@ +/* + * 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 the NatSemi PC87332 Super I/O chip. + * + * + * + * Author: Miran Grca, + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/rom.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 tries, + regs[15]; + int cur_reg; + fdc_t *fdc; + serial_t *uart[2]; + nvr_t *nvr; +} pc87332_t; + + +static void +lpt1_handler(pc87332_t *dev) +{ + int temp; + uint16_t lpt_port = 0x378; + uint8_t lpt_irq = 5; + + temp = dev->regs[0x01] & 3; + + switch (temp) { + case 0: + lpt_port = 0x378; + lpt_irq = (dev->regs[0x02] & 0x08) ? 7 : 5; + break; + case 1: + lpt_port = 0x3bc; + lpt_irq = 7; + break; + case 2: + lpt_port = 0x278; + lpt_irq = 5; + break; + case 3: + lpt_port = 0x000; + lpt_irq = 0xff; + break; + } + + if (lpt_port) + lpt1_init(lpt_port); + + lpt1_irq(lpt_irq); +} + + +static void +serial_handler(pc87332_t *dev, int uart) +{ + int temp; + + temp = (dev->regs[1] >> (2 << uart)) & 3; + + switch (temp) { + case 0: + serial_setup(dev->uart[uart], SERIAL1_ADDR, 4); + break; + case 1: + serial_setup(dev->uart[uart], SERIAL2_ADDR, 3); + break; + case 2: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x3e8, 4); + break; + case 1: + serial_setup(dev->uart[uart], 0x338, 4); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e8, 4); + break; + case 3: + serial_setup(dev->uart[uart], 0x220, 4); + break; + } + break; + case 3: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x2e8, 3); + break; + case 1: + serial_setup(dev->uart[uart], 0x238, 3); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e0, 3); + break; + case 3: + serial_setup(dev->uart[uart], 0x228, 3); + break; + } + break; + } +} + + +static void +pc87332_write(uint16_t port, uint8_t val, void *priv) +{ + pc87332_t *dev = (pc87332_t *) priv; + uint8_t index, valxor; + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val & 0x1f; + dev->tries = 0; + return; + } else { + if (dev->tries) { + valxor = val ^ dev->regs[dev->cur_reg]; + dev->tries = 0; + if ((dev->cur_reg <= 14) && (dev->cur_reg != 8)) + dev->regs[dev->cur_reg] = val; + else + return; + } else { + dev->tries++; + return; + } + } + + switch(dev->cur_reg) { + case 0: + if (valxor & 1) { + lpt1_remove(); + if ((val & 1) && !(dev->regs[2] & 1)) + lpt1_handler(dev); + } + if (valxor & 2) { + serial_remove(dev->uart[0]); + if ((val & 2) && !(dev->regs[2] & 1)) + serial_handler(dev, 0); + } + if (valxor & 4) { + serial_remove(dev->uart[1]); + if ((val & 4) && !(dev->regs[2] & 1)) + serial_handler(dev, 1); + } + if (valxor & 0x28) { + fdc_remove(dev->fdc); + if ((val & 8) && !(dev->regs[2] & 1)) + fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); + } + break; + case 1: + if (valxor & 3) { + lpt1_remove(); + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) + lpt1_handler(dev); + } + if (valxor & 0xcc) { + serial_remove(dev->uart[0]); + if ((dev->regs[0] & 2) && !(dev->regs[2] & 1)) + serial_handler(dev, 0); + } + if (valxor & 0xf0) { + serial_remove(dev->uart[1]); + if ((dev->regs[0] & 4) && !(dev->regs[2] & 1)) + serial_handler(dev, 1); + } + break; + case 2: + if (valxor & 1) { + lpt1_remove(); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + fdc_remove(dev->fdc); + + if (!(val & 1)) { + if (dev->regs[0] & 1) + lpt1_handler(dev); + if (dev->regs[0] & 2) + serial_handler(dev, 0); + if (dev->regs[0] & 4) + serial_handler(dev, 1); + if (dev->regs[0] & 8) + fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); + } + } + if (valxor & 8) { + lpt1_remove(); + if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) + lpt1_handler(dev); + } + break; + } +} + + +uint8_t +pc87332_read(uint16_t port, void *priv) +{ + pc87332_t *dev = (pc87332_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + dev->tries = 0; + + if (index) + ret = dev->cur_reg & 0x1f; + else { + if (dev->cur_reg == 8) + ret = 0x10; + else if (dev->cur_reg < 14) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +void +pc87332_reset(pc87332_t *dev) +{ + memset(dev->regs, 0, 15); + + dev->regs[0x00] = 0x0F; + dev->regs[0x01] = 0x10; + dev->regs[0x03] = 0x01; + dev->regs[0x05] = 0x0D; + dev->regs[0x08] = 0x70; + + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + lpt1_handler(dev); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + serial_handler(dev, 0); + serial_handler(dev, 1); + fdc_reset(dev->fdc); +} + + +static void +pc87332_close(void *priv) +{ + pc87332_t *dev = (pc87332_t *) priv; + + free(dev); +} + + +static void * +pc87332_init(const device_t *info) +{ + pc87332_t *dev = (pc87332_t *) malloc(sizeof(pc87332_t)); + memset(dev, 0, sizeof(pc87332_t)); + + dev->fdc = device_add(&fdc_at_nsc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + // dev->nvr = device_add(&piix4_nvr_device); + + pc87332_reset(dev); + + io_sethandler(0x02e, 0x0002, + pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev); + + return dev; +} + + +const device_t pc87332_device = { + "National Semiconductor PC87332 Super I/O", + 0, + 0, + pc87332_init, pc87332_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 4c1c694aa..2eb242ce3 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -593,7 +593,7 @@ SIOOBJ := sio_acc3221.o \ sio_f82c710.o \ sio_fdc37c66x.o sio_fdc37c669.o \ sio_fdc37c93x.o \ - sio_pc87306.o \ + sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87332.o \ sio_w83787f.o \ sio_w83877f.o sio_w83977f.o \ sio_um8669f.o