From 4f6df76f1092ee1070eda628b4fddf55ce143077 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 17:40:39 +0200 Subject: [PATCH 001/140] Revert "Revert "Merge branch 'feature/machine_and_kb' into master"" This reverts commit f2cd3756dd0e0abaecc0d2f0d912d1dae66e6333. --- src/CMakeLists.txt | 4 +- src/acpi.c | 184 +- src/chipset/CMakeLists.txt | 17 +- src/chipset/ali1531.c | 371 ++-- src/chipset/ali1543.c | 1938 ++++++++++++------ src/chipset/opti391.c | 226 +++ src/chipset/opti895.c | 32 +- src/chipset/vl82c480.c | 25 +- src/config.c | 20 +- src/cpu/386_ops.h | 8 +- src/cpu/x86.c | 11 +- src/cpu/x86_ops_msr.h | 2 + src/device/kbc_at.c | 2324 +++++++++++++++++++++ src/device/kbd_at.c | 1162 +++++++++++ src/device/keyboard_at.c | 2794 ++++++++++++++++---------- src/device/keyboard_xt.c | 236 ++- src/device/mouse_ps2.c | 61 +- src/disk/hdc_ide.c | 59 +- src/disk/hdc_ide_sff8038i.c | 97 +- src/dma.c | 30 +- src/include/86box/acpi.h | 8 +- src/include/86box/chipset.h | 15 +- src/include/86box/hdc_ide.h | 3 + src/include/86box/hdc_ide_sff8038i.h | 6 +- src/include/86box/keyboard.h | 7 +- src/include/86box/machine.h | 149 +- src/include/86box/pci.h | 4 + src/include/86box/pic.h | 5 + src/include/86box/pit.h | 29 +- src/include/86box/port_6x.h | 38 + src/include/86box/sio.h | 2 + src/include/86box/spd.h | 1 + src/include/86box/vid_svga.h | 11 +- src/include/86box/vid_svga_render.h | 2 + src/include/86box/video.h | 5 +- src/log.c | 3 + src/machine/CMakeLists.txt | 5 +- src/machine/m_at.c | 5 + src/machine/m_at_286_386sx.c | 91 +- src/machine/m_at_386dx_486.c | 288 +-- src/machine/m_at_slot1.c | 33 +- src/machine/m_at_socket370.c | 38 +- src/machine/m_at_socket4.c | 406 ++++ src/machine/m_at_socket5.c | 446 ++++ src/machine/m_at_socket7.c | 865 +++----- src/machine/m_at_socket7_3v.c | 514 +++++ src/machine/m_at_socket8.c | 2 + src/machine/m_ps1.c | 2 + src/machine/m_ps2_isa.c | 4 +- src/machine/m_ps2_mca.c | 4 +- src/machine/m_xt.c | 22 - src/machine/m_xt_olivetti.c | 5 + src/machine/m_xt_xi8088.c | 2 + src/machine/machine_table.c | 500 ++++- src/mem/mem.c | 41 +- src/mem/rom.c | 6 +- src/mem/spd.c | 56 + src/pci.c | 3 +- src/pic.c | 44 + src/pit.c | 465 +++-- src/port_6x.c | 214 ++ src/sio/CMakeLists.txt | 2 +- src/sio/sio_fdc37c67x.c | 613 ++++++ src/sio/sio_pc87332.c | 10 + src/sound/snd_sb.c | 3 +- src/usb.c | 3 + src/video/CMakeLists.txt | 4 +- src/video/vid_cl54xx.c | 24 +- src/video/vid_et3000.c | 308 +++ src/video/vid_et4000.c | 153 +- src/video/vid_et4000w32.c | 7 +- src/video/vid_oak_oti.c | 38 +- src/video/vid_s3.c | 30 +- src/video/vid_svga.c | 152 +- src/video/vid_table.c | 2 + src/win/Makefile.mingw | 65 +- src/win/win.c | 3 +- 77 files changed, 11883 insertions(+), 3484 deletions(-) create mode 100644 src/chipset/opti391.c create mode 100644 src/device/kbc_at.c create mode 100644 src/device/kbd_at.c create mode 100644 src/include/86box/port_6x.h create mode 100644 src/machine/m_at_socket4.c create mode 100644 src/machine/m_at_socket5.c create mode 100644 src/machine/m_at_socket7_3v.c create mode 100644 src/port_6x.c create mode 100644 src/sio/sio_fdc37c67x.c create mode 100644 src/video/vid_et3000.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1f4b9c7c..d4a22abbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,8 +14,8 @@ # # WIN32 marks us as a GUI app on Windows -add_executable(86Box WIN32 86box.c config.c random.c timer.c io.c acpi.c apm.c - dma.c ddma.c nmi.c pic.c pit.c port_92.c ppi.c pci.c mca.c usb.c +add_executable(86Box WIN32 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c + dma.c ddma.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c mca.c usb.c device.c nvr.c nvr_at.c nvr_ps2.c) if(NEW_DYNAREC) diff --git a/src/acpi.c b/src/acpi.c index e9acd971a..0c3af0ed2 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -75,11 +75,15 @@ acpi_update_irq(void *priv) if (sci_level) { if (dev->irq_mode == 1) pci_set_irq(dev->slot, dev->irq_pin); + else if (dev->irq_mode == 2) + pci_set_mirq(5, dev->mirq_is_level); else pci_set_mirq(0xf0 | dev->irq_line, 1); } else { if (dev->irq_mode == 1) pci_clear_irq(dev->slot, dev->irq_pin); + else if (dev->irq_mode == 2) + pci_clear_mirq(5, dev->mirq_is_level); else pci_clear_mirq(0xf0 | dev->irq_line, 1); } @@ -87,22 +91,29 @@ acpi_update_irq(void *priv) static void -acpi_raise_smi(void *priv) +acpi_raise_smi(void *priv, int do_smi) { acpi_t *dev = (acpi_t *) priv; if (dev->regs.glbctl & 0x01) { if ((dev->vendor == VEN_VIA) || (dev->vendor == VEN_VIA_596B)) { - if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { - smi_line = 1; + if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { + if (do_smi) + smi_line = 1; dev->regs.smi_active = 1; } } else if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) { - smi_line = 1; + if (do_smi) + smi_line = 1; /* Clear bit 16 of GLBCTL. */ - dev->regs.glbctl &= ~0x00010000; - } else if (dev->vendor == VEN_SMC) - smi_line = 1; + if (dev->vendor == VEN_INTEL) + dev->regs.glbctl &= ~0x00010000; + else + dev->regs.ali_soft_smi = 1; + } else if (dev->vendor == VEN_SMC) { + if (do_smi) + smi_line = 1; + } } } @@ -164,8 +175,7 @@ acpi_reg_read_ali(int size, uint16_t addr, void *p) shift16 = (addr & 1) << 3; shift32 = (addr & 3) << 3; - switch(addr) - { + switch(addr) { case 0x10: case 0x11: case 0x12: case 0x13: /* PCNTRL - Processor Control Register (IO) */ ret = (dev->regs.pcntrl >> shift16) & 0xff; @@ -180,39 +190,33 @@ acpi_reg_read_ali(int size, uint16_t addr, void *p) break; case 0x18: case 0x19: /* GPE0_STS - General Purpose Event0 Status Register */ - ret = (dev->regs.gpsts >> shift16) & 0xff; - break; + ret = (dev->regs.gpsts >> shift16) & 0xff; + break; case 0x1a: case 0x1b: /* GPE0_EN - General Purpose Event0 Enable Register */ - ret = (dev->regs.gpen >> shift16) & 0xff; - break; + ret = (dev->regs.gpen >> shift16) & 0xff; + break; case 0x1d: case 0x1c: /* GPE1_STS - General Purpose Event1 Status Register */ - ret = (dev->regs.gpsts >> shift16) & 0xff; - break; + ret = (dev->regs.gpsts1 >> shift16) & 0xff; + break; case 0x1f: case 0x1e: /* GPE1_EN - General Purpose Event1 Enable Register */ - ret = (dev->regs.gpen1 >> shift16) & 0xff; - break; - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: + ret = (dev->regs.gpen1 >> shift16) & 0xff; + break; + case 0x20 ... 0x27: /* GPE1_CTL - General Purpose Event1 Control Register */ - ret = (dev->regs.gpcntrl >> shift32) & 0xff; - break; + ret = (dev->regs.gpcntrl >> shift32) & 0xff; + break; case 0x30: /* PM2_CNTRL - Power Management 2 Control Register( */ - ret = dev->regs.pmcntrl; - break; + ret = dev->regs.pmcntrl; + break; default: ret = acpi_reg_read_common_regs(size, addr, p); break; - } + } + #ifdef ENABLE_ACPI_LOG if (size != 1) acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); @@ -296,6 +300,7 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) return ret; } + static uint32_t acpi_reg_read_sis(int size, uint16_t addr, void *p) { @@ -703,44 +708,37 @@ acpi_reg_write_ali(int size, uint16_t addr, uint8_t val, void *p) break; case 0x18: case 0x19: /* GPE0_STS - General Purpose Event0 Status Register */ - dev->regs.gpsts &= ~((val << shift16) & 0x0d07); - break; + dev->regs.gpsts &= ~((val << shift16) & 0x0d07); + break; case 0x1a: case 0x1b: /* GPE0_EN - General Purpose Event0 Enable Register */ - dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0d07; - break; + dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0d07; + break; case 0x1d: case 0x1c: /* GPE1_STS - General Purpose Event1 Status Register */ - dev->regs.gpsts &= ~((val << shift16) & 0x0c01); - break; + dev->regs.gpsts1 &= ~((val << shift16) & 0x0c01); + break; case 0x1f: case 0x1e: /* GPE1_EN - General Purpose Event1 Enable Register */ - dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0c01; - break; - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: + dev->regs.gpen1 = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0c01; + break; + case 0x20 ... 0x27: /* GPE1_CTL - General Purpose Event1 Control Register */ - dev->regs.gpcntrl = ((dev->regs.gpcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00000001; - break; + dev->regs.gpcntrl = ((dev->regs.gpcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00000001; + break; case 0x30: /* PM2_CNTRL - Power Management 2 Control Register( */ - dev->regs.pmcntrl = val & 1; - break; + dev->regs.pmcntrl = val & 1; + break; default: acpi_reg_write_common_regs(size, addr, val, p); /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) - dev->regs.glbctl &= ~0x0002; + dev->regs.gpcntrl &= ~0x0002; else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { - dev->regs.glbsts |= 0x01; - if (dev->regs.glben & 0x02) - acpi_raise_smi(dev); + dev->regs.gpsts1 |= 0x01; + if (dev->regs.gpen1 & 0x01) + acpi_raise_smi(dev, 1); } } } @@ -816,7 +814,7 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { dev->regs.glbsts |= 0x01; if (dev->regs.glben & 0x02) - acpi_raise_smi(dev); + acpi_raise_smi(dev, 1); } break; } @@ -973,7 +971,7 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) dev->regs.smicmd = val & 0xff; dev->regs.glbsts |= 0x40; if (dev->regs.glben & 0x40) - acpi_raise_smi(dev); + acpi_raise_smi(dev, 1); } break; case 0x30: case 0x31: case 0x32: case 0x33: @@ -996,7 +994,7 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { dev->regs.glbsts |= 0x20; if (dev->regs.glben & 0x20) - acpi_raise_smi(dev); + acpi_raise_smi(dev, 1); } break; } @@ -1084,7 +1082,7 @@ acpi_reg_write_smc(int size, uint16_t addr, uint8_t val, void *p) else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { dev->regs.glbsts |= 0x01; if (dev->regs.glben & 0x01) - acpi_raise_smi(dev); + acpi_raise_smi(dev, 1); } } @@ -1476,6 +1474,13 @@ acpi_set_irq_line(acpi_t *dev, int irq_line) } +void +acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level) +{ + dev->mirq_is_level = mirq_is_level; +} + + void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default) { @@ -1491,6 +1496,20 @@ acpi_set_nvr(acpi_t *dev, nvr_t *nvr) } +uint8_t +acpi_ali_soft_smi_status_read(acpi_t *dev) +{ + return dev->regs.ali_soft_smi = 1; +} + + +void +acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi) +{ + dev->regs.ali_soft_smi = soft_smi; +} + + static void acpi_apm_out(uint16_t port, uint8_t val, void *p) { @@ -1500,15 +1519,25 @@ acpi_apm_out(uint16_t port, uint8_t val, void *p) port &= 0x0001; - if (port == 0x0000) { - dev->apm->cmd = val; - if (dev->apm->do_smi) { - if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) + if (dev->vendor == VEN_ALI) { + if (port == 0x0001) { + acpi_log("ALi SOFT SMI# status set (%i)\n", dev->apm->do_smi); + dev->apm->cmd = val; + // acpi_raise_smi(dev, dev->apm->do_smi); + if (dev->apm->do_smi) + smi_line = 1; + dev->regs.ali_soft_smi = 1; + } else if (port == 0x0003) + dev->apm->stat = val; + } else { + if (port == 0x0000) { + dev->apm->cmd = val; + if (dev->vendor == VEN_INTEL) dev->regs.glbsts |= 0x20; - acpi_raise_smi(dev); - } - } else - dev->apm->stat = val; + acpi_raise_smi(dev, dev->apm->do_smi); + } else + dev->apm->stat = val; + } } @@ -1520,10 +1549,17 @@ acpi_apm_in(uint16_t port, void *p) port &= 0x0001; - if (port == 0x0000) - ret = dev->apm->cmd; - else - ret = dev->apm->stat; + if (dev->vendor == VEN_ALI) { + if (port == 0x0001) + ret = dev->apm->cmd; + else if (port == 0x0003) + ret = dev->apm->stat; + } else { + if (port == 0x0000) + ret = dev->apm->cmd; + else + ret = dev->apm->stat; + } acpi_log("[%04X:%08X] APM read: %04X = %02X\n", CS, cpu_state.pc, port, ret); @@ -1616,8 +1652,14 @@ acpi_init(const device_t *info) dev->irq_line = 9; if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) { + if (dev->vendor == VEN_ALI) + dev->irq_mode = 2; dev->apm = device_add(&apm_pci_acpi_device); - io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + if (dev->vendor == VEN_ALI) { + acpi_log("Setting I/O handler at port B1\n"); + io_sethandler(0x00b1, 0x0003, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + } else + io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); } else if (dev->vendor == VEN_VIA) { dev->i2c = i2c_gpio_init("smbus_vt82c586b"); i2c_smbus = i2c_gpio_get_bus(dev->i2c); diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 76cf45db0..ab8f96e61 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,25 +13,18 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(chipset OBJECT 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 - umc_8886.c umc_8890.c umc_hb4.c +add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c ali1531.c ali1543.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 opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c - via_apollo.c via_pipc.c wd76c10.c - vl82c480.c) + via_apollo.c via_pipc.c vl82c480.c wd76c10.c) if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) endif() -if(M154X) - target_sources(chipset PRIVATE ali1531.c) - target_sources(chipset PRIVATE ali1543.c) -endif() - if(M6117) target_sources(chipset PRIVATE ali6117.c) endif() diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index c29d831fc..ce161ce7c 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -34,6 +34,7 @@ #include <86box/chipset.h> + typedef struct ali1531_t { uint8_t pci_conf[256]; @@ -41,201 +42,287 @@ typedef struct ali1531_t smram_t *smram; } ali1531_t; -void ali1531_shadow_recalc(int cur_reg, ali1531_t *dev) -{ - for (uint32_t i = 0; i < 8; i++) - mem_set_mem_state_both(0xc0000 + ((cur_reg & 1) << 17) + (i << 14), 0x4000, (((dev->pci_conf[0x4c + (cur_reg & 1)] >> i) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | (((dev->pci_conf[0x4e + (cur_reg & 1)] >> i) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); - flushmmucache_nopc(); +#ifdef ENABLE_ALI1531_LOG +int ali1531_do_log = ENABLE_ALI1531_LOG; +static void +ali1531_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1531_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } +#else +#define ali1531_log(fmt, ...) +#endif -void ali1531_smm_recalc(uint8_t smm_state, ali1531_t *dev) + +static void +ali1531_smram_recalc(uint8_t val, ali1531_t *dev) { - smram_disable_all(); - if (dev->pci_conf[0x48] & 1) - { - switch (smm_state) - { - case 0: - smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, 0, 1); - smram_map(1, 0xd0000, 0x10000, 1); - break; - case 1: - smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, 1, 1); - smram_map(1, 0xd0000, 0x10000, 1); - break; - case 2: - smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, 0, 1); - smram_map(1, 0xa0000, 0x20000, (dev->pci_conf[0x48] & 0x10) ? 2 : 1); - break; - case 3: - smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, 1, 1); - smram_map(1, 0xa0000, 0x20000, (dev->pci_conf[0x48] & 0x10) ? 2 : 1); - break; - case 4: - smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, 0, 1); - smram_map(1, 0x30000, 0x10000, 1); - break; - case 5: - smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, 1, 1); - smram_map(1, 0x30000, 0x10000, 1); - break; - } + if (val & 1) { + switch (val & 0x0c) { + case 0x00: + ali1531_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); + break; + case 0x04: + ali1531_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + break; + case 0x08: + ali1531_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + break; + } } flushmmucache_nopc(); } + +static void +ali1531_shadow_recalc(int cur_reg, ali1531_t *dev) +{ + int i, bit, r_reg, w_reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 16; i++) { + base = 0x000c0000 + (i << 14); + bit = i & 7; + r_reg = 0x4c + (i >> 3); + w_reg = 0x4e + (i >> 3); + + flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[r_reg] & (1 << bit)) + shadowbios |= 1; + if (dev->pci_conf[w_reg] & (1 << bit)) + shadowbios_write |= 1; + } + + ali1531_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + flushmmucache_nopc(); +} + + static void ali1531_write(int func, int addr, uint8_t val, void *priv) { ali1531_t *dev = (ali1531_t *)priv; - switch (addr) - { - case 0x05: - dev->pci_conf[addr] = val & 1; - break; + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; - case 0x07: - dev->pci_conf[addr] = val & 0xfe; - break; + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf8); + break; - case 0x0d: - dev->pci_conf[addr] = val & 0xf8; - break; + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; - case 0x40: - dev->pci_conf[addr] = val & 0xf1; - break; + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (dev->pci_conf[0x70] & 0x08) + dev->pci_conf[addr] = val; + break; - case 0x41: - dev->pci_conf[addr] = val & 0xdf; - break; + case 0x40: + dev->pci_conf[addr] = val & 0xf1; + break; - case 0x42: /* L2 Cache */ - dev->pci_conf[addr] = val & 0xf7; - cpu_cache_ext_enabled = !!(val & 1); - cpu_update_waitstates(); - break; + case 0x41: + dev->pci_conf[addr] = (val & 0xd6) | 0x08; + break; - case 0x43: /* L1 Cache */ - dev->pci_conf[addr] = val; - cpu_cache_int_enabled = !!(val & 1); - cpu_update_waitstates(); - break; + case 0x42: /* L2 Cache */ + dev->pci_conf[addr] = val & 0xf7; + cpu_cache_ext_enabled = !!(val & 1); + cpu_update_waitstates(); + break; - case 0x47: - dev->pci_conf[addr] = val & 0xfc; + case 0x43: /* L1 Cache */ + dev->pci_conf[addr] = val; + cpu_cache_int_enabled = !!(val & 1); + cpu_update_waitstates(); + break; - if (mem_size > 0xe00000) - mem_set_mem_state_both(0xe00000, 0x100000, !(val & 0x20) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; - if (mem_size > 0xf00000) - mem_set_mem_state_both(0xf00000, 0x100000, !(val & 0x10) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + case 0x46: + dev->pci_conf[addr] = val; + break; - mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - break; + case 0x47: + dev->pci_conf[addr] = val & 0xfc; - case 0x48: /* SMRAM */ - dev->pci_conf[addr] = val; - ali1531_smm_recalc((val >> 1) & 7, dev); - break; + if (mem_size > 0xe00000) + mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - case 0x49: - dev->pci_conf[addr] = val & 0x73; - break; + if (mem_size > 0xf00000) + mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - case 0x4c: /* Shadow RAM */ - case 0x4d: - case 0x4e: - case 0x4f: - dev->pci_conf[addr] = val; - ali1531_shadow_recalc(addr, dev); - break; + mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - case 0x57: /* H2PO */ - dev->pci_conf[addr] = val & 0x60; - if (!(val & 0x20)) - outb(0x92, 0x01); - break; + flushmmucache_nopc(); + break; - case 0x58: - dev->pci_conf[addr] = val & 0x83; - break; + case 0x48: /* SMRAM */ + dev->pci_conf[addr] = val; + ali1531_smram_recalc(val, dev); + break; - case 0x5b: - dev->pci_conf[addr] = val & 0x4f; - break; + case 0x49: + dev->pci_conf[addr] = val & 0x73; + break; - case 0x5d: - dev->pci_conf[addr] = val & 0x53; - break; + case 0x4a: + dev->pci_conf[addr] = val; + break; - case 0x5f: - dev->pci_conf[addr] = val & 0x7f; - break; + case 0x4c ... 0x4f: /* Shadow RAM */ + dev->pci_conf[addr] = val; + ali1531_shadow_recalc(val, dev); + break; - case 0x60: /* DRB's */ - case 0x61: + case 0x50: case 0x51: case 0x52: case 0x54: + case 0x55: case 0x56: + dev->pci_conf[addr] = val; + break; + + case 0x57: /* H2PO */ + dev->pci_conf[addr] = val & 0x60; + /* Find where the Shut-down Special cycle is initiated. */ + // if (!(val & 0x20)) + // outb(0x92, 0x01); + break; + + case 0x58: + dev->pci_conf[addr] = val & 0x86; + break; + + case 0x59: case 0x5a: + case 0x5c: + dev->pci_conf[addr] = val; + break; + + case 0x5b: + dev->pci_conf[addr] = val & 0x4f; + break; + + case 0x5d: + dev->pci_conf[addr] = val & 0x53; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x60: /* DRB's */ case 0x62: - case 0x63: case 0x64: - case 0x65: case 0x66: - case 0x67: case 0x68: - case 0x69: case 0x6a: - case 0x6b: case 0x6c: - case 0x6d: case 0x6e: + dev->pci_conf[addr] = val; + spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); + break; + case 0x61: + case 0x63: + case 0x65: + case 0x67: + case 0x69: + case 0x6b: + case 0x6d: case 0x6f: - dev->pci_conf[addr] = val; - spd_write_drbs(dev->pci_conf, 0x60, 0x6f, 1); - break; + dev->pci_conf[addr] = val; + break; - case 0x72: - dev->pci_conf[addr] = val & 0xf; - break; + case 0x70: case 0x71: + dev->pci_conf[addr] = val; + break; - case 0x74: - dev->pci_conf[addr] = val & 0x2b; - break; + case 0x72: + dev->pci_conf[addr] = val & 0x0f; + break; - case 0x80: - dev->pci_conf[addr] = val & 0x84; - break; + case 0x74: + dev->pci_conf[addr] = val & 0x2b; + break; - case 0x81: - dev->pci_conf[addr] = val & 0x81; - break; + case 0x76: case 0x77: + dev->pci_conf[addr] = val; + break; - case 0x83: - dev->pci_conf[addr] = val & 0x10; - break; + case 0x80: + dev->pci_conf[addr] = val & 0x84; + break; - default: - dev->pci_conf[addr] = val; - break; + case 0x81: + dev->pci_conf[addr] = val & 0x81; + break; + + case 0x83: + dev->pci_conf[addr] = val & 0x10; + break; } } + static uint8_t ali1531_read(int func, int addr, void *priv) { ali1531_t *dev = (ali1531_t *)priv; - return dev->pci_conf[addr]; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; } + static void ali1531_reset(void *priv) { ali1531_t *dev = (ali1531_t *)priv; + int i; /* Default Registers */ dev->pci_conf[0x00] = 0xb9; @@ -267,11 +354,20 @@ ali1531_reset(void *priv) ali1531_write(0, 0x42, 0x00, dev); ali1531_write(0, 0x43, 0x00, dev); + ali1531_write(0, 0x47, 0x00, dev); - ali1531_write(0, 0x60, 0x08, dev); - ali1531_write(0, 0x61, 0x40, dev); + ali1531_write(0, 0x48, 0x00, dev); + + for (i = 0; i < 4; i++) + ali1531_write(0, 0x4c + i, 0x00, dev); + + for (i = 0; i < 16; i += 2) { + ali1531_write(0, 0x60 + i, 0x08, dev); + ali1531_write(0, 0x61 + i, 0x40, dev); + } } + static void ali1531_close(void *priv) { @@ -281,6 +377,7 @@ ali1531_close(void *priv) free(dev); } + static void * ali1531_init(const device_t *info) { @@ -296,6 +393,7 @@ ali1531_init(const device_t *info) return dev; } + const device_t ali1531_device = { "ALi M1531 CPU-to-PCI Bridge", DEVICE_PCI, @@ -306,4 +404,5 @@ const device_t ali1531_device = { {NULL}, NULL, NULL, - NULL}; + NULL +}; diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 158d42ba4..4f0d3cbff 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -34,10 +34,12 @@ #include <86box/fdc.h> #include <86box/hdc_ide.h> #include <86box/hdc_ide_sff8038i.h> +#include <86box/keyboard.h> #include <86box/lpt.h> #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> +#include <86box/pic.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/smbus_piix4.h> @@ -47,6 +49,41 @@ #include <86box/chipset.h> + +typedef struct ali1543_t +{ + uint8_t pci_conf[256], pmu_conf[256], usb_conf[256], ide_conf[256], + sio_regs[256], device_regs[8][256], sio_index, in_configuration_mode, + pci_slot, ide_slot, usb_slot, pmu_slot, usb_dev_enable, ide_dev_enable, + pmu_dev_enable; + + apm_t * apm; + acpi_t * acpi; + ddma_t * ddma; + fdc_t * fdc_controller; + nvr_t * nvr; + port_92_t * port_92; + serial_t * uart[2]; + sff8038i_t * ide_controller[2]; + smbus_piix4_t * smbus; + usb_t * usb; + +} ali1543_t; + +/* + Notes: + - Power Managment isn't functioning properly + - IDE isn't functioning properly + - 1543C differences have to be examined + - Some Chipset functionality might be missing + - Device numbers and types might be incorrect + - Code quality is abysmal and needs lot's of cleanup. +*/ + +int ali1533_irq_routing[16] = { PCI_IRQ_DISABLED, 9, 3, 10, 4, 5, 7, 6, + 1, 11, PCI_IRQ_DISABLED, 12, PCI_IRQ_DISABLED, 14, PCI_IRQ_DISABLED, 15 }; + + #ifdef ENABLE_ALI1543_LOG int ali1543_do_log = ENABLE_ALI1543_LOG; static void @@ -65,216 +102,413 @@ ali1543_log(const char *fmt, ...) #define ali1543_log(fmt, ...) #endif -typedef struct ali1543_t + +static void +ali1533_ddma_handler(ali1543_t *dev) { - uint8_t pci_conf[256], pmu_conf[256], usb_conf[256], ide_conf[256], - sio_regs[256], device_regs[8][256], sio_index, in_configuration_mode, - pci_slot, ide_slot, usb_slot, pmu_slot; - - apm_t *apm; - acpi_t *acpi; - ddma_t *ddma; - fdc_t *fdc_controller; - nvr_t *nvr; - port_92_t *port_92; - serial_t *uart[2]; - sff8038i_t *ide_controller[2]; - smbus_piix4_t *smbus; - usb_t *usb; - -} ali1543_t; - -/* - - Notes: - - Power Managment isn't functioning properly - - IDE isn't functioning properly - - 1543C differences have to be examined - - Some Chipset functionality might be missing - - Device numbers and types might be incorrect - - Code quality is abysmal and needs lot's of cleanup. - -*/ - -int ali1533_irq_routing[15] = {9, 3, 0x0a, 4, 5, 7, 6, 1, 0x0b, 0, 0x0c, 0, 0x0e, 0, 0x0f}; - -void ali1533_ddma_handler(ali1543_t *dev) -{ - for (uint8_t i = 0; i < 8; i++) - { - if (i != 4) - ddma_update_io_mapping(dev->ddma, i & 7, dev->pci_conf[0x73] & 0xf, dev->pci_conf[0x73] & 0xf0, dev->pci_conf[0x45] & 2); - } + /* TODO: Find any documentation that actually explains the ALi southbridge DDMA mapping. */ } -void ali5229_ide_handler(ali1543_t *dev); + +static void ali5229_ide_handler(ali1543_t *dev); +static void ali5229_ide_irq_handler(ali1543_t *dev); + +static void ali5229_write(int func, int addr, uint8_t val, void *priv); + static void ali1533_write(int func, int addr, uint8_t val, void *priv) { ali1543_t *dev = (ali1543_t *)priv; + int irq; + ali1543_log("M1533: dev->pci_conf[%02x] = %02x\n", addr, val); - switch (addr) - { - case 0x04: - if (dev->pci_conf[0x5f] & 8) - dev->pci_conf[addr] = val; - break; - case 0x2c: /* Subsystem Vendor ID */ - case 0x2d: - case 0x2e: - case 0x2f: - if (dev->pci_conf[0x74] & 0x40) - dev->pci_conf[addr] = val; - break; + if (func > 0) + return; - case 0x40: - dev->pci_conf[addr] = val & 0x7f; - break; + switch (addr) { + case 0x04: /* Command Register */ + if (!(dev->pci_conf[0x5f] & 0x08)) + dev->pci_conf[0x04] = val; + break; + case 0x05: /* Command Register */ + if (!(dev->pci_conf[0x5f] & 0x08)) + dev->pci_conf[0x04] = val & 0x03; + break; - case 0x42: /* ISA Bus Speed */ - dev->pci_conf[addr] = val & 0xcf; - switch(val & 7) - { - case 0: - cpu_set_isa_speed(7159091); - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - cpu_set_isa_pci_div(val & 7); - break; - } + case 0x07: /* Status Byte */ + dev->pci_conf[addr] &= ~(val & 0x30); + break; - break; + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->pci_conf[0x74] & 0x40)) + dev->pci_conf[addr] = val; + break; - case 0x43: - dev->pci_conf[addr] = val; - if (val & 0x80) - port_92_add(dev->port_92); - else - port_92_remove(dev->port_92); - break; + case 0x40: + dev->pci_conf[addr] = val & 0x7f; + break; - case 0x44: /* Set IRQ Line for Primary IDE if it's on native mode */ - dev->pci_conf[addr] = 0xdf; - if (dev->ide_conf[0x09] & 1) - sff_set_irq_line(dev->ide_controller[0], ((val & 0x0f) == 0) ? ali1533_irq_routing[(val & 0x0f) - 1] : PCI_IRQ_DISABLED); - break; + case 0x41: + /* TODO: Bit 7 selects keyboard controller type: + 0 = AT, 1 = PS/2 */ + keyboard_at_set_mouse_scan((val & 0x40) ? 1 : 0); + dev->pci_conf[addr] = val & 0xbf; + break; - case 0x45: /* DDMA Enable */ - dev->pci_conf[addr] = 0xcf; - ali1533_ddma_handler(dev); - break; + case 0x42: /* ISA Bus Speed */ + dev->pci_conf[addr] = val & 0xcf; + switch (val & 7) { + case 0: + cpu_set_isa_speed(7159091); + break; + case 1: case 2: case 3: case 4: + case 5: case 6: + cpu_set_isa_pci_div((val & 7) + 1); + break; + } + break; - case 0x48: /* PCI IRQ Routing */ - case 0x49: - dev->pci_conf[addr] = val; - pci_set_irq_routing(((addr & 1) * 2) + 2, (((val >> 4) & 0x0f) == 0) ? ali1533_irq_routing[((val >> 4) & 0x0f) - 1] : PCI_IRQ_DISABLED); - pci_set_irq_routing(((addr & 1) * 2) + 1, ((val & 0x0f) == 0) ? ali1533_irq_routing[(val & 0x0f) - 1] : PCI_IRQ_DISABLED); - break; + case 0x43: + dev->pci_conf[addr] = val; + if (val & 0x80) + port_92_add(dev->port_92); + else + port_92_remove(dev->port_92); + break; - case 0x53: /* USB Enable */ - dev->pci_conf[addr] = val & 0xe7; - ohci_update_mem_mapping(dev->usb, 0x11, 0x12, 0x13, (dev->usb_conf[0x04] & 1) && (!(dev->pci_conf[0x53] & 0x40))); - break; + /* We're going to cheat a little bit here and use MIRQ's as a substitute for the ALi's INTAJ's, + as they work pretty much the same - specifically, we're going to use MIRQ2 and MIRQ3 for them, + as MIRQ0 and MIRQ1 map to the ALi's MBIRQ0 and MBIRQ1. */ + case 0x44: /* Set IRQ Line for Primary IDE if it's on native mode */ + dev->pci_conf[addr] = val & 0xdf; + soft_reset_pci = !!(val & 0x80); + sff_set_irq_level(dev->ide_controller[0], 0, !(val & 0x10)); + sff_set_irq_level(dev->ide_controller[1], 0, !(val & 0x10)); + ali1543_log("INTAJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ2, ali1533_irq_routing[val & 0x0f]); + break; - case 0x54: /* USB Control ? */ - dev->pci_conf[addr] = val & 0xdf; - break; + /* TODO: Implement a ROMCS# assertion bitmask for I/O ports. */ + case 0x45: /* DDMA Enable */ + dev->pci_conf[addr] = val & 0xcb; + ali1533_ddma_handler(dev); + break; - case 0x57: - dev->pci_conf[addr] = val & 0xc7; - break; + /* TODO: For 0x47, we need a way to obtain the memory state for an address + and toggle ROMCS#. */ + case 0x47: /* BIOS chip select control */ + dev->pci_conf[addr] = val; + break; - case 0x58: /* IDE Enable */ - dev->pci_conf[addr] = val & 0x7f; - ali5229_ide_handler(dev); - break; + /* PCI IRQ Routing */ + case 0x48: case 0x49: case 0x4a: case 0x4b: + dev->pci_conf[addr] = val; - case 0x59: - case 0x5a: - dev->pci_conf[addr] = val & 0x0e; - break; + pci_set_irq_routing(((addr & 0x03) << 1) + 2, ali1533_irq_routing[(val >> 4) & 0x0f]); + pci_set_irq_routing(((addr & 0x03) << 1) + 1, ali1533_irq_routing[val & 0x0f]); + break; - case 0x5b: - dev->pci_conf[addr] = val & 0x02; - break; + case 0x4c: /* PCI INT to ISA Level to Edge transfer */ + dev->pci_conf[addr] = val; - case 0x5c: - dev->pci_conf[addr] = val & 0x7f; - break; + for (irq = 1; irq < 9; irq++) + pci_set_irq_level(irq, !(val & (1 << (irq - 1)))); + break; - case 0x5d: - dev->pci_conf[addr] = val & 0x02; - break; + case 0x4d: /* MBIRQ0(SIRQI#), MBIRQ1(SIRQII#) Interrupt to ISA IRQ routing table */ + dev->pci_conf[addr] = val; - case 0x5e: - dev->pci_conf[addr] = val & 0xe0; - break; + ali1543_log("SIRQI = IRQ %i; SIRQII = IRQ %i\n", ali1533_irq_routing[(val >> 4) & 0x0f], ali1533_irq_routing[val & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[(val >> 4) & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + break; - case 0x5f: - dev->pci_conf[addr] = val; - acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - break; + /* I/O cycle posted-write first port definition */ + case 0x50: + dev->pci_conf[addr] = val; + break; + case 0x51: + dev->pci_conf[addr] = val & 0x8f; + break; - case 0x6d: - dev->pci_conf[addr] = val & 0xbf; - break; + /* I/O cycle posted-write second port definition */ + case 0x52: + dev->pci_conf[addr] = val; + break; + case 0x53: + dev->pci_conf[addr] = val & 0xcf; + /* This actually enables/disables the USB *device* rather than the interface itself. */ + dev->usb_dev_enable = !(val & 0x40); + break; - case 0x71: - case 0x72: - dev->pci_conf[addr] = val & 0xef; - break; + /* Hardware setting status bits, read-only (register 0x54) */ - case 0x73: /* DDMA Base Address */ - dev->pci_conf[addr] = val; - ali1533_ddma_handler(dev); - break; + /* Programmable chip select (pin PCSJ) address define */ + case 0x55: case 0x56: + dev->pci_conf[addr] = val; + break; + case 0x57: + dev->pci_conf[addr] = val & 0xc7; + break; - case 0x74: /* USB IRQ Routing */ - dev->pci_conf[addr] = val & 0xdf; - break; + /* IDE interface control + TODO: What is IDSEL address? */ + case 0x58: + dev->pci_conf[addr] = val & 0x7f; + ali1543_log("PCI58: %02X\n", val); + dev->ide_dev_enable = !!(val & 0x40); + switch (val & 0x30) { + case 0x00: + dev->ide_slot = 0x10; /* A27 = slot 16 */ + break; + case 0x10: + dev->ide_slot = 0x0f; /* A26 = slot 15 */ + break; + case 0x20: + dev->ide_slot = 0x0e; /* A25 = slot 14 */ + break; + case 0x30: + dev->ide_slot = 0x0d; /* A24 = slot 13 */ + break; + } + ali1543_log("IDE slot = %02X (A%0i)\n", dev->ide_slot, dev->ide_slot + 11 - 5); + ali5229_ide_irq_handler(dev); + break; - case 0x75: /* Set IRQ Line for Secondary IDE if it's on native mode */ - dev->pci_conf[addr] = val & 0x1f; - if (dev->ide_conf[0x09] & 8) - sff_set_irq_line(dev->ide_controller[1], ((val & 0x0f) == 0) ? ali1533_irq_routing[(val & 0x0f) - 1] : PCI_IRQ_DISABLED); - break; + /* General Purpose input multiplexed pin(GPI) select */ + case 0x59: + dev->pci_conf[addr] = val & 0x0e; + break; - case 0x76: /* PMU IRQ Routing */ - dev->pci_conf[addr] = val & 0x1f; - acpi_set_irq_line(dev->acpi, val & 0x0f); - break; + /* General Purpose output multiplexed pin(GPO) select low */ + case 0x5a: + dev->pci_conf[addr] = val & 0x0f; + break; + /* General Purpose output multiplexed pin(GPO) select high */ + case 0x5b: + dev->pci_conf[addr] = val & 0x02; + break; - case 0x77: /* SMBus IRQ Routing */ - dev->pci_conf[addr] = val & 0x1f; - break; + case 0x5c: + dev->pci_conf[addr] = val & 0x7f; + break; + case 0x5d: + dev->pci_conf[addr] = val & 0x02; + break; - default: - dev->pci_conf[addr] = val; - break; + case 0x5e: + dev->pci_conf[addr] = val & 0xe0; + break; + + case 0x5f: + dev->pci_conf[addr] = val; + dev->pmu_dev_enable = !(val & 0x04); + break; + + case 0x6c: /* Deleted - no idea what it used to do */ + dev->pci_conf[addr] = val; + break; + + case 0x6d: + dev->pci_conf[addr] = val & 0xbf; + break; + + case 0x6e: case 0x70: + dev->pci_conf[addr] = val; + break; + + case 0x71: + dev->pci_conf[addr] = val & 0xef; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xef; + switch (val & 0x0c) { + case 0x00: + dev->pmu_slot = 0x11; /* A28 = slot 17 */ + break; + case 0x04: + dev->pmu_slot = 0x12; /* A29 = slot 18 */ + break; + case 0x08: + dev->pmu_slot = 0x03; /* A14 = slot 03 */ + break; + case 0x0c: + dev->pmu_slot = 0x04; /* A15 = slot 04 */ + break; + } + ali1543_log("PMU slot = %02X (A%0i)\n", dev->pmu_slot, dev->pmu_slot + 11 - 5); + switch (val & 0x03) { + case 0x00: + dev->usb_slot = 0x14; /* A31 = slot 20 */ + break; + case 0x01: + dev->usb_slot = 0x13; /* A30 = slot 19 */ + break; + case 0x02: + dev->usb_slot = 0x02; /* A13 = slot 02 */ + break; + case 0x03: + dev->usb_slot = 0x01; /* A12 = slot 01 */ + break; + } + ali1543_log("USB slot = %02X (A%0i)\n", dev->usb_slot, dev->usb_slot + 11 - 5); + break; + + case 0x73: /* DDMA Base Address */ + dev->pci_conf[addr] = val; + ali1533_ddma_handler(dev); + break; + + case 0x74: /* USB IRQ Routing - we cheat and use MIRQ4 */ + dev->pci_conf[addr] = val & 0xdf; + /* TODO: MIRQ level/edge control - if bit 4 = 1, it's level */ + pci_set_mirq_routing(PCI_MIRQ4, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x75: /* Set IRQ Line for Secondary IDE if it's on native mode */ + dev->pci_conf[addr] = val & 0x1f; + sff_set_irq_level(dev->ide_controller[0], 1, !(val & 0x10)); + sff_set_irq_level(dev->ide_controller[1], 1, !(val & 0x10)); + ali1543_log("INTBJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ3, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x76: /* PMU IRQ Routing - we cheat and use MIRQ5 */ + dev->pci_conf[addr] = val & 0x1f; + acpi_set_mirq_is_level(dev->acpi, !!(val & 0x10)); + pci_set_mirq_routing(PCI_MIRQ5, ali1533_irq_routing[val & 0x0f]); + /* TODO: Tell ACPI to use MIRQ5 */ + break; + + case 0x77: /* SMBus IRQ Routing - we cheat and use MIRQ6 */ + dev->pci_conf[addr] = val & 0x1f; + pci_set_mirq_routing(PCI_MIRQ6, ali1533_irq_routing[val & 0x0f]); + break; } } + static uint8_t ali1533_read(int func, int addr, void *priv) { ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; - if (((dev->pci_conf[0x42] & 0x80) && (addr >= 0x40)) || ((dev->pci_conf[0x5f] & 8) && (addr == 4))) - return 0; - else - return dev->pci_conf[addr]; + if (func == 0) { + if (((dev->pci_conf[0x42] & 0x80) && (addr >= 0x40)) || ((dev->pci_conf[0x5f] & 8) && (addr == 4))) + ret = 0x00; + else { + ret = dev->pci_conf[addr]; + if (addr == 0x41) + ret |= (keyboard_at_get_mouse_scan() << 2); + else if (addr == 0x58) + ret = (ret & 0xbf) | (dev->ide_dev_enable ? 0x40 : 0x00); + } + } + + return ret; } -void ali5229_ide_handler(ali1543_t *dev) + +static void +ali5229_ide_irq_handler(ali1543_t *dev) { + int ctl = 0, ch = 0; + int bit = 0; + + if (dev->ide_conf[0x52] & 0x10) { + ctl ^= 1; + ch ^= 1; + bit ^= 5; + } + + if (dev->ide_conf[0x09] & (1 ^ bit)) { + /* Primary IDE is native. */ + ali1543_log("Primary IDE IRQ mode: Native, Native\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 4); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 4); + } else { + /* Primary IDE is legacy. */ + switch (dev->pci_conf[0x58] & 0x03) { + case 0x00: + /* SIRQI, SIRQII */ + ali1543_log("Primary IDE IRQ mode: SIRQI, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 2); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x01: + /* IRQ14, IRQ15 */ + ali1543_log("Primary IDE IRQ mode: IRQ14, IRQ15\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 0); + break; + case 0x02: + /* IRQ14, SIRQII */ + ali1543_log("Primary IDE IRQ mode: IRQ14, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x03: + /* IRQ14, SIRQI */ + ali1543_log("Primary IDE IRQ mode: IRQ14, SIRQI\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 2); + break; + } + } + + ctl ^= 1; + + if (dev->ide_conf[0x09] & (4 ^ bit)) { + /* Secondary IDE is native. */ + ali1543_log("Secondary IDE IRQ mode: Native, Native\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 4); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 4); + } else { + /* Secondary IDE is legacy. */ + switch (dev->pci_conf[0x58] & 0x03) { + case 0x00: + /* SIRQI, SIRQII */ + ali1543_log("Secondary IDE IRQ mode: SIRQI, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 2); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x01: + /* IRQ14, IRQ15 */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, IRQ15\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 0); + break; + case 0x02: + /* IRQ14, SIRQII */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x03: + /* IRQ14, SIRQI */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, SIRQI\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 2); + break; + } + } +} + + +static void +ali5229_ide_handler(ali1543_t *dev) +{ + uint32_t ch = 0; + uint16_t native_base_pri_addr = (dev->ide_conf[0x11] | dev->ide_conf[0x10] << 8); uint16_t native_side_pri_addr = (dev->ide_conf[0x15] | dev->ide_conf[0x14] << 8); uint16_t native_base_sec_addr = (dev->ide_conf[0x19] | dev->ide_conf[0x18] << 8); @@ -288,505 +522,71 @@ void ali5229_ide_handler(ali1543_t *dev) uint16_t current_pri_base, current_pri_side, current_sec_base, current_sec_side; /* Primary Channel Programming */ - if (!(dev->ide_conf[0x52] & 0x10)) - { - current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_pri_addr : native_base_pri_addr; - current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_pri_addr : native_side_pri_addr; - } - else - { - current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_sec_addr : native_base_sec_addr; - current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_sec_addr : native_side_sec_addr; + if (dev->ide_conf[0x52] & 0x10) { + current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_sec_addr : native_base_sec_addr; + current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_sec_addr : native_side_sec_addr; + } else { + current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_pri_addr : native_base_pri_addr; + current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_pri_addr : native_side_pri_addr; } /* Secondary Channel Programming */ - if (!(dev->ide_conf[0x52] & 0x10)) - { - current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_sec_addr : native_base_sec_addr; - current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_sec_addr : native_side_sec_addr; - } - else - { - current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_pri_addr : native_base_pri_addr; - current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_pri_addr : native_side_pri_addr; + if (dev->ide_conf[0x52] & 0x10) { + current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_pri_addr : native_base_pri_addr; + current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_pri_addr : native_side_pri_addr; + } else { + current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_sec_addr : native_base_sec_addr; + current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_sec_addr : native_side_sec_addr; } - /* Both channels use one port */ - if (dev->ide_conf[0x52] & 0x40) - { - current_pri_base = current_sec_base; - current_pri_side = current_sec_side; - } - - if (dev->ide_conf[0x52] & 0x20) - { - current_sec_base = current_pri_base; - current_sec_side = current_pri_side; - } + if (dev->ide_conf[0x52] & 0x10) + ch ^= 8; + ali1543_log("ali5229_ide_handler(): Disabling primary IDE...\n"); ide_pri_disable(); + ali1543_log("ali5229_ide_handler(): Disabling secondary IDE...\n"); ide_sec_disable(); - if (dev->pci_conf[0x58] & 0x40) - { - sff_set_irq_pin(dev->ide_controller[0], dev->ide_conf[0x3d] & 4); - sff_set_irq_pin(dev->ide_controller[1], dev->ide_conf[0x3d] & 4); + if (dev->ide_conf[0x04] & 0x01) { + /* Primary Channel Setup */ + if (dev->ide_conf[0x09] & 0x20) { + ali1543_log("ali5229_ide_handler(): Primary IDE base now %04X...\n", current_pri_base); + ide_set_base(0, current_pri_base); + ali1543_log("ali5229_ide_handler(): Primary IDE side now %04X...\n", current_pri_side); + ide_set_side(0, current_pri_side); - /* Primary Channel Setup */ - if (dev->ide_conf[0x09] & 0x10) - { - ide_pri_enable(); - if (!(dev->ide_conf[0x09] & 1)) - sff_set_irq_line(dev->ide_controller[0], (dev->ide_conf[0x3c] != 0) ? ali1533_irq_routing[(dev->ide_conf[0x3c] & 0x0f) - 1] : PCI_IRQ_DISABLED); + ali1543_log("ali5229_ide_handler(): Enabling primary IDE...\n"); + ide_pri_enable(); - ide_set_base(0, current_pri_base); - ide_set_side(0, current_pri_side); + sff_bus_master_handler(dev->ide_controller[0], dev->ide_conf[0x04] & 0x01, ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + (0 ^ ch)); + ali1543_log("M5229 PRI: BASE %04x SIDE %04x\n", current_pri_base, current_pri_side); + } - sff_bus_master_handler(dev->ide_controller[0], dev->ide_conf[0x09] & 0x80, (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); - ali1543_log("M5229 PRI: BASE %04x SIDE %04x\n", current_pri_base, current_pri_side); - } + /* Secondary Channel Setup */ + if (dev->ide_conf[0x09] & 0x10) { + ali1543_log("ali5229_ide_handler(): Secondary IDE base now %04X...\n", current_sec_base); + ide_set_base(1, current_sec_base); + ali1543_log("ali5229_ide_handler(): Secondary IDE side now %04X...\n", current_sec_side); + ide_set_side(1, current_sec_side); - /* Secondary Channel Setup */ - if (dev->ide_conf[0x09] & 8) - { - ide_sec_enable(); - if (!(dev->ide_conf[0x09] & 4)) - sff_set_irq_line(dev->ide_controller[1], (dev->ide_conf[0x3c] != 0) ? ali1533_irq_routing[(dev->ide_conf[0x3c] & 0x0f) - 1] : PCI_IRQ_DISABLED); + ali1543_log("ali5229_ide_handler(): Enabling secondary IDE...\n"); + ide_sec_enable(); - ide_set_base(1, current_sec_base); - ide_set_side(1, current_sec_side); - - sff_bus_master_handler(dev->ide_controller[1], dev->ide_conf[0x09] & 0x80, ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); - ali1543_log("M5229 SEC: BASE %04x SIDE %04x\n", current_sec_base, current_sec_side); - } + sff_bus_master_handler(dev->ide_controller[1], dev->ide_conf[0x04] & 0x01, (((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8))) + (8 ^ ch)); + ali1543_log("M5229 SEC: BASE %04x SIDE %04x\n", current_sec_base, current_sec_side); + } + } else { + sff_bus_master_handler(dev->ide_controller[0], dev->ide_conf[0x04] & 0x01, (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); + sff_bus_master_handler(dev->ide_controller[1], dev->ide_conf[0x04] & 0x01, ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); } } + static void -ali5229_write(int func, int addr, uint8_t val, void *priv) +ali5229_chip_reset(ali1543_t *dev) { - ali1543_t *dev = (ali1543_t *)priv; - ali1543_log("M5229: dev->ide_conf[%02x] = %02x\n", addr, val); - - switch (addr) - { - case 0x09: /* Control */ - if (dev->ide_conf[0x4d] & 0x80) - dev->ide_conf[addr] |= val & 0x8f; - else - dev->ide_conf[addr] = val; - ali5229_ide_handler(dev); - break; - - case 0x10: /* Primary Base Address */ - case 0x11: - case 0x12: - case 0x13: - case 0x14: - - case 0x18: /* Secondary Base Address */ - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - - case 0x20: /* Bus Mastering Base Address */ - case 0x21: - case 0x22: - case 0x23: - dev->ide_conf[addr] = val; - ali5229_ide_handler(dev); - break; - - /* The machines don't touch anything beyond that point so we avoid any programming */ - - case 0x2c: /* Subsystem Vendor */ - case 0x2d: - case 0x2e: - case 0x2f: - if (dev->ide_conf[0x53] & 0x80) - dev->ide_conf[addr] = val; - break; - - case 0x4d: - dev->ide_conf[addr] = val & 0x80; - break; - - case 0x4f: - dev->ide_conf[addr] = val & 0x3f; - break; - - case 0x50: /* Configuration */ - dev->ide_conf[addr] = val & 0x2b; - break; - - case 0x51: - dev->ide_conf[addr] = val & 0xf7; - break; - - case 0x53: /* Subsystem Vendor ID */ - dev->ide_conf[addr] = val & 0x8b; - break; - - case 0x58: - dev->ide_conf[addr] = val & 3; - break; - - case 0x59: - case 0x5a: - case 0x5b: - dev->ide_conf[addr] = val & 0x7f; - break; - - case 0x5c: - dev->ide_conf[addr] = val & 3; - break; - - case 0x5d: - case 0x5e: - case 0x5f: - dev->ide_conf[addr] = val & 0x7f; - break; - - default: - dev->ide_conf[addr] = val; - break; - } -} - -static uint8_t -ali5229_read(int func, int addr, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - return dev->ide_conf[addr]; -} - -static void -ali5237_write(int func, int addr, uint8_t val, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - ali1543_log("M5237: dev->usb_conf[%02x] = %02x\n", addr, val); - switch (addr) - { - case 0x04: /* USB Enable */ - dev->usb_conf[addr] = val; - ohci_update_mem_mapping(dev->usb, 0x10, 0x11, 0x12, (dev->usb_conf[0x04] & 1) && (!(dev->pci_conf[0x53] & 0x40))); - break; - - case 0x05: - dev->usb_conf[addr] = 0x03; - break; - - case 0x06: - dev->usb_conf[addr] = 0xc0; - break; - - case 0x11: - case 0x12: - case 0x13: /* USB Base I/O */ - dev->usb_conf[addr] = val; - ohci_update_mem_mapping(dev->usb, 0x11, 0x12, 0x13, (dev->usb_conf[0x04] & 1) && (!(dev->pci_conf[0x53] & 0x40))); - break; - - case 0x42: - dev->usb_conf[addr] = 0x10; - break; - - default: - dev->usb_conf[addr] = val; - break; - } -} - -static uint8_t -ali5237_read(int func, int addr, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - return dev->usb_conf[addr]; -} - -static void -ali7101_write(int func, int addr, uint8_t val, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - ali1543_log("M7101: dev->pmu_conf[%02x] = %02x\n", addr, val); - - switch (addr) - { - case 0x04: /* Enable PMU */ - dev->pmu_conf[addr] = val & 0x1f; - acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - break; - - case 0x07: - dev->pmu_conf[addr] = val & 0xfe; - break; - - case 0x10: /* PMU Base I/O */ - case 0x11: - if (addr == 0x10) - dev->pmu_conf[addr] = (val & 0xe0) | 1; - else if (addr == 0x11) - dev->pmu_conf[addr] = val; - - acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - break; - - case 0x14: /* SMBus Base I/O */ - case 0x15: - dev->pmu_conf[addr] = val; - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - break; - - case 0x2c: /* Subsystem Vendor ID */ - case 0x2d: - case 0x2e: - case 0x2f: - if (dev->pmu_conf[0xd8] & 0x10) - dev->pmu_conf[addr] = val; - - case 0x40: - dev->pmu_conf[addr] = val & 0x1f; - break; - - case 0x41: - dev->pmu_conf[addr] = val & 0x10; - break; - - case 0x45: - dev->pmu_conf[addr] = val & 0x9f; - break; - - case 0x46: - dev->pmu_conf[addr] = val & 0x18; - break; - - case 0x48: - dev->pmu_conf[addr] = val & 0x9f; - break; - - case 0x49: - dev->pmu_conf[addr] = val & 0x38; - break; - - case 0x4c: - dev->pmu_conf[addr] = val & 5; - break; - - case 0x4d: - dev->pmu_conf[addr] = val & 1; - break; - - case 0x4e: - dev->pmu_conf[addr] = val & 5; - break; - - case 0x4f: - dev->pmu_conf[addr] = val & 1; - break; - - case 0x55: /* APM Timer */ - dev->pmu_conf[addr] = val & 0x7f; - break; - - case 0x59: - dev->pmu_conf[addr] = val & 0x1f; - break; - - case 0x5b: /* ACPI/SMB Base I/O Control */ - dev->pmu_conf[addr] = val & 0x7f; - break; - - case 0x61: - dev->pmu_conf[addr] = val & 0x13; - break; - - case 0x62: - dev->pmu_conf[addr] = val & 0xf1; - break; - - case 0x63: - dev->pmu_conf[addr] = val & 3; - break; - - case 0x65: - dev->pmu_conf[addr] = val & 0x1f; - break; - - case 0x68: - dev->pmu_conf[addr] = val & 7; - break; - - case 0x6e: - dev->pmu_conf[addr] = val & 0xef; - break; - - case 0x6f: - dev->pmu_conf[addr] = val & 7; - break; - - /* Continue Further Later */ - case 0xc0: /* GPO Registers */ - case 0xc1: - case 0xc2: - case 0xc3: - dev->pmu_conf[addr] = val; - acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2], dev->pmu_conf[0xc3]); - break; - - case 0xe0: - dev->pmu_conf[addr] = val; - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); - break; - - default: - dev->pmu_conf[addr] = val; - break; - } -} - -static uint8_t -ali7101_read(int func, int addr, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - return dev->pmu_conf[addr]; -} - -void ali1533_sio_fdc_handler(ali1543_t *dev) -{ - fdc_remove(dev->fdc_controller); - if (dev->device_regs[0][0x30] & 1) - { - fdc_set_base(dev->fdc_controller, dev->device_regs[0][0x61] | (dev->device_regs[0][0x60] << 8)); - fdc_set_irq(dev->fdc_controller, dev->device_regs[0][0x70] & 0xf); - fdc_set_dma_ch(dev->fdc_controller, dev->device_regs[0][0x74] & 0x07); - ali1543_log("M1543-SIO FDC: ADDR %04x IRQ %02x DMA %02x\n", dev->device_regs[0][0x61] | (dev->device_regs[0][0x60] << 8), dev->device_regs[0][0x70] & 0xf, dev->device_regs[0][0x74] & 0x07); - } -} - -void ali1533_sio_uart_handler(int num, ali1543_t *dev) -{ - serial_remove(dev->uart[num]); - if (dev->device_regs[num + 4][0x30] & 1) - { - serial_setup(dev->uart[num], dev->device_regs[num + 4][0x61] | (dev->device_regs[num + 4][0x60] << 8), dev->device_regs[num + 4][0x70] & 0xf); - ali1543_log("M1543-SIO UART%d: ADDR %04x IRQ %02x\n", num, dev->device_regs[num + 4][0x61] | (dev->device_regs[num + 4][0x60] << 8), dev->device_regs[num + 4][0x70] & 0xf); - } -} - -void ali1533_sio_lpt_handler(ali1543_t *dev) -{ - lpt1_remove(); - if (dev->device_regs[3][0x30] & 1) - { - lpt1_init(dev->device_regs[3][0x61] | (dev->device_regs[3][0x60] << 8)); - lpt1_irq(dev->device_regs[3][0x70] & 0xf); - ali1543_log("M1543-SIO LPT: ADDR %04x IRQ %02x\n", dev->device_regs[3][0x61] | (dev->device_regs[3][0x60] << 8), dev->device_regs[3][0x70] & 0xf); - } -} - -void ali1533_sio_ldn(uint16_t ldn, ali1543_t *dev) -{ - /* We don't include all LDN's */ - switch (ldn) - { - case 0: /* FDC */ - ali1533_sio_fdc_handler(dev); - break; - case 3: /* LPT */ - ali1533_sio_lpt_handler(dev); - break; - case 4: /* UART */ - case 5: - ali1533_sio_uart_handler(ldn - 4, dev); - break; - } -} - -static void -ali1533_sio_write(uint16_t addr, uint8_t val, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - - switch (addr) - { - case 0x3f0: - dev->sio_index = val; - if (dev->sio_index == 0x51) - { - dev->in_configuration_mode = 1; - } - else if (dev->sio_index == 0xbb) - dev->in_configuration_mode = 0; - break; - - case 0x3f1: - if (dev->in_configuration_mode) - { - switch (dev->sio_index) - { - case 0x07: - dev->sio_regs[dev->sio_index] = val & 0x7; - break; - - case 0x22: - dev->sio_regs[dev->sio_index] = val & 0x39; - break; - - case 0x23: - dev->sio_regs[dev->sio_index] = val & 0x38; - break; - - default: - if ((dev->sio_index < 0x30) || (dev->sio_index == 0x51) || (dev->sio_index == 0xbb)) - dev->sio_regs[dev->sio_index] = val; - else if (dev->sio_regs[0x07] <= 7) - dev->device_regs[dev->sio_regs[0x07]][dev->sio_index] = val; - break; - } - } - break; - } - - if ((!dev->in_configuration_mode) && (dev->sio_regs[0x07] <= 7) && (addr == 0x03f0)) - { - ali1533_sio_ldn(dev->sio_regs[0x07], dev); - } -} - -static uint8_t -ali1533_sio_read(uint16_t addr, void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - if (dev->sio_index >= 0x30) - return dev->device_regs[dev->sio_regs[0x07]][dev->sio_index]; - else - return dev->sio_regs[dev->sio_index]; -} - -static void -ali1543_reset(void *priv) -{ - ali1543_t *dev = (ali1543_t *)priv; - - /* M1533 */ - dev->pci_conf[0x00] = 0xb9; - dev->pci_conf[0x01] = 0x10; - dev->pci_conf[0x02] = 0x33; - dev->pci_conf[0x03] = 0x15; - dev->pci_conf[0x04] = 0x0f; - dev->pci_conf[0x08] = 0xb4; - dev->pci_conf[0x0a] = 0x01; - dev->pci_conf[0x0b] = 0x06; - - ali1533_write(0, 0x48, 0x00, dev); // Disables all IRQ's - ali1533_write(0, 0x44, 0x00, dev); - ali1533_write(0, 0x74, 0x00, dev); - ali1533_write(0, 0x75, 0x00, dev); - ali1533_write(0, 0x76, 0x00, dev); - /* M5229 */ + memset(dev->ide_conf, 0x00, sizeof(dev->pmu_conf)); dev->ide_conf[0x00] = 0xb9; dev->ide_conf[0x01] = 0x10; dev->ide_conf[0x02] = 0x29; @@ -794,7 +594,6 @@ ali1543_reset(void *priv) dev->ide_conf[0x06] = 0x80; dev->ide_conf[0x07] = 0x02; dev->ide_conf[0x08] = 0x20; - dev->ide_conf[0x09] = 0xfa; dev->ide_conf[0x0a] = 0x01; dev->ide_conf[0x0b] = 0x01; dev->ide_conf[0x10] = 0xf1; @@ -806,10 +605,11 @@ ali1543_reset(void *priv) dev->ide_conf[0x1a] = 0x75; dev->ide_conf[0x1b] = 0x03; dev->ide_conf[0x20] = 0x01; - dev->ide_conf[0x23] = 0xf0; + dev->ide_conf[0x21] = 0xf0; dev->ide_conf[0x3d] = 0x01; - dev->ide_conf[0x3c] = 0x02; - dev->ide_conf[0x3d] = 0x03; + dev->ide_conf[0x3e] = 0x02; + dev->ide_conf[0x3f] = 0x04; + dev->ide_conf[0x53] = 0x03; dev->ide_conf[0x54] = 0x55; dev->ide_conf[0x55] = 0x55; dev->ide_conf[0x63] = 0x01; @@ -817,13 +617,772 @@ ali1543_reset(void *priv) dev->ide_conf[0x67] = 0x01; dev->ide_conf[0x78] = 0x21; + ali5229_write(0, 0x04, 0x01, dev); + ali5229_write(0, 0x10, 0xf1, dev); + ali5229_write(0, 0x11, 0x01, dev); + ali5229_write(0, 0x14, 0xf5, dev); + ali5229_write(0, 0x15, 0x03, dev); + ali5229_write(0, 0x18, 0x71, dev); + ali5229_write(0, 0x19, 0x01, dev); + ali5229_write(0, 0x1a, 0x75, dev); + ali5229_write(0, 0x1b, 0x03, dev); + ali5229_write(0, 0x20, 0x01, dev); + ali5229_write(0, 0x21, 0xf0, dev); + ali5229_write(0, 0x4d, 0x00, dev); + dev->ide_conf[0x09] = 0xfa; + ali5229_write(0, 0x09, 0xfa, dev); + ali5229_write(0, 0x52, 0x00, dev); + + ali5229_write(0, 0x50, 0x00, dev); + sff_set_slot(dev->ide_controller[0], dev->ide_slot); sff_set_slot(dev->ide_controller[1], dev->ide_slot); sff_bus_master_reset(dev->ide_controller[0], (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); sff_bus_master_reset(dev->ide_controller[1], ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); ali5229_ide_handler(dev); +} + + +static void +ali5229_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M5229: dev->ide_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->ide_dev_enable) + return; + + switch (addr) { + case 0x04: /* COM - Command Register */ + ali1543_log("IDE04: %02X\n", val); + dev->ide_conf[addr] = val & 0x45; + ali5229_ide_handler(dev); + break; + + case 0x05: + dev->ide_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->ide_conf[addr] &= ~(val & 0xf1); + break; + + case 0x09: /* Control */ + ali1543_log("IDE09: %02X\n", val); +#ifdef M1543_C + val &= ~(dev->ide_conf[0x43]); + val |= (dev->ide_conf[addr] & dev->ide_conf[0x43]); +#endif + if (dev->ide_conf[0x4d] & 0x80) + dev->ide_conf[addr] = (dev->ide_conf[addr] & 0xfa) | (val & 0x05); + else + dev->ide_conf[addr] = (dev->ide_conf[addr] & 0x8a) | (val & 0x75); + ali5229_ide_handler(dev); + ali5229_ide_irq_handler(dev); + break; + + /* Primary Base Address */ + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: + + /* Secondary Base Address */ + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: + + /* Bus Mastering Base Address */ + case 0x20: case 0x21: case 0x22: case 0x23: + dev->ide_conf[addr] = val; + ali5229_ide_handler(dev); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->ide_conf[0x53] & 0x80)) + dev->ide_conf[addr] = val; + break; + + case 0x3c: /* Interrupt Line */ + case 0x3d: /* Interrupt Pin */ + dev->ide_conf[addr] = val; + break; + + /* The machines don't touch anything beyond that point so we avoid any programming */ +#ifdef M1543_C + case 0x43: + dev->ide_conf[addr] = val & 0x7f; + break; +#endif + + case 0x4d: + dev->ide_conf[addr] = val & 0x80; + break; + + case 0x4f: + dev->ide_conf[addr] = val & 0x3f; + break; + + case 0x50: /* Configuration */ + ali1543_log("IDE50: %02X\n", val); + dev->ide_conf[addr] = val & 0x2b; + dev->ide_dev_enable = !!(val & 0x01); + break; + + case 0x51: + dev->ide_conf[addr] = val & 0xf7; + if (val & 0x80) + ali5229_chip_reset(dev); + else if (val & 0x40) { + sff_bus_master_reset(dev->ide_controller[0], (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); + sff_bus_master_reset(dev->ide_controller[1], ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); + } + break; + + case 0x52: /* FCS - Flexible Channel Setting Register */ + dev->ide_conf[addr] = val; + ali5229_ide_handler(dev); + ali5229_ide_irq_handler(dev); + break; + + case 0x53: /* Subsystem Vendor ID */ + dev->ide_conf[addr] = val & 0x8b; + break; + + case 0x54: /* FIFO threshold of primary channel drive 0 and drive 1 */ + case 0x55: /* FIFO threshold of secondary channel drive 0 and drive 1 */ + case 0x56: /* Ultra DMA /33 setting for Primary drive 0 and drive 1 */ + case 0x57: /* Ultra DMA /33 setting for Secondary drive 0 and drive 1 */ + case 0x78: /* IDE clock's frequency (default value is 33 = 21H) */ + dev->ide_conf[addr] = val; + break; + + case 0x58: + dev->ide_conf[addr] = val & 3; + break; + + case 0x59: case 0x5a: + case 0x5b: + dev->ide_conf[addr] = val & 0x7f; + break; + + case 0x5c: + dev->ide_conf[addr] = val & 3; + break; + + case 0x5d: case 0x5e: + case 0x5f: + dev->ide_conf[addr] = val & 0x7f; + break; + } +} + + +static uint8_t +ali5229_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->ide_dev_enable && (func == 0)) { + ret = dev->ide_conf[addr]; + if ((addr == 0x09) && !(dev->ide_conf[0x50] & 0x02)) + ret &= 0x0f; + else if (addr == 0x50) + ret = (ret & 0xfe) | (dev->ide_dev_enable ? 0x01 : 0x00); + else if (addr == 0x75) + ret = ide_read_ali_75(); + else if (addr == 0x76) + ret = ide_read_ali_76(); + } + + return ret; +} + + +static void +ali5237_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M5237: dev->usb_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->usb_dev_enable) + return; + + switch (addr) { + case 0x04: /* USB Enable */ + dev->usb_conf[addr] = val & 0x5f; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + + case 0x05: + dev->usb_conf[addr] = 0x01; + break; + + case 0x07: + dev->usb_conf[addr] &= ~(val & 0xc9); + break; + + case 0x0c: /* Cache Line Size */ + case 0x0d: /* Latency Timer */ + case 0x3c: /* Interrupt Line Register */ + case 0x40 ... 0x43: /* Test Mode Register */ + dev->usb_conf[addr] = val; + break; + + /* USB Base I/O */ + case 0x11: + dev->usb_conf[addr] = val & 0xf0; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + case 0x12: case 0x13: + dev->usb_conf[addr] = val; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->usb_conf[0x42] & 0x10)) + dev->usb_conf[addr] = val; + break; + } +} + + +static uint8_t +ali5237_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->usb_dev_enable && (func == 0)) + ret = dev->usb_conf[addr]; + + return ret; +} + + +static void +ali7101_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M7101: dev->pmu_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->pmu_dev_enable) + return; + + if ((dev->pmu_conf[0xc9] & 0x01) && (addr >= 0x40) && (addr != 0xc9)) + return; + + switch (addr) { + case 0x04: /* Enable PMU */ + ali1543_log("PMU04: %02X\n", val); + dev->pmu_conf[addr] = val & 0x01; + acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); + smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + break; + + /* PMU Base I/O */ + case 0x10: case 0x11: + if (!(dev->pmu_conf[0x5b] & 0x02)) { + if (addr == 0x10) + dev->pmu_conf[addr] = (val & 0xc0) | 1; + else if (addr == 0x11) + dev->pmu_conf[addr] = val; + + acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); + } + break; + + /* SMBus Base I/O */ + case 0x14: case 0x15: + if (!(dev->pmu_conf[0x5b] & 0x04)) { + if (addr == 0x14) + dev->pmu_conf[addr] = (val & 0xe0) | 1; + else if (addr == 0x15) + dev->pmu_conf[addr] = val; + + smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } + break; + + /* Subsystem Vendor ID */ + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + if (!(dev->pmu_conf[0xd8] & 0x08)) + dev->pmu_conf[addr] = val; + break; + + case 0x40: + dev->pmu_conf[addr] = val & 0x1f; + pic_set_smi_irq_mask(8, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x40] & 0x03)); + break; + case 0x41: + dev->pmu_conf[addr] = val & 0x10; + ali1543_log("PMU41: %02X\n", val); + apm_set_do_smi(dev->acpi->apm, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x41] & 0x10)); + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x42: + dev->pmu_conf[addr] &= ~(val & 0x1f); + break; + case 0x43: + dev->pmu_conf[addr] &= ~(val & 0x10); + if (val & 0x10) + acpi_ali_soft_smi_status_write(dev->acpi, 0); + break; + + case 0x44: + dev->pmu_conf[addr] = val; + break; + case 0x45: + dev->pmu_conf[addr] = val & 0x9f; + break; + case 0x46: + dev->pmu_conf[addr] = val & 0x18; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x48: + dev->pmu_conf[addr] &= ~val; + break; + case 0x49: + dev->pmu_conf[addr] &= ~(val & 0x9f); + break; + case 0x4a: + dev->pmu_conf[addr] &= ~(val & 0x38); + break; + + case 0x4c: + dev->pmu_conf[addr] = val & 5; + break; + case 0x4d: + dev->pmu_conf[addr] = val & 1; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x4e: + dev->pmu_conf[addr] &= ~(val & 5); + break; + case 0x4f: + dev->pmu_conf[addr] &= ~(val & 1); + break; + + case 0x54: /* Standby timer */ + dev->pmu_conf[addr] = val; + break; + case 0x55: /* APM Timer */ + dev->pmu_conf[addr] = val & 0x7f; + break; + case 0x59: /* Global display timer. */ + dev->pmu_conf[addr] = val & 0x1f; + break; + + case 0x5b: /* ACPI/SMB Base I/O Control */ + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x60: + dev->pmu_conf[addr] = val; + break; + case 0x61: + dev->pmu_conf[addr] = val & 0x13; + break; + case 0x62: + dev->pmu_conf[addr] = val & 0xf1; + break; + case 0x63: + dev->pmu_conf[addr] = val & 0x07; + break; + + case 0x64: + dev->pmu_conf[addr] = val; + break; + case 0x65: + dev->pmu_conf[addr] = val & 0x11; + break; + + case 0x68: + dev->pmu_conf[addr] = val & 0x07; + break; + + case 0x6c: case 0x6d: + dev->pmu_conf[addr] = val; + break; + case 0x6e: + dev->pmu_conf[addr] = val & 0xbf; + break; + case 0x6f: + dev->pmu_conf[addr] = val & 0x1f; + break; + + case 0x70: + dev->pmu_conf[addr] = val; + break; + case 0x71: + dev->pmu_conf[addr] = val & 0x3f; + break; + + case 0x72: + dev->pmu_conf[addr] = val & 0x0f; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x74: + dev->pmu_conf[addr] &= ~(val & 0x33); + break; + + case 0x75: + dev->pmu_conf[addr] = val; + break; + + case 0x76: + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x77: + /* TODO: If bit 1 is clear, then status bit is set even if SMI is disabled. */ + dev->pmu_conf[addr] = val; + pic_set_smi_irq_mask(8, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x40] & 0x03)); + ali1543_log("PMU77: %02X\n", val); + apm_set_do_smi(dev->acpi->apm, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x41] & 0x10)); + break; + + case 0x78: + dev->pmu_conf[addr] = val; + break; + case 0x79: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0x7a: + dev->pmu_conf[addr] = val & 0x02; + break; + + case 0x7b: + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x7c ... 0x7f: + dev->pmu_conf[addr] = val; + break; + + case 0x81: + dev->pmu_conf[addr] = val & 0xf0; + break; + + case 0x8c: case 0x8d: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0x90: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0x94: + dev->pmu_conf[addr] = val & 0xf0; + break; + case 0x95 ... 0x97: + dev->pmu_conf[addr] = val; + break; + + case 0xa4: case 0xa5: + dev->pmu_conf[addr] = val; + break; + + case 0xb2: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xb3: + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0xb4: + dev->pmu_conf[addr] = val & 0x7c; + break; + + case 0xb5: case 0xb7: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0xbc: + outb(0x70, val); + break; + + case 0xbd: + dev->pmu_conf[addr] = val & 0x0f; + acpi_set_timer32(dev->acpi, val & 0x04); + break; + + case 0xbe: + dev->pmu_conf[addr] = val & 0x03; + break; + + /* Continue Further Later */ + /* GPO Registers */ + case 0xc0: + dev->pmu_conf[addr] = val & 0x0f; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc1: + dev->pmu_conf[addr] = val & 0x12; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc2: + dev->pmu_conf[addr] = val & 0x1c; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc3: + dev->pmu_conf[addr] = val & 0x06; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + + case 0xc6: + dev->pmu_conf[addr] = val & 0x06; + break; + + case 0xc8: case 0xc9: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xca: + /* TODO: Write to this port causes a beep. */ + dev->pmu_conf[addr] = val; + break; + + case 0xd4: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xd8: + dev->pmu_conf[addr] = val & 0xfd; + break; + + case 0xe0: + dev->pmu_conf[addr] = val & 0x03; + smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); + break; + + case 0xe1: + dev->pmu_conf[addr] = val; + break; + + case 0xe2: + dev->pmu_conf[addr] = val & 0xf8; + break; + + default: + dev->pmu_conf[addr] = val; + break; + } +} + + +static uint8_t +ali7101_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->pmu_dev_enable && (func == 0)) { + if ((dev->pmu_conf[0xc9] & 0x01) && (addr >= 0x40) && (addr != 0xc9)) + return 0xff; + + /* TODO: C4, C5 = GPIREG (masks: 0D, 0E) */ + if (addr == 0x43) + ret = acpi_ali_soft_smi_status_read(dev->acpi) ? 0x10 : 0x00; + else if (addr == 0xbc) + ret = inb(0x70); + else + ret = dev->pmu_conf[addr]; + + if (dev->pmu_conf[0x77] & 0x10) { + switch (addr) { + case 0x42: + dev->pmu_conf[addr] &= 0xe0; + break; + case 0x43: + dev->pmu_conf[addr] &= 0xef; + acpi_ali_soft_smi_status_write(dev->acpi, 0); + break; + + case 0x48: + dev->pmu_conf[addr] = 0x00; + break; + case 0x49: + dev->pmu_conf[addr] &= 0x60; + break; + case 0x4a: + dev->pmu_conf[addr] &= 0xc7; + break; + + case 0x4e: + dev->pmu_conf[addr] &= 0xfa; + break; + case 0x4f: + dev->pmu_conf[addr] &= 0xfe; + break; + + case 0x74: + dev->pmu_conf[addr] &= 0xcc; + break; + } + } + } + + return ret; +} + + +static void +ali1533_sio_fdc_handler(ali1543_t *dev) +{ + fdc_remove(dev->fdc_controller); + + if (dev->device_regs[0][0x30] & 1) { + ali1543_log("New FDC base address: %04X\n", dev->device_regs[0][0x61] | (dev->device_regs[0][0x60] << 8)); + fdc_set_base(dev->fdc_controller, dev->device_regs[0][0x61] | (dev->device_regs[0][0x60] << 8)); + fdc_set_irq(dev->fdc_controller, dev->device_regs[0][0x70] & 0xf); + fdc_set_dma_ch(dev->fdc_controller, dev->device_regs[0][0x74] & 0x07); + ali1543_log("M1543-SIO FDC: ADDR %04x IRQ %02x DMA %02x\n", dev->device_regs[0][0x61] | (dev->device_regs[0][0x60] << 8), dev->device_regs[0][0x70] & 0xf, dev->device_regs[0][0x74] & 0x07); + } +} + + +static void +ali1533_sio_uart_handler(int num, ali1543_t *dev) +{ + serial_remove(dev->uart[num]); + + if (dev->device_regs[num + 4][0x30] & 1) { + serial_setup(dev->uart[num], dev->device_regs[num + 4][0x61] | (dev->device_regs[num + 4][0x60] << 8), dev->device_regs[num + 4][0x70] & 0xf); + ali1543_log("M1543-SIO UART%d: ADDR %04x IRQ %02x\n", num, dev->device_regs[num + 4][0x61] | (dev->device_regs[num + 4][0x60] << 8), dev->device_regs[num + 4][0x70] & 0xf); + } +} + + +void +ali1533_sio_lpt_handler(ali1543_t *dev) +{ + lpt1_remove(); + + if (dev->device_regs[3][0x30] & 1) { + lpt1_init(dev->device_regs[3][0x61] | (dev->device_regs[3][0x60] << 8)); + lpt1_irq(dev->device_regs[3][0x70] & 0xf); + ali1543_log("M1543-SIO LPT: ADDR %04x IRQ %02x\n", dev->device_regs[3][0x61] | (dev->device_regs[3][0x60] << 8), dev->device_regs[3][0x70] & 0xf); + } +} + + +void +ali1533_sio_ldn(uint16_t ldn, ali1543_t *dev) +{ + /* We don't include all LDN's */ + switch (ldn) { + case 0: /* FDC */ + ali1533_sio_fdc_handler(dev); + break; + case 3: /* LPT */ + ali1533_sio_lpt_handler(dev); + break; + /* UART */ + case 4: case 5: + ali1533_sio_uart_handler(ldn - 4, dev); + break; + } +} + + +static void +ali1533_sio_write(uint16_t addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + + switch (addr) { + case 0x3f0: + dev->sio_index = val; + if (dev->sio_index == 0x51) + dev->in_configuration_mode = 1; + else if ((dev->sio_index == 0x23) && (dev->in_configuration_mode == 1)) + dev->in_configuration_mode = 2; + else if (dev->sio_index == 0xbb) + dev->in_configuration_mode = 0; + break; + + case 0x3f1: + if (dev->in_configuration_mode == 2) { + switch (dev->sio_index) { + case 0x07: + dev->sio_regs[dev->sio_index] = val & 0x7; + break; + + case 0x22: + dev->sio_regs[dev->sio_index] = val & 0x39; + break; + + case 0x23: + dev->sio_regs[dev->sio_index] = val & 0x38; + break; + + default: + if ((dev->sio_index < 0x30) || (dev->sio_index == 0x51) || (dev->sio_index == 0xbb)) + dev->sio_regs[dev->sio_index] = val; + else if (dev->sio_regs[0x07] <= 7) + dev->device_regs[dev->sio_regs[0x07]][dev->sio_index] = val; + break; + } + } + break; + } + + if ((!dev->in_configuration_mode) && (dev->sio_regs[0x07] <= 7) && (addr == 0x03f0)) + ali1533_sio_ldn(dev->sio_regs[0x07], dev); +} + + +static uint8_t +ali1533_sio_read(uint16_t addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x03f1) { + if (dev->sio_index >= 0x30) + ret = dev->device_regs[dev->sio_regs[0x07]][dev->sio_index]; + else + ret = dev->sio_regs[dev->sio_index]; + } + + return ret; +} + + +static void +ali1543_reset(void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + int i; + + /* Temporarily enable everything. Register writes will disable the devices. */ + dev->ide_dev_enable = 1; + dev->usb_dev_enable = 1; + dev->pmu_dev_enable = 1; + + /* M5229 */ + ali5229_chip_reset(dev); /* M5237 */ + memset(dev->usb_conf, 0x00, sizeof(dev->pmu_conf)); dev->usb_conf[0x00] = 0xb9; dev->usb_conf[0x01] = 0x10; dev->usb_conf[0x02] = 0x37; @@ -837,24 +1396,73 @@ ali1543_reset(void *priv) dev->usb_conf[0x3d] = 0x01; ali5237_write(0, 0x04, 0x00, dev); + ali5237_write(0, 0x10, 0x00, dev); + ali5237_write(0, 0x11, 0x00, dev); + ali5237_write(0, 0x12, 0x00, dev); + ali5237_write(0, 0x13, 0x00, dev); /* M7101 */ + memset(dev->pmu_conf, 0x00, sizeof(dev->pmu_conf)); dev->pmu_conf[0x00] = 0xb9; dev->pmu_conf[0x01] = 0x10; dev->pmu_conf[0x02] = 0x01; dev->pmu_conf[0x03] = 0x71; - dev->pmu_conf[0x04] = 0x0f; dev->pmu_conf[0x05] = 0x00; dev->pmu_conf[0x0a] = 0x01; dev->pmu_conf[0x0b] = 0x06; + dev->pmu_conf[0xe2] = 0x20; acpi_set_slot(dev->acpi, dev->pmu_slot); acpi_set_nvr(dev->acpi, dev->nvr); - ali7101_write(0, 0x04, 0x00, dev); + ali7101_write(0, 0x04, 0x0f, dev); + ali7101_write(0, 0x10, 0x01, dev); + ali7101_write(0, 0x11, 0x00, dev); + ali7101_write(0, 0x12, 0x00, dev); + ali7101_write(0, 0x13, 0x00, dev); + ali7101_write(0, 0x14, 0x01, dev); + ali7101_write(0, 0x15, 0x00, dev); + ali7101_write(0, 0x16, 0x00, dev); + ali7101_write(0, 0x17, 0x00, dev); + ali7101_write(0, 0x40, 0x00, dev); + ali7101_write(0, 0x41, 0x00, dev); + ali7101_write(0, 0x42, 0x00, dev); + ali7101_write(0, 0x43, 0x00, dev); + ali7101_write(0, 0x77, 0x00, dev); + ali7101_write(0, 0xbd, 0x00, dev); ali7101_write(0, 0xc0, 0x00, dev); + ali7101_write(0, 0xc1, 0x00, dev); + ali7101_write(0, 0xc2, 0x00, dev); + ali7101_write(0, 0xc3, 0x00, dev); + ali7101_write(0, 0xe0, 0x00, dev); + + /* Do the bridge last due to device deactivations. */ + /* M1533 */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x33; + dev->pci_conf[0x03] = 0x15; + dev->pci_conf[0x04] = 0x0f; + dev->pci_conf[0x07] = 0x02; + dev->pci_conf[0x0a] = 0x01; + dev->pci_conf[0x0b] = 0x06; + + ali1533_write(0, 0x48, 0x00, dev); // Disables all IRQ's + ali1533_write(0, 0x44, 0x00, dev); + ali1533_write(0, 0x4d, 0x00, dev); + ali1533_write(0, 0x53, 0x00, dev); + ali1533_write(0, 0x58, 0x00, dev); + ali1533_write(0, 0x5f, 0x00, dev); + ali1533_write(0, 0x72, 0x00, dev); + ali1533_write(0, 0x74, 0x00, dev); + ali1533_write(0, 0x75, 0x00, dev); + ali1533_write(0, 0x76, 0x00, dev); /* M1543 Super I/O */ + memset(dev->sio_regs, 0x00, sizeof(dev->sio_regs)); + for (i = 0; i < 8; i++) + memset(dev->device_regs[i], 0x00, sizeof(dev->device_regs[i])); + dev->device_regs[0][0x60] = 0x03; dev->device_regs[0][0x61] = 0xf0; dev->device_regs[0][0x70] = 0x06; @@ -887,8 +1495,11 @@ ali1543_reset(void *priv) ali1533_sio_uart_handler(0, dev); ali1533_sio_uart_handler(1, dev); ali1533_sio_lpt_handler(dev); + + unmask_a20_in_smm = 1; } + static void ali1543_close(void *priv) { @@ -897,6 +1508,7 @@ ali1543_close(void *priv) free(dev); } + static void * ali1543_init(const device_t *info) { @@ -912,7 +1524,7 @@ ali1543_init(const device_t *info) /* Device 0C: M7101 Power Managment Controller */ dev->pmu_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, ali7101_read, ali7101_write, dev); - /* Device 0D: M5237 USB */ + /* Device 0F: M5237 USB */ dev->usb_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, ali5237_read, ali5237_write, dev); /* Ports 3F0-1h: M1543 Super I/O */ @@ -920,20 +1532,24 @@ ali1543_init(const device_t *info) /* ACPI */ dev->acpi = device_add(&acpi_ali_device); - dev->nvr = device_add(&at_nvr_device); // Generic NVR + dev->nvr = device_add(&piix4_nvr_device); /* APM */ - dev->apm = device_add(&apm_pci_device); + // dev->apm = device_add(&apm_pci_device); /* DMA */ dma_alias_set(); + + dma_set_sg_base(0x04); + dma_set_params(1, 0xffffffff); + dma_ext_mode_init(); dma_high_page_init(); /* DDMA */ dev->ddma = device_add(&ddma_device); /* Floppy Disk Controller */ - dev->fdc_controller = device_add(&fdc_at_device); + dev->fdc_controller = device_add(&fdc_at_smc_device); /* IDE Controllers */ dev->ide_controller[0] = device_add_inst(&sff8038i_device, 1); @@ -950,16 +1566,25 @@ ali1543_init(const device_t *info) dev->smbus = device_add(&piix4_smbus_device); /* Super I/O Configuration Mechanism */ - dev->in_configuration_mode = 1; + dev->in_configuration_mode = 0; /* USB */ dev->usb = device_add(&usb_device); + pci_enable_mirq(0); + pci_enable_mirq(1); + pci_enable_mirq(2); + pci_enable_mirq(3); + pci_enable_mirq(4); + pci_enable_mirq(5); + pci_enable_mirq(6); + ali1543_reset(dev); return dev; } + const device_t ali1543_device = { "ALi M1543 Desktop South Bridge", DEVICE_PCI, @@ -967,7 +1592,8 @@ const device_t ali1543_device = { ali1543_init, ali1543_close, ali1543_reset, - {NULL}, + { NULL }, NULL, NULL, - NULL}; + NULL +}; diff --git a/src/chipset/opti391.c b/src/chipset/opti391.c new file mode 100644 index 000000000..f6b1f2686 --- /dev/null +++ b/src/chipset/opti391.c @@ -0,0 +1,226 @@ +/* + * 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 OPTi 82C391/392 chipset. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/chipset.h> + + +#ifdef ENABLE_OPTI391_LOG +int opti391_do_log = ENABLE_OPTI391_LOG; + +static void +opti391_log(const char *fmt, ...) +{ + va_list ap; + + if (opti391_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti391_log(fmt, ...) +#endif + + +typedef struct +{ + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, regs[256]; +} opti391_t; + + +static void +opti391_shadow_recalc(opti391_t *dev) +{ + uint32_t i, base; + uint8_t sh_enable, sh_master; + uint8_t sh_wp, sh_write_internal; + + shadowbios = shadowbios_write = 0; + + /* F0000-FFFFF */ + sh_enable = !(dev->regs[0x22] & 0x80); + if (sh_enable) + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + sh_write_internal = (dev->regs[0x26] & 0x40); + /* D0000-EFFFF */ + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + if (base >= 0xe0000) { + sh_master = (dev->regs[0x22] & 0x40); + sh_wp = (dev->regs[0x22] & 0x10); + } else { + sh_master = (dev->regs[0x22] & 0x20); + sh_wp = (dev->regs[0x22] & 0x08); + } + sh_enable = dev->regs[0x23] & (1 << i); + + if (sh_master) { + if (sh_enable) { + if (sh_wp) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + + /* C0000-CFFFF */ + sh_master = !(dev->regs[0x26] & 0x10); + sh_wp = (dev->regs[0x26] & 0x20); + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + sh_enable = dev->regs[0x26] & (1 << i); + + if (sh_master) { + if (sh_enable) { + if (sh_wp) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } +} + + +static void +opti391_write(uint16_t addr, uint8_t val, void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; + break; + + case 0x24: + opti391_log("OPTi 391: dev->regs[%02x] = %02x\n", dev->index, val); + + switch (dev->index) { + case 0x20: + dev->regs[dev->index] = (dev->regs[dev->index] & 0xc0) | (val & 0x3f); + break; + + case 0x21: case 0x24: case 0x25: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + dev->regs[dev->index] = val; + break; + + case 0x22: case 0x23: + case 0x26: + dev->regs[dev->index] = val; + opti391_shadow_recalc(dev); + break; + } + break; + } +} + + +static uint8_t +opti391_read(uint16_t addr, void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x24) + ret = dev->regs[dev->index]; + + return ret; +} + + +static void +opti391_close(void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + + free(dev); +} + + +static void * +opti391_init(const device_t *info) +{ + opti391_t *dev = (opti391_t *)malloc(sizeof(opti391_t)); + memset(dev, 0x00, sizeof(opti391_t)); + + io_sethandler(0x0022, 0x0001, opti391_read, NULL, NULL, opti391_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti391_read, NULL, NULL, opti391_write, NULL, NULL, dev); + + dev->regs[0x21] = 0x84; + dev->regs[0x24] = 0x07; + dev->regs[0x25] = 0xf0; + dev->regs[0x26] = 0x30; + dev->regs[0x27] = 0x91; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + dev->regs[0x2a] = 0x80; + dev->regs[0x2b] = 0x10; + + opti391_shadow_recalc(dev); + + return dev; +} + + +const device_t opti391_device = { + "OPTi 82C391", + 0, + 0, + opti391_init, + opti391_close, + NULL, + { NULL }, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 49277d53d..447d64fa3 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -43,6 +43,7 @@ typedef struct } opti895_t; +#define ENABLE_OPTI895_LOG 1 #ifdef ENABLE_OPTI895_LOG int opti895_do_log = ENABLE_OPTI895_LOG; @@ -91,11 +92,15 @@ opti895_recalc(opti895_t *dev) shflags = MEM_READ_INTERNAL; shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; } else { - if (dev->regs[0x26] & 0x40) { - shflags = MEM_READ_EXTANY; + shflags = (dev->regs[0x2d] & (1 << ((i >> 1) + 2))) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + if (dev->regs[0x26] & 0x40) shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; - } else - shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else { + if (dev->regs[0x26] & 0x80) + shflags |= (dev->regs[0x2d] & (1 << ((i >> 1) + 2))) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + else + shflags |= MEM_WRITE_EXTERNAL; + } } mem_set_mem_state_both(base, 0x4000, shflags); @@ -108,17 +113,21 @@ opti895_recalc(opti895_t *dev) shflags = MEM_READ_INTERNAL; shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; } else { - if (dev->regs[0x26] & 0x40) { - shflags = MEM_READ_EXTANY; + shflags = (dev->regs[0x2d] & (1 << (i >> 1))) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + if (dev->regs[0x26] & 0x40) shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; - } else - shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else { + if (dev->regs[0x26] & 0x80) + shflags |= (dev->regs[0x2d] & (1 << (i >> 1))) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + else + shflags |= MEM_WRITE_EXTERNAL; + } } mem_set_mem_state_both(base, 0x4000, shflags); } - flushmmucache(); + flushmmucache_nopc(); } @@ -138,7 +147,7 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) } break; case 0x24: - if (((dev->idx >= 0x20) && (dev->idx <= 0x2c)) || + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { dev->regs[dev->idx] = val; opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); @@ -152,6 +161,7 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) case 0x22: case 0x23: case 0x26: + case 0x2d: opti895_recalc(dev); break; @@ -195,7 +205,7 @@ opti895_read(uint16_t addr, void *priv) ret = dev->regs[dev->idx]; break; case 0x24: - if (((dev->idx >= 0x20) && (dev->idx <= 0x2c)) || + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { ret = dev->regs[dev->idx]; if (dev->idx == 0xe0) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 634cb948e..f5cc06d6a 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -98,9 +98,18 @@ vl82c480_write(uint16_t addr, uint8_t val, void *p) default: dev->regs[dev->idx] = val; break; + case 0x04: + if (dev->regs[0x00] == 0x98) + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7); + else + dev->regs[dev->idx] = val; + break; case 0x05: dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef); break; + case 0x07: + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf); + break; case 0x0d: case 0x0e: case 0x0f: case 0x10: case 0x11: case 0x12: dev->regs[dev->idx] = val; @@ -163,11 +172,13 @@ vl82c480_init(const device_t *info) vl82c480_t *dev = (vl82c480_t *)malloc(sizeof(vl82c480_t)); memset(dev, 0, sizeof(vl82c480_t)); - dev->regs[0x00] = 0x90; + dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; dev->regs[0x02] = 0x8a; dev->regs[0x03] = 0x88; dev->regs[0x06] = 0x1b; + if (info->local == 0x98) + dev->regs[0x07] = 0x21; dev->regs[0x08] = 0x38; io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, dev); @@ -181,7 +192,17 @@ vl82c480_init(const device_t *info) const device_t vl82c480_device = { "VLSI VL82c480", 0, - 0, + 0x90, + vl82c480_init, vl82c480_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + +const device_t vl82c486_device = { + "VLSI VL82c486", + 0, + 0x98, vl82c480_init, vl82c480_close, NULL, { NULL }, NULL, NULL, NULL diff --git a/src/config.c b/src/config.c index d412e1553..e72fb55f7 100644 --- a/src/config.c +++ b/src/config.c @@ -583,20 +583,26 @@ load_machine(void) machine = machine_get_machine_from_internal_name("pc916sx"); else if (! strcmp(p, "cbm_sl386sx16")) machine = machine_get_machine_from_internal_name("cmdsl386sx16"); - else if (! strcmp(p, "olivetti_m300_08")) - machine = machine_get_machine_from_internal_name("m30008"); - else if (! strcmp(p, "olivetti_m300_15")) - machine = machine_get_machine_from_internal_name("m30015"); else if (! strcmp(p, "cbm_sl386sx25")) machine = machine_get_machine_from_internal_name("cmdsl386sx25"); else if (! strcmp(p, "award386dx")) /* ...merged machines... */ - machine = machine_get_machine_from_internal_name("award486"); + machine = machine_get_machine_from_internal_name("award495"); else if (! strcmp(p, "ami386dx")) - machine = machine_get_machine_from_internal_name("ami486"); + machine = machine_get_machine_from_internal_name("ami495"); else if (! strcmp(p, "mr386dx")) - machine = machine_get_machine_from_internal_name("mr486"); + machine = machine_get_machine_from_internal_name("mr495"); + else if (! strcmp(p, "award486")) + machine = machine_get_machine_from_internal_name("award495"); + else if (! strcmp(p, "ami486")) + machine = machine_get_machine_from_internal_name("ami495"); + else if (! strcmp(p, "mr486")) + machine = machine_get_machine_from_internal_name("mr495"); else if (! strcmp(p, "fw6400gx_s1")) machine = machine_get_machine_from_internal_name("fw6400gx"); + else if (! strcmp(p, "p54vl")) + machine = machine_get_machine_from_internal_name("p5vl"); + else if (! strcmp(p, "chariot")) + machine = machine_get_machine_from_internal_name("fmb"); else if (! strcmp(p, "president")) { /* ...and removed machines */ machine = machine_get_machine_from_internal_name("mb500n"); migrate_from = NULL; diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index bc6f56324..613d8842e 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -641,7 +641,7 @@ const OpFn OP_TABLE(c486_0f)[1024] = /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -663,7 +663,7 @@ const OpFn OP_TABLE(c486_0f)[1024] = /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -685,7 +685,7 @@ const OpFn OP_TABLE(c486_0f)[1024] = /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -707,7 +707,7 @@ const OpFn OP_TABLE(c486_0f)[1024] = /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, diff --git a/src/cpu/x86.c b/src/cpu/x86.c index e652c5d27..a80eb2d21 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -26,6 +26,7 @@ #include "cpu.h" #include "x86.h" #include <86box/machine.h> +#include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/rom.h> @@ -239,8 +240,10 @@ reset_common(int hard) leave_smm(); /* Needed for the ALi M1533. */ - if (soft_reset_pci && !hard) + if (soft_reset_pci && !hard) { pci_reset(); + device_reset_all_pci(); + } use32 = 0; cpu_cur_status = 0; @@ -264,7 +267,7 @@ reset_common(int hard) } else { loadcs(0xFFFF); cpu_state.pc = 0; - rammask = 0xfffff; + rammask = is286 ? 0xffffff : 0xfffff; } } idt.base = 0; @@ -307,8 +310,10 @@ reset_common(int hard) shadowbios = shadowbios_write = 0; alt_access = cpu_end_block_after_ins = 0; - if (hard) + if (hard) { reset_on_hlt = hlt_reset_pending = 0; + soft_reset_pci = 0; + } if (!is286) reset_808x(hard); diff --git a/src/cpu/x86_ops_msr.h b/src/cpu/x86_ops_msr.h index 6624218e4..227677268 100644 --- a/src/cpu/x86_ops_msr.h +++ b/src/cpu/x86_ops_msr.h @@ -1,11 +1,13 @@ static int opRDTSC(uint32_t fetchdat) { +#if 0 if (!cpu_has_feature(CPU_FEATURE_RDTSC)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); return 1; } +#endif if ((cr4 & CR4_TSD) && CPL) { x86gpf("RDTSC when TSD set and CPL != 0", 0); diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c new file mode 100644 index 000000000..bb756f67d --- /dev/null +++ b/src/device/kbc_at.c @@ -0,0 +1,2324 @@ +/* + * 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. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/ppi.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/m_xt_xi8088.h> +#include <86box/m_at_t3100e.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/keyboard.h> + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_UNLOCKED 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +#define RESET_DELAY_TIME 1000 /* 100 ms */ + +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 + +#define CCB_MASK 0x68 +#define MODE_MASK 0x6c + +#define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ +#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ +/* This only differs in that translation is forced off. */ +#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x07 + +#define KBC_FLAG_PS2 0x04 + +/* We need to redefine this: + Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 + for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling + controller mode, normally set according to the flags, but togglable on + AMIKey: + 0000 0000 0x00 IBM, AT + 0000 0001 0x01 MR + 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 + 0001 0000 0x10 Olivetti + 0010 0000 0x20 Toshiba + 0011 0000 0x30 Quadtel + 0100 0000 0x40 Phoenix MultiKey/42 + 0101 0000 0x50 AMI KF + 0101 0001 0x51 AMI KH + 0101 0010 0x52 AMIKey + 0101 0011 0x53 AMIKey-2 + 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) + 0110 0000 0x60 Award + 0110 0001 0x61 Award 286 (has some AMI commands apparently) + 0111 0000 0x70 Siemens +*/ + +/* Standard IBM controller */ +#define KBC_VEN_GENERIC 0x00 +/* All commands are standard PS/2 */ +#define KBC_VEN_IBM_MCA 0x08 +/* Standard IBM commands, differs in input port bits */ +#define KBC_VEN_IBM_PS1 0x10 +/* Olivetti - proprietary commands and port 62h with switches + readout */ +#define KBC_VEN_OLIVETTI 0x20 +/* Toshiba T3100e - has a bunch of proprietary commands, also sets + IFULL on command AA */ +#define KBC_VEN_TOSHIBA 0x28 +/* Standard IBM commands, uses input port as a switches readout */ +#define KBC_VEN_NCR 0x30 +/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the + polarity of the video type bit in the input port is inverted */ +#define KBC_VEN_XI8088 0x38 +/* QuadtelKey - currently guesswork */ +#define KBC_VEN_QUADTEL 0x40 +/* Phoenix MultiKey/42 - not yet implemented */ +#define KBC_VEN_PHOENIX 0x48 +/* Generic commands, XI8088-like input port handling of video type, + maybe we just need a flag for that? */ +#define KBC_VEN_ACER 0x50 +/* AMI KF/KH/AMIKey/AMIKey-2 */ +#define KBC_VEN_AMI 0xf0 +/* Standard AMI commands, differs in input port bits */ +#define KBC_VEN_INTEL_AMI 0xf8 +#define KBC_VEN_MASK 0xf8 + + +/* Flags should be fully 32-bit: + Bits 7- 0: Vendor and revision/variant; + Bits 15- 8: Input port mask; + Bits 23-16: Input port bits that are always on; + Bits 31-24: Flags: + Bit 0: Invert P1 video type bit polarity; + Bit 1: Is PS/2; + Bit 2: Translation forced always off. + + So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ + + +typedef struct { + uint8_t *c_in, *c_data, /* Data to controller */ + *d_in, *d_data, /* Data to device */ + *inhibit; + + void (*process)(void *priv); + void *priv; +} kbc_dev_t; + +typedef struct { + uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, + secr_phase, mem_index, ami_stat, ami_mode, + kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, + kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit; + + uint8_t mem_int[0x40], mem[0x240]; + + uint16_t last_irq, kbc_phase; + + uint32_t flags; + + kbc_dev_t * kbc_devs[2]; + + pc_timer_t pulse_cb, send_delay_timer; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); + + void * log; +} atkbc_t; + + +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbc_wait(atkbc_t *dev, uint8_t flags); + + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t keyboard_mode = 0x42; + +uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; + + +uint8_t mouse_queue[16]; +int mouse_queue_start = 0, mouse_queue_end = 0; +static void (*mouse_write)(uint8_t val, void *priv) = NULL; +static void *mouse_p = NULL; +static uint8_t sc_or = 0; +static atkbc_t *saved_kbc = NULL; + + +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, + 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, + 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, + 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, + 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, + 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, + 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, + 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, + 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, + 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, + 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, + 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, + 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + + +#define UISTR_LEN 256 +static char kbc_str[UISTR_LEN]; /* UI output string */ + + +extern void ui_sb_bugui(char *__str); + + +static void +kbc_status(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(kbc_str, fmt, ap); + ui_sb_bugui(kbc_str); + va_end(ap); +} + + +#define ENABLE_KBC_AT_LOG 1 +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) +int kbc_at_do_log = ENABLE_KBC_AT_LOG; + + +static void +kbc_log(atkbc_t *dev, const char *fmt, ...) +{ + va_list ap; + + if ((dev == NULL) || (dev->log == NULL)) + return; + + if (kbc_at_do_log) { + va_start(ap, fmt); + log_out(dev->log, fmt, ap); + va_end(ap); + } +} +#else +#define kbc_log(dev, fmt, ...) +#endif + + +static void +kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t ch = (channel > 0) ? channel : 1; + uint8_t do_irq = (dev->mem[0x20] & ch); + int translate = (channel == 1) && (keyboard_mode & 0x60); + + if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) + return; + + stat_hi |= dev->inhibit; + + if (!dev->kbc_send_pending) { + dev->kbc_send_pending = 1; + dev->kbc_to_send = val; + dev->kbc_channel = channel; + dev->kbc_stat_hi = stat_hi; + return; + } + + if (translate) { + /* Allow for scan code translation. */ + if (val == 0xf0) { + kbc_log(dev, "Translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if ((sc_or == 0x80) && (val & 0x80)) { + kbc_log(dev, "Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + } + + dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; + if (do_irq) { + kbc_log(dev, "[%04X:%08X] IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); + picint(dev->last_irq); + } + kbc_log(dev, "%02X coming from channel %i (%i)\n", val, channel, do_irq); + dev->ob = translate ? (nont_to_t[val] | sc_or) : val; + + dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); + if (ch == 2) + dev->status |= STAT_MFULL; + + if (translate && (sc_or == 0x80)) + sc_or = 0; +} + + +static void +write_output(atkbc_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbc_log(dev, "Write output port: %02X (old: %02X)\n", val, dev->p2); + + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + val |= ((dev->mem[0x20] << 4) & 0x30); + + dev->kbc_devs[0]->inhibit = (val & 0x40); + dev->kbc_devs[1]->inhibit = (val & 0x08); + + if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) { + kbc_log(dev, "write_output(): IRQ 12\n"); + picint(1 << 12); + } else + picintc(1 << 12); + } + if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) { + kbc_log(dev, "write_output(): IRQ 1\n"); + picint(1 << 1); + } else + picintc(1 << 1); + } + if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->p2 ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->p2 = val; +} + + +static void +write_cmd(atkbc_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbc_log(dev, "Write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + val &= ~CCB_TRANSLATE; + + dev->mem[0x20] = val; + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbc_log(dev, "Keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { + keyboard_mode &= ~CCB_PCMODE; + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + + kbc_log(dev, "Mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + kbc_log(dev, "Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbc_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbc_log(dev, "pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + +static void +set_enable_kbd(atkbc_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbc_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + + +static void +kbc_transmit(atkbc_t *dev, uint8_t val) +{ + kbc_send_to_ob(dev, val, 0, 0x00); +} + + +static void +kbc_command(atkbc_t *dev) +{ + uint8_t mask, val = dev->ib; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int bad = 1; + + if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { + if (dev-> kbc_phase < 16) + kbc_transmit(dev, dev->mem[dev->kbc_phase]); + else if (dev-> kbc_phase == 16) + kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); + else if (dev-> kbc_phase == 17) + kbc_transmit(dev, dev->p2); + else if (dev-> kbc_phase == 18) + kbc_transmit(dev, dev->status); + + dev->kbc_phase++; + if (dev->kbc_phase == 19) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } + return; + } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { + val = ami_copr[dev->kbc_phase]; + kbc_transmit(dev, val); + if (val == 0x00) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } else + dev->kbc_phase++; + return; + } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { + /* load security */ + kbc_log(dev, "Load security\n"); + dev->mem[0x50 + dev->kbc_in - 0x01] = val; + if ((dev->kbc_in == 0x80) && (val != 0x00)) { + /* Security string too long, set it to 0x00. */ + dev->mem[0x50] = 0x00; + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else if (val == 0x00) { + /* Security string finished. */ + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else /* Increase pointer and request another byte. */ + dev->kbc_in++; + return; + } + + /* If the written port is 64, go straight to the beginning of the command. */ + if (!(dev->status & STAT_CD) && dev->kbc_in) { + /* Write data to controller. */ + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (dev->kbc_cmd) { + case 0x60 ... 0x7f: + if (dev->kbc_cmd == 0x60) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + break; + + case 0xc7: /* or input port with system data */ + dev->p1 |= val; + break; + + case 0xcb: /* set keyboard mode */ + kbc_log(dev, "New AMIKey mode: %02X\n", val); + dev->ami_mode = val; + dev->flags &= ~KBC_FLAG_PS2; + if (val & 1) + dev->flags |= KBC_FLAG_PS2; +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) + log_set_dev_name(dev->kbc_log, (dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); +#endif + break; + + case 0xd1: /* write output port */ + if (dev->p2_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->p2 & 0x0c); + } + kbc_log(dev, "Write %02X to output port\n", val); + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbc_log(dev, "Write %02X to keyboard output buffer\n", val); + /* Should be channel 1, but we send to 0 to avoid translation, + since bytes output using this command do *NOT* get translated. */ + kbc_send_to_ob(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbc_log(dev, "Write %02X to mouse output buffer\n", val); + if (dev->flags & KBC_FLAG_PS2) + kbc_send_to_ob(dev, val, 2, 0x00); + break; + + case 0xd4: /* write to mouse */ + kbc_log(dev, "Write %02X to mouse\n", val); + + if (dev->flags & KBC_FLAG_PS2) { + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x20; + if (dev->kbc_devs[1] && !dev->kbc_devs[1]->c_in) { + kbc_log(dev, "Transmitting %02X to mouse...\n", dev->ib); + dev->kbc_devs[1]->d_data = val; + dev->kbc_devs[1]->d_in = 1; + dev->kbc_wait_for_response = 2; + } else + kbc_send_to_ob(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + + if (bad) + kbc_log(dev, "Bad controller command %02x data %02x\n", dev->kbc_cmd, val); + } + } else { + /* Controller command. */ + kbc_log(dev, "Controller command: %02X\n", val); + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->kbc_in = 1; + break; + + case 0xaa: /* self-test */ + kbc_log(dev, "Self-test\n"); + write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + dev->in_cmd = dev->mouse_in_cmd = 0; + dev->status &= ~STAT_OFULL; + dev->last_irq = 0; + dev->kbc_phase = 0; + + /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ + if (dev->flags & KBC_FLAG_PS2) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + kbc_transmit(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbc_log(dev, "Interface test\n"); + /* No error. */ + kbc_transmit(dev, 0x00); + break; + + case 0xac: /* diagnostic dump */ + kbc_log(dev, "Diagnostic dump\n"); + kbc_transmit(dev, dev->mem[0x20]); + dev->kbc_phase = 1; + break; + + case 0xad: /* disable keyboard */ + kbc_log(dev, "Disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbc_log(dev, "Enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* or input port with system data */ + kbc_log(dev, "Phoenix - or input port with system data\n"); + dev->kbc_in = 1; + break; + + case 0xca: /* read keyboard mode */ + kbc_log(dev, "AMI - Read keyboard mode\n"); + kbc_transmit(dev, dev->ami_mode); + break; + + case 0xcb: /* set keyboard mode */ + kbc_log(dev, "ATkbc: AMI - Set keyboard mode\n"); + dev->kbc_in = 1; + break; + + case 0xd0: /* read output port */ + kbc_log(dev, "Read output port\n"); + mask = 0xff; + if (dev->mem[0x20] & 0x10) + mask &= 0xbf; + if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) + mask &= 0xf7; + kbc_transmit(dev, dev->p2 & mask); + break; + + case 0xd1: /* write output port */ + kbc_log(dev, "Write output port\n"); + dev->kbc_in = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbc_log(dev, "Write keyboard output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + dev->kbc_in = 1; + else + kbc_transmit(dev, 0x00); /* NCR */ + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbc_log(dev, "%sable A20\n", (val == 0xdd) ? "Dis": "En"); + write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbc_log(dev, "Read test inputs\n"); + kbc_transmit(dev, 0x00); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + if (bad) + kbc_log(dev, "Bad controller command %02X\n", val); + } + + /* If the command needs data, remember the command. */ + if (dev->kbc_in || (dev->kbc_phase > 0)) + dev->kbc_cmd = val; + } +} + + +static void +kbc_dev_data_to_ob(atkbc_t *dev, uint8_t channel) +{ + if (channel == 0) + return; + + dev->kbc_devs[channel - 1]->c_in = 0; + kbc_log(dev, "Forwarding %02X from channel %i...\n", dev->kbc_devs[channel - 1]->c_data, channel); + kbc_send_to_ob(dev, dev->kbc_devs[channel - 1]->c_data, channel, 0x00); +} + + +static void +kbc_main_loop_scan(atkbc_t *dev) +{ + uint8_t port_dis = dev->mem[0x20] & 0x30; + uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); + + if (!ps2) + port_dis |= 0x20; + + if (!(dev->status & STAT_OFULL)) { + if (port_dis & 0x20) { + if (!(port_dis & 0x10)) { + kbc_log(dev, "kbc_process(): Main loop, Scan: AUX DIS, KBD EN\n"); + /* Enable communication with keyboard. */ + dev->p2 &= 0xbf; + dev->kbc_devs[0]->inhibit = 0; + kbc_wait(dev, 1); + } else + kbc_log(dev, "kbc_process(): Main loop, Scan: AUX DIS, KBD DIS\n"); + } else { + /* Enable communication with mouse. */ + dev->p2 &= 0xf7; + dev->kbc_devs[1]->inhibit = 0; + if (dev->mem[0x20] & 0x10) { + kbc_log(dev, "kbc_process(): Main loop, Scan: AUX EN , KBD DIS\n"); + kbc_wait(dev, 2); + } else { + /* Enable communication with keyboard. */ + kbc_log(dev, "kbc_process(): Main loop, Scan: AUX EN , KBD EN\n"); + dev->p2 &= 0xbf; + dev->kbc_devs[0]->inhibit = 0; + kbc_wait(dev, 3); + } + } + } else + kbc_log(dev, "kbc_process(): Main loop, Scan: IBF not full and OBF full, do nothing\n"); +} + + +static uint8_t +kbc_reset_cmd(atkbc_t *dev) +{ + uint8_t ret = 0; + + if ((dev->status & STAT_CD) || (dev->kbc_poll_phase == KBC_WAIT_FOR_NOBF)) { + kbc_log(dev, " Resetting command\n"); + dev->kbc_phase = 0; + dev->kbc_in = 0; + dev->kbc_in_cmd = 0; + dev->kbc_poll_phase = KBC_MAIN_LOOP; + ret = 1; + } + + return ret; +} + + +static uint8_t +kbc_process_cmd(atkbdt_t *dev, uint8_t restart) +{ + uint8_t ret = 0; + + if (restart) + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + ret = 1; + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response && !(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + + return ret; +} + + +static void +kbc_process_ib(atkbc_t *dev) +{ + if ((dev->status & STAT_CD) || (kbc->flags & KBC_FLAG_PS2) || !(dev->status & STAT_OFULL)) + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) + (void) kbc_process_cmd(dev, 1); + else if ((kbc->flags & KBC_FLAG_PS2) || !(dev->status & STAT_OFULL)) + /* The AT KBC does *NOT* send data to the keyboard if OBF. */ + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x10; + if (dev->kbc_devs[0] && !dev->kbc_devs[0]->c_in) { + dev->kbc_devs[0]->d_data = val; + dev->kbc_devs[0]->d_in = 1; + dev->kbc_wait_for_response = 1; + } else + kbc_send_to_ob(dev, 0xfe, 1, 0x40); + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response && !(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + } +} + + +static void +kbc_wait(atkbc_t *dev, uint8_t flags) +{ + if ((flags & 1) && dev->kbc_devs[0]->c_in) { + /* Disable communication with mouse. */ + dev->p2 |= 0x08; + dev->kbc_devs[1]->inhibit = 1; + /* Send keyboard byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_KBD); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if ((flags & 2) && dev->kbc_devs[1]->c_in) { + /* Disable communication with keyboard. */ + dev->p2 |= 0x40; + dev->kbc_devs[0]->inhibit = 1; + /* Send mouse byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if (dev->status & STAT_IFULL) { + /* Disable communication with keyboard and mouse. */ + dev->p2 |= 0x48; + dev->kbc_devs[0]->inhibit = dev->kbc_devs[1]->inhibit = 1; + kbc_process_ib(dev); + } else + dev->kbc_poll_phase = KBC_WAIT | flags; +} + + +/* Controller processing */ +static void +kbc_process(atkbc_t *dev) +{ + /* If we're waiting for the response from the keyboard or mouse, do nothing + until the device has repsonded back. */ + if (dev->kbc_wait_for_response > 0) { + if (dev->kbc_devs[dev->kbc_wait_for_response - 1]->c_in) + dev->kbc_wait_for_response = 0; + else + return; + } + + if (dev->kbc_send_pending) { + kbc_log(dev, "Sending delayed %02X on channel %i with high status %02X\n", + dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + dev->kbc_send_pending = 0; + } + + /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ + if ((dev->kbc_poll_phase == KBC_RESET) || (dev->kbc_poll_phase >= KBC_WAIT_FOR_NIBF) || + !(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { + case KBC_RESET: + kbc_log(dev, "kbc_process(): Reset loop()\n"); + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { + (void) kbc_process_cmd(dev, 1); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } + } + break; + case KBC_MAIN_LOOP: + if (dev->status & STAT_IFULL) { + kbc_log(dev, "kbc_process(): Main loop, IBF full, process\n"); + kbc_process_ib(dev); + } else + kbc_main_loop_scan(dev); + break; + case KBC_SCAN_KBD: + case KBC_SCAN_MOUSE: + case KBC_SCAN_BOTH: + kbc_log(dev, "kbc_process(): Scan: Phase %i\n", dev->kbc_poll_phase); + kbc_wait(dev, dev->kbc_poll_phase & 3); + break; + case KBC_WAIT_FOR_NOBF: + kbc_log(dev, "kbc_process(): Waiting for !OBF\n"); + + if (dev->status & STAT_IFULL) { + /* Host writing a command aborts the current command. */ + (void) !kbc_reset_cmd(dev); + + /* Process the input buffer. */ + kbc_process_ib(dev); + } else if (!dev->status & STAT_OFULL) { + /* Not aborted and OBF cleared - process command. */ + kbc_log(dev, " Continuing commmand\n"); + + if (kbc_process_cmd(dev, 0)) + return; + } + break; + case KBC_WAIT_FOR_IBF: + kbc_log(dev, "kbc_process(): Waiting for IBF\n"); + + if (dev->status & STAT_IFULL) { + /* IBF, process if port 60h, otherwise abort the current command. */ + dev->status &= ~STAT_IFULL; + + if (!kbc_reset_cmd(dev)) + kbc_log(dev, " Continuing commmand\n"); + + /* Process command. */ + if (kbc_process_cmd(dev, 0)) + return; + } + break; + default: + kbc_log(dev, "kbc_process(): Invalid phase %i\n", dev->kbc_poll_phase); + break; + } +} + + +static void +kbd_poll(void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t i; + + if (dev == NULL) + return; + + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + + /* Device processing */ + for (i = 0; i < 2; i++) { + if (dev->kbc_devs[i] && dev->kbd_devs[i]->priv && dev->kbd_devs[i]->process) + dev->kbc_devs[i]->process(dev->kbc_devs[i]->priv); + } + + /* Controller processing */ + kbc_process(dev); +} + + +static void +pulse_poll(void *priv) +{ + atkbc_t *dev = (atkbc_t *)priv; + + kbc_log(dev, "pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); + write_output(dev, dev->p2 | dev->old_p2); +} + + +static uint8_t +write64_generic(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + uint8_t current_drive, fixed_bits; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + + switch (val) { + case 0xa4: /* check if password installed */ + if (dev->flags & KBC_FLAG_PS2) { + kbc_log(dev, "Check if password installed\n"); + kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); + return 0; + } + break; + + case 0xa5: /* load security */ + if (dev->flags & KBC_FLAG_PS2) { + kbc_log(dev, "Load security\n"); + dev->kbc_in = 1; + return 0; + } + break; + + case 0xa7: /* disable mouse port */ + if (dev->flags & KBC_FLAG_PS2) { + kbc_log(dev, "Disable mouse port\n"); + return 0; + } + break; + + case 0xa8: /*Enable mouse port*/ + if (dev->flags & KBC_FLAG_PS2) { + kbc_log(dev, "Enable mouse port\n"); + return 0; + } + break; + + case 0xa9: /*Test mouse port*/ + kbc_log(dev, "Test mouse port\n"); + if (dev->flags & KBC_FLAG_PS2) { + /* No error, this is testing the channel 2 interface. */ + kbc_transmit(dev, 0x00); + return 0; + } + break; + + case 0xaf: /* read keyboard version */ + kbc_log(dev, "Read keyboard version\n"); + kbc_transmit(dev, 0x00); + return 0; + + case 0xc0: /* read input port */ + /* IBM PS/1: + Bit 2 and 4 ignored (we return always 0), + Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". + Intel AMI: + Bit 2 ignored (we return always 1), + Bit 4 must be 1, + Bit 6 must be 1 or else error in SMM. + Acer: + Bit 2 must be 0, + Bit 4 must be 0, + Bit 6 ignored. + P6RP4: + Bit 2 must be 1 or CMOS setup is disabled. */ + kbc_log(dev, "Read input port\n"); + fixed_bits = 4; + /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ + if (kbc_ven == KBC_VEN_INTEL_AMI) + fixed_bits |= 0x40; + if (kbc_ven == KBC_VEN_IBM_PS1) { + current_drive = fdc_get_current_drive(); + kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + } else if (kbc_ven == KBC_VEN_NCR) { + /* switch settings + * bit 7: keyboard disable + * bit 6: display type (0 color, 1 mono) + * bit 5: power-on default speed (0 high, 1 low) + * bit 4: sense RAM size (0 unsupported, 1 512k on system board) + * bit 3: coprocessor detect + * bit 2: unused + * bit 1: high/auto speed + * bit 0: dma mode + */ + kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + } else { + if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); + else + kbc_transmit(dev, dev->p1 | fixed_bits); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + } + return 0; + + case 0xd3: /* write mouse output buffer */ + if (dev->flags & KBC_FLAG_PS2) { + kbc_log(dev, "Write mouse output buffer\n"); + dev->kbc_in = 1; + return 0; + } + break; + + case 0xd4: /* write to mouse */ + kbc_log(dev, "Write to mouse\n"); + dev->kbc_in = 1; + return 0; + + case 0xf0 ... 0xff: + kbc_log(dev, "Pulse %01X\n", val & 0x0f); + pulse_output(dev, val & 0x0f); + return 0; + } + + kbc_log(dev, "Bad command %02X\n", val); + return 1; +} + + +static uint8_t +write60_ami(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + uint16_t index = 0x00c0; + + switch(dev->kbc_cmd) { + /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ + case 0x40 ... 0x5f: + kbc_log(dev, "AMI - Alias write to %08X\n", dev->kbc_cmd); + if (dev->kbc_cmd == 0x40) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + return 0; + + case 0xaf: /* set extended controller RAM */ + kbc_log(dev, "AMI - Set extended controller RAM, input phase %i\n", dev->secr_phase); + if (dev->secr_phase == 0) { + dev->mem_index = val; + dev->kbc_in = 1; + dev->secr_phase++; + } else if (dev->secr_phase == 1) { + if (dev->mem_index == 0x20) + write_cmd(dev, val); + else + dev->mem[dev->mem_index] = val; + dev->secr_phase = 0; + } + return 0; + + case 0xb8: + kbc_log(dev, "AMIKey-3 - Memory index %02X\n", val); + dev->mem_index = val; + return 0; + + case 0xbb: + kbc_log(dev, "AMIKey-3 - write %02X to memory index %02X\n", val, dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + dev->mem[index + dev->mem_index] = val; + } else if (dev->mem_index == 0x60) + write_cmd(dev, val); + else if (dev->mem_index == 0x42) + dev->status = val; + else if (dev->mem_index >= 0x40) + dev->mem[dev->mem_index - 0x40] = val; + else + dev->mem_int[dev->mem_index] = val; + return 0; + + case 0xbd: + kbc_log(dev, "AMIKey-3 - write %02X to config index %02X\n", val, dev->mem_index); + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + dev->status = val; + break; + case 0x01: /* Password_ptr */ + dev->mem[0x1c] = val; + break; + case 0x02: /* Wakeup_Tsk_Reg */ + dev->mem[0x1e] = val; + break; + case 0x03: /* CCB */ + write_cmd(dev, val); + break; + case 0x04: /* Debounce_time */ + dev->mem[0x4d] = val; + break; + case 0x05: /* Pulse_Width */ + dev->mem[0x4e] = val; + break; + case 0x06: /* Pk_sel_byte */ + dev->mem[0x4c] = val; + break; + case 0x07: /* Func_Tsk_Reg */ + dev->mem[0x7e] = val; + break; + case 0x08: /* TypematicRate */ + dev->mem[0x80] = val; + break; + case 0x09: /* Led_Flag_Byte */ + dev->mem[0x81] = val; + break; + case 0x0a: /* Kbms_Command_St */ + dev->mem[0x87] = val; + break; + case 0x0b: /* Delay_Count_Byte */ + dev->mem[0x86] = val; + break; + case 0x0c: /* KBC_Flags */ + dev->mem[0x9b] = val; + break; + case 0x0d: /* SCODE_HK1 */ + dev->mem[0x50] = val; + break; + case 0x0e: /* SCODE_HK2 */ + dev->mem[0x51] = val; + break; + case 0x0f: /* SCODE_HK3 */ + dev->mem[0x52] = val; + break; + case 0x10: /* SCODE_HK4 */ + dev->mem[0x53] = val; + break; + case 0x11: /* SCODE_HK5 */ + dev->mem[0x54] = val; + break; + case 0x12: /* SCODE_HK6 */ + dev->mem[0x55] = val; + break; + case 0x13: /* TASK_HK1 */ + dev->mem[0x56] = val; + break; + case 0x14: /* TASK_HK2 */ + dev->mem[0x57] = val; + break; + case 0x15: /* TASK_HK3 */ + dev->mem[0x58] = val; + break; + case 0x16: /* TASK_HK4 */ + dev->mem[0x59] = val; + break; + case 0x17: /* TASK_HK5 */ + dev->mem[0x5a] = val; + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + dev->mem[0x5b] = val; + break; + case 0x19: /* Batt_Alarm_Reg1 */ + dev->mem[0x5c] = val; + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + dev->mem[0x5d] = val; + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + dev->mem[0x5e] = val; + break; + case 0x1c: /* Kbc_State1 */ + dev->mem[0x9d] = val; + break; + case 0x1d: /* Aux_Config */ + dev->mem[0x75] = val; + break; + case 0x1e: /* Kbc_State3 */ + dev->mem[0x73] = val; + break; + } + return 0; + + case 0xc1: /* write input port */ + kbc_log(dev, "AMI MegaKey - write %02X to input port\n", val); + dev->p1 = val; + return 0; + + case 0xcb: /* set keyboard mode */ + kbc_log(dev, "AMI - Set keyboard mode\n"); + return 0; + } + + return 1; +} + + +static uint8_t +write64_ami(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + uint16_t index = 0x00c0; + + switch (val) { + case 0x00 ... 0x1f: + kbc_log(dev, "AMI - Alias read from %08X\n", val); + kbc_transmit(dev, dev->mem[val + 0x20]); + return 0; + + case 0x40 ... 0x5f: + kbc_log(dev, "AMI - Alias write to %08X\n", dev->kbc_cmd); + dev->kbc_in = 1; + return 0; + + case 0xa0: /* copyright message */ + kbc_log(dev, "AMI - Get copyright message\n"); + kbc_transmit(dev, ami_copr[0]); + dev->kbc_phase = 1; + return 0; + + case 0xa1: /* get controller version */ + kbc_log(dev, "AMI - Get controller version\n"); + // kbc_transmit(dev, 'H'); + kbc_transmit(dev, '5'); + return 0; + + case 0xa2: /* clear keyboard controller lines P22/P23 */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Clear KBC lines P22 and P23\n"); + write_output(dev, dev->p2 & 0xf3); + kbc_transmit(dev, 0x00); + return 0; + } + break; + + case 0xa3: /* set keyboard controller lines P22/P23 */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Set KBC lines P22 and P23\n"); + write_output(dev, dev->p2 | 0x0c); + kbc_transmit(dev, 0x00); + return 0; + } + break; + + case 0xa4: /* write clock = low */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Write clock = low\n"); + dev->ami_stat &= 0xfe; + return 0; + } + break; + + case 0xa5: /* write clock = high */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Write clock = high\n"); + dev->ami_stat |= 0x01; + return 0; + } + break; + + case 0xa6: /* read clock */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Read clock\n"); + kbc_transmit(dev, !!(dev->ami_stat & 1)); + return 0; + } + break; + + case 0xa7: /* write cache bad */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Write cache bad\n"); + dev->ami_stat &= 0xfd; + return 0; + } + break; + + case 0xa8: /* write cache good */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Write cache good\n"); + dev->ami_stat |= 0x02; + return 0; + } + break; + + case 0xa9: /* read cache */ + if (!(dev->flags & KBC_FLAG_PS2)) { + kbc_log(dev, "AMI - Read cache\n"); + kbc_transmit(dev, !!(dev->ami_stat & 2)); + return 0; + } + break; + + case 0xaf: /* set extended controller RAM */ + kbc_log(dev, "AMI - Set extended controller RAM\n"); + dev->kbc_in = 1; + return 0; + + case 0xb0 ... 0xb3: + /* set KBC lines P10-P13 (input port bits 0-3) low */ + kbc_log(dev, "AMI - Set KBC lines P10-P13 (input port bits 0-3) low\n"); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { + dev->p1 &= ~(1 << (val & 0x03)); + } + kbc_transmit(dev, 0x00); + return 0; + + case 0xb4: case 0xb5: + /* set KBC lines P22-P23 (output port bits 2-3) low */ + kbc_log(dev, "AMI - Set KBC lines P22-P23 (output port bits 2-3) low\n"); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 & ~(4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; + +#if 0 + case 0xb8 ... 0xbb: +#else + case 0xb9: +#endif + /* set KBC lines P10-P13 (input port bits 0-3) high */ + kbc_log(dev, "AMI - Set KBC lines P10-P13 (input port bits 0-3) high\n"); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + kbc_transmit(dev, 0x00); + } + return 0; + + case 0xb8: + kbc_log(dev, "AMIKey-3 - memory index\n"); + dev->kbc_in = 1; + return 0; + + case 0xba: + kbc_log(dev, "AMIKey-3 - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + kbc_transmit(dev, dev->mem[index + dev->mem_index]); + } else if (dev->mem_index == 0x42) + kbc_transmit(dev, dev->status); + else if (dev->mem_index >= 0x40) + kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); + else + kbc_transmit(dev, dev->mem_int[dev->mem_index]); + return 0; + + case 0xbb: + kbc_log(dev, "AMIKey-3 - write to memory index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + +#if 0 + case 0xbc: case 0xbd: + /* set KBC lines P22-P23 (output port bits 2-3) high */ + kbc_log(dev, "AMI - Set KBC lines P22-P23 (output port bits 2-3) high\n"); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 | (4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; +#endif + + case 0xbc: + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + kbc_transmit(dev, dev->status); + break; + case 0x01: /* Password_ptr */ + kbc_transmit(dev, dev->mem[0x1c]); + break; + case 0x02: /* Wakeup_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x1e]); + break; + case 0x03: /* CCB */ + kbc_transmit(dev, dev->mem[0x20]); + break; + case 0x04: /* Debounce_time */ + kbc_transmit(dev, dev->mem[0x4d]); + break; + case 0x05: /* Pulse_Width */ + kbc_transmit(dev, dev->mem[0x4e]); + break; + case 0x06: /* Pk_sel_byte */ + kbc_transmit(dev, dev->mem[0x4c]); + break; + case 0x07: /* Func_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x7e]); + break; + case 0x08: /* TypematicRate */ + kbc_transmit(dev, dev->mem[0x80]); + break; + case 0x09: /* Led_Flag_Byte */ + kbc_transmit(dev, dev->mem[0x81]); + break; + case 0x0a: /* Kbms_Command_St */ + kbc_transmit(dev, dev->mem[0x87]); + break; + case 0x0b: /* Delay_Count_Byte */ + kbc_transmit(dev, dev->mem[0x86]); + break; + case 0x0c: /* KBC_Flags */ + kbc_transmit(dev, dev->mem[0x9b]); + break; + case 0x0d: /* SCODE_HK1 */ + kbc_transmit(dev, dev->mem[0x50]); + break; + case 0x0e: /* SCODE_HK2 */ + kbc_transmit(dev, dev->mem[0x51]); + break; + case 0x0f: /* SCODE_HK3 */ + kbc_transmit(dev, dev->mem[0x52]); + break; + case 0x10: /* SCODE_HK4 */ + kbc_transmit(dev, dev->mem[0x53]); + break; + case 0x11: /* SCODE_HK5 */ + kbc_transmit(dev, dev->mem[0x54]); + break; + case 0x12: /* SCODE_HK6 */ + kbc_transmit(dev, dev->mem[0x55]); + break; + case 0x13: /* TASK_HK1 */ + kbc_transmit(dev, dev->mem[0x56]); + break; + case 0x14: /* TASK_HK2 */ + kbc_transmit(dev, dev->mem[0x57]); + break; + case 0x15: /* TASK_HK3 */ + kbc_transmit(dev, dev->mem[0x58]); + break; + case 0x16: /* TASK_HK4 */ + kbc_transmit(dev, dev->mem[0x59]); + break; + case 0x17: /* TASK_HK5 */ + kbc_transmit(dev, dev->mem[0x5a]); + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + kbc_transmit(dev, dev->mem[0x5b]); + break; + case 0x19: /* Batt_Alarm_Reg1 */ + kbc_transmit(dev, dev->mem[0x5c]); + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + kbc_transmit(dev, dev->mem[0x5d]); + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x5e]); + break; + case 0x1c: /* Kbc_State1 */ + kbc_transmit(dev, dev->mem[0x9d]); + break; + case 0x1d: /* Aux_Config */ + kbc_transmit(dev, dev->mem[0x75]); + break; + case 0x1e: /* Kbc_State3 */ + kbc_transmit(dev, dev->mem[0x73]); + break; + default: + kbc_transmit(dev, 0x00); + break; + } + kbc_log(dev, "AMIKey-3 - read from config index %02X\n", dev->mem_index); + return 0; + + case 0xbd: + kbc_log(dev, "AMIKey-3 - write to config index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + + case 0xc1: /* write input port */ + kbc_log(dev, "AMIKey-3 - write input port\n"); + dev->kbc_in = 1; + return 0; + + case 0xc8: case 0xc9: + /* + * (un)block KBC lines P22/P23 + * (allow command D1 to change bits 2/3 of the output port) + */ + kbc_log(dev, "AMI - %slock KBC lines P22 and P23\n", (val & 1) ? "B" : "Unb"); + dev->p2_locked = (val & 1); + return 0; + + case 0xef: /* ??? - sent by AMI486 */ + kbc_log(dev, "??? - sent by AMI486\n"); + return 0; + } + + return write64_generic(dev, val); +} + + +static uint8_t +write64_ibm_mca(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch (val) { + case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ + kbc_log(dev, "Copy bits 0 to 3 of input port to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); + return 0; + + case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ + kbc_log(dev, "Copy bits 4 to 7 of input port to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); + return 0; + + case 0xaf: + kbc_log(dev, "Bad KBC command AF\n"); + return 1; + + case 0xf0 ... 0xff: + kbc_log(dev, "Pulse: %01X\n", (val & 0x03) | 0x0c); + pulse_output(dev, (val & 0x03) | 0x0c); + return 0; + } + + return write64_generic(dev, val); +} + + +static uint8_t +write60_quadtel(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch(dev->kbc_cmd) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbc_log(dev, "??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + + +static uint8_t +write64_olivetti(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch (val) { + /* This appears to be a clone of "Read input port", in which case, the bis would be: + 7: M290 (AT KBC): + Keyboard lock (1 = unlocked, 0 = locked); + M300 (PS/2 KBC): + Bus expansion board present (1 = present, 0 = not present); + 6: Usually: + Display (1 = MDA, 0 = CGA, but can have its polarity inverted); + 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); + 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); + 3: Fast Ram check (if inactive keyboard works erratically); + 2: Keyboard fuse present + This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; + 1: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Mouse data in; + 0: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Key data in. + */ + case 0x80: /* Olivetti-specific command */ + /* + * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) + * bits 4-6: ??? + * bit 3: fast ram check (if inactive keyboard works erratically) + * bit 2: keyboard fuse present + * bits 0-1: ??? + */ + kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); + return 0; + } + + return write64_generic(dev, val); +} + + +static uint8_t +write64_quadtel(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch (val) { + case 0xaf: + kbc_log(dev, "Bad KBC command AF\n"); + return 1; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbc_log(dev, "??? - sent by MegaPC BIOS\n"); + dev->kbc_in = 1; + return 0; + } + + return write64_generic(dev, val); +} + + +static uint8_t +write60_toshiba(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch(dev->kbc_cmd) { + case 0xb6: /* T3100e - set color/mono switch */ + kbc_log(dev, "T3100e - Set color/mono switch\n"); + t3100e_mono_set(val); + return 0; + } + + return 1; +} + + +static uint8_t +write64_toshiba(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *)priv; + + switch (val) { + case 0xaf: + kbc_log(dev, "Bad KBC command AF\n"); + return 1; + + case 0xb0: /* T3100e: Turbo on */ + kbc_log(dev, "T3100e: Turbo on\n"); + t3100e_turbo_set(1); + return 0; + + case 0xb1: /* T3100e: Turbo off */ + kbc_log(dev, "T3100e: Turbo off\n"); + t3100e_turbo_set(0); + return 0; + + case 0xb2: /* T3100e: Select external display */ + kbc_log(dev, "T3100e: Select external display\n"); + t3100e_display_set(0x00); + return 0; + + case 0xb3: /* T3100e: Select internal display */ + kcd_log("T3100e: Select internal display\n"); + t3100e_display_set(0x01); + return 0; + + case 0xb4: /* T3100e: Get configuration / status */ + kbc_log(dev, "T3100e: Get configuration / status\n"); + kbc_transmit(dev, t3100e_config_get()); + return 0; + + case 0xb5: /* T3100e: Get colour / mono byte */ + kbc_log(dev, "T3100e: Get colour / mono byte\n"); + kbc_transmit(dev, t3100e_mono_get()); + return 0; + + case 0xb6: /* T3100e: Set colour / mono byte */ + kbc_log(dev, "T3100e: Set colour / mono byte\n"); + dev->kbc_in = 1; + return 0; + + case 0xb7: /* T3100e: Emulate PS/2 keyboard */ + case 0xb8: /* T3100e: Emulate AT keyboard */ + dev->flags &= ~KBC_FLAG_PS2; + if (val == 0xb7) { + kbc_log(dev, "T3100e: Emulate PS/2 keyboard\n"); + dev->flags |= KBC_FLAG_PS2; + } else + kbc_log(dev, "T3100e: Emulate AT keyboard\n"); +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) + log_set_dev_name(dev->kbc_log, (dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); +#endif + return 0; + + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right Alt; on the real + T3100e, these keystrokes could only be generated + using 'Fn'. */ + kbc_log(dev, "T3100e: Read 'Fn' key\n"); + if (keyboard_recv(0xb8) || /* Right Alt */ + keyboard_recv(0x9d)) /* Right Ctrl */ + kbc_transmit(dev, 0x04); + else + kbc_transmit(dev, 0x00); + return 0; + + case 0xbc: /* T3100e: Reset Fn+Key notification */ + kbc_log(dev, "T3100e: Reset Fn+Key notification\n"); + t3100e_notify_set(0x00); + return 0; + + case 0xc0: /*Read input port*/ + kbc_log(dev, "Read input port\n"); + + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + kbc_transmit(dev, dev->p1); + return 0; + + } + + return write64_generic(dev, val); +} + + +static void +kbc_write(uint16_t port, uint8_t val, void *priv) +{ + atkbc_t *dev = (atkbc_t *)priv; + + kbc_log(dev, "[%04X:%08X] write(%04X, %02X)\n", CS, cpu_state.pc, port, val); + + switch (port) { + case 0x60: + dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); + +#if 0 + if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { + dev->status &= ~STAT_IFULL; + write_output(dev, val); + dev->fast_a20_phase = 0; + } +#endif + break; + case 0x64: + dev->status |= (STAT_CD | STAT_IFULL); + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); + +#if 0 + if (val == 0xd1) { + dev->status &= ~STAT_IFULL; + dev->fast_a20_phase = 1; + } else if (val == 0xfe) { + dev->status &= ~STAT_IFULL; + pulse_output(dev, 0x0e); + } else if ((val == 0xad) || (val == 0xae)) { + dev->status &= ~STAT_IFULL; + if (val & 0x01) + dev->mem[0x20] |= 0x10; + else + dev->mem[0x20] &= ~0x10; + } else if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); + } +#endif + break; + } +} + + +static uint8_t +kbc_read(uint16_t port, void *priv) +{ + atkbc_t *dev = (atkbc_t *)priv; + uint8_t ret = 0xff; + + // if (dev->flags & KBC_FLAG_PS2) + // cycles -= ISA_CYCLES(8); + + switch (port) { + case 0x60: + ret = dev->ob; + dev->status &= ~STAT_OFULL; + picintc(dev->last_irq); + dev->last_irq = 0; + break; + + case 0x64: + ret = dev->status; + break; + + default: + kbc_log(dev, "Reading unknown port %02X\n", port); + break; + } + + kbc_log(dev, "[%04X:%08X] read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); + + return(ret); +} + + +static void +kbc_reset(void *priv) +{ + atkbc_t *dev = (atkbc_t *)priv; + int i; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + + dev->status = STAT_UNLOCKED; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; + write_output(dev, 0xcf); + dev->last_irq = 0; + dev->secr_phase = 0; + dev->in = 0; + dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); + + /* Set up the correct Video Type bits. */ + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; + if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) + dev->p1 ^= 0x40; + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + dev->inhibit = ((dev->p1 & 0x80) >> 3); + else + dev->inhibit = 0x10; + kbc_log(dev, "Input port = %02x\n", dev->p1); + + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); + + /* Enable keyboard, disable mouse. */ + set_enable_kbd(dev, 1); + keyboard_scan = 1; + set_enable_mouse(dev, 0); + mouse_scan = 0; + + dev->ob = 0xff; + + sc_or = 0; + + dev->mem[0x31] = 0xfe; +} + + +/* Reset the AT keyboard - this is needed for the PCI TRC and is done + until a better solution is found. */ +void +keyboard_at_reset(void) +{ + kbc_reset(SavedKbd); +} + + +void +kbc_dev_attach(kbc_dev_t *kbc_dev, int channel) +{ + if ((channel < 1) || (channel > 2)) + log_fatal(saved_kbc->log, "Attaching device to invalid channel %i\n", channel); + else { + kbc_log(saved_kbc, "Attaching device to channel %i\n", channel); + saved_kbc->kbc_devs[channel - 1] = kbc_dev; + } +} + + +static void +kbc_close(void *priv) +{ + atkbc_t *dev = (atkbc_t *)priv; + + kbc_reset(dev); + + /* Stop timers. */ + timer_disable(&dev->send_delay_timer); + +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) + log_close(dev->log); +#endif + + free(dev); +} + + +static void * +kbc_init(const device_t *info) +{ + atkbc_t *dev; + + dev = (atkbc_t *)malloc(sizeof(atkbc_t)); + memset(dev, 0x00, sizeof(atkbc_t)); + + dev->flags = info->local; + + video_reset(gfxcard); + dev->kbc_poll_phase = KBC_RESET; + + io_sethandler(0x0060, 1, kbc_read, NULL, NULL, kbc_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbc_read, NULL, NULL, kbc_write, NULL, NULL, dev); + + timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); + +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) + dev->kbc_log = log_open((dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); +#endif + + dev->write60_ven = NULL; + dev->write64_ven = NULL; + + switch(dev->flags & KBC_VEN_MASK) { + case KBC_VEN_ACER: + case KBC_VEN_GENERIC: + case KBC_VEN_NCR: + case KBC_VEN_IBM_PS1: + case KBC_VEN_XI8088: + dev->write64_ven = write64_generic; + break; + + case KBC_VEN_OLIVETTI: + /* The Olivetti controller is a special case - starts directly in the + main loop instead of the reset loop. */ + dev->kbc_poll_phase = KBC_MAIN_LOOP; + dev->write64_ven = write64_olivetti; + break; + + case KBC_VEN_AMI: + case KBC_VEN_INTEL_AMI: + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + + case KBC_VEN_IBM_MCA: + dev->write64_ven = write64_ibm_mca; + break; + + case KBC_VEN_QUADTEL: + dev->write60_ven = write60_quadtel; + dev->write64_ven = write64_quadtel; + break; + + case KBC_VEN_TOSHIBA: + dev->write60_ven = write60_toshiba; + dev->write64_ven = write64_toshiba; + break; + } + + kbc_reset(dev); + + /* Local variable, needed for device attaching. */ + saved_kbc = dev; + + /* Add the actual keyboard. */ + device_add(&keyboard_at_kbd_device); + + return(dev); +} + + +const device_t keyboard_at_device = { + "PC/AT Keyboard", + 0, + KBC_TYPE_ISA | KBC_VEN_GENERIC, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_at_ami_device = { + "PC/AT Keyboard (AMI)", + 0, + KBC_TYPE_ISA | KBC_VEN_AMI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_at_toshiba_device = { + "PC/AT Keyboard (Toshiba)", + 0, + KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_at_olivetti_device = { + "PC/AT Keyboard (Olivetti)", + 0, + KBC_TYPE_ISA | KBC_VEN_OLIVETTI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_at_ncr_device = { + "PC/AT Keyboard (NCR)", + 0, + KBC_TYPE_ISA | KBC_VEN_NCR, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps1_device = { + "PS/2 Keyboard (IBM PS/1)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps1_pci_device = { + "PS/2 Keyboard (IBM PS/1)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_xi8088_device = { + "PS/2 Keyboard (Xi8088)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_XI8088, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_device = { + "PS/2 Keyboard (AMI)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_olivetti_device = { + "PS/2 Keyboard (Olivetti)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_quadtel_device = { + "PS/2 Keyboard (Quadtel/MegaPC)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_pci_device = { + "PS/2 Keyboard", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_intel_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_acer_pci_device = { + "PS/2 Keyboard (Acer 90M002A)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_ACER, + kbc_init, + kbc_close, + kbc_reset, + { NULL }, NULL, NULL, NULL +}; + + +void +keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) +{ +} + + +void +keyboard_at_adddata_mouse(uint8_t val) +{ + return; +} + + +void +keyboard_at_adddata_mouse_direct(uint8_t val) +{ + return; +} + + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + return; +} + + +void +keyboard_at_mouse_reset(void) +{ + return; +} + + +uint8_t +keyboard_at_mouse_pos(void) +{ + return ((mouse_queue_end - mouse_queue_start) & 0xf); +} + + +int +keyboard_at_fixed_channel(void) +{ + return 0x000; +} + + +void +keyboard_at_set_mouse_scan(uint8_t val) +{ + atkbc_t *dev = SavedKbd; + uint8_t temp_mouse_scan = val ? 1 : 0; + + if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) + return; + + set_enable_mouse(dev, val ? 1 : 0); + + kbc_log(dev, "Mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +} + + +uint8_t +keyboard_at_get_mouse_scan(void) +{ + atkbc_t *dev = SavedKbd; + + return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); +} + + +void +keyboard_at_set_a20_key(int state) +{ + atkbc_t *dev = SavedKbd; + + write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); +} + + +void +keyboard_at_set_mode(int ps2) +{ + atkbc_t *dev = SavedKbd; + + if (ps2) + dev->flags |= KBC_FLAG_PS2; + else + dev->flags &= ~KBC_FLAG_PS2; +} diff --git a/src/device/kbd_at.c b/src/device/kbd_at.c new file mode 100644 index 000000000..f24177d37 --- /dev/null +++ b/src/device/kbd_at.c @@ -0,0 +1,1162 @@ +/* + * 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. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/log.h> +#include <86box/keyboard.h> + + +// static uint8_t key_queue[16]; +// static int key_queue_start = 0, key_queue_end = 0; +// static uint8_t kbd_last_scan_code; + +typedef struct { + uint8_t in, cmd, in_cmd, state, last_byte; + + uint8_t queue[16]; + + uint16_t phase; + + int quueue_start, queue_end; + + void * log; + + kbc_dev_t kd; +} atkbd_t; + + +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbd_cmd_process(atkbd_t *dev); + + +/* bit 0 = repeat, bit 1 = makes break code? */ +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; + + +static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK + + +#ifdef USE_SET1 +static const scancode scancode_set1[512] = { + { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ + { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/ + { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/ + { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/ + { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/ + { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/ + { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/ + { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/ + { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/ + { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/ + { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/ + { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/ + { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/ + { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/ + { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/ + { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/ + { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/ + { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/ + { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/ + { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/ + { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/ + { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/ + { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/ + { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/ + { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/ + { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/ + { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/ + { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/ + { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/ + { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/ + { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/ + { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/ + + { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/ + { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/ + { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/ + { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/ + { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/ + { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/ + { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/ + { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/ + { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/ + { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/ + { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/ + { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/ + { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/ + { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/ + { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/ + { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/ + { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/ + { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/ + { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/ + { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/ + { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/ + { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/ + { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/ + { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/ + { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/ + { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/ + { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/ + { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/ + { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/ + { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/ + + { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/ + { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/ + { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/ + { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/ + { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/ + { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/ + { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/ + { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/ + { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/ + { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/ + { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/ + { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/ + { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/ + { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/ + { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/ + { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/ + { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/ + { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/ + { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/ + { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/ + { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/ + { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/ + { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/ + { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/ + { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/ + { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/ +}; +#endif + +static const scancode scancode_set2[512] = { + { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/ + { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/ + { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/ + { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/ + { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/ + { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/ + { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/ + { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/ + { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/ + { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/ + { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/ + { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/ + { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/ + + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ + + { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/ + { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/ + { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/ + { {0xe0,0x72,0},{0xe0,0xF0,0x72,0} }, { {0xe0,0x7A,0},{0xe0,0xF0,0x7A,0} }, { {0xe0,0x70,0},{0xe0,0xF0,0x70,0} }, { {0xe0,0x71,0},{0xe0,0xF0,0x71,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/ + { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ +}; + +static const scancode scancode_set3[512] = { + { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/ + { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/ + { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/ + { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/ + { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/ + { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/ + { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/ + { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/ + { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/ + { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/ + { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/ + + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ + + { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/ + { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/ + { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/ + { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/ + { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ +}; + + +static void add_data_kbd(uint16_t val); + + +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) +int kbd_at_do_log = ENABLE_KBD_AT_LOG; + + +static void +kbd_log(atkbd_t *dev, const char *fmt, ...) +{ + va_list ap; + + if ((dev == NULL) || (dev->log == NULL)) + return; + + if (kbd_at_do_log) { + va_start(ap, fmt); + log_out(dev->log, fmt, ap); + va_end(ap); + } +} +#else +#define kbd_log(dev, fmt, ...) +#endif + + +/* TODO: Get rid of keyboard_mode entirely - keyboard.c just need to know which scan codes to + send break codes for and which to repeat. + The break code stuff, though, might also be doable on the AT keyboard side, if F0 F0 + is never sent. */ +static void +set_scancode_map(atkbd_t *dev) +{ + switch (keyboard_mode & 3) { +#ifdef USE_SET1 + case 1: + default: + keyboard_set_table(scancode_set1); + break; +#else + default: +#endif + case 2: + keyboard_set_table(scancode_set2); + break; + + case 3: + keyboard_set_table(scancode_set3); + break; + } + + if (keyboard_mode & 0x20) +#ifdef USE_SET1 + keyboard_set_table(scancode_set1); +#else + keyboard_set_table(scancode_set2); +#endif +} + + + +/* TODO: Move the queues to the device. */ +static void +kbc_queue_reset(uint8_t channel) +{ + if (channel == 2) { + mouse_queue_start = mouse_queue_end = 0; + memset(mouse_queue, 0x00, sizeof(mouse_queue)); + } else if (channel == 1) { + dev->queue_start = dev->queue_end = 0; + memset(dev->queue, 0x00, sizeof(dev->queue)); + } +} + + +static void +add_data_kbd_queue(atkbd_t *dev, uint8_t val) +{ + if (!keyboard_scan || (dev->queue_end >= 16)) { + kbd_log(dev, "Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (dev->queue_end >= 16)); + return; + } + + kbd_log(dev, "dev->queue[%02X] = %02X;\n", dev->queue_end, val); + dev->queue[dev->queue_end] = val; + dev->queue_end = (dev->queue_end + 1) & 0xf; +} + + +static void +kbd_send_to_host(atkbd_t *dev, uint8_t val) +{ + dev->kd.c_in = 1; + dev->kd.c_data = val; + + dev->last_byte = val; +} + + +static void +kbd_reset(atkbd_t *dev) +{ + kbc_queue_reset(1); + dev->kd.c_in = 0x00; + /* TODO: Move this to the keyboard struct. */ + dev->last_byte = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->phase = 0; + dev->in = 0; + + memset(keyboard_set3_flags, 0, 512); +} + + +static void +kbd_command(atkbd_t *dev) +{ + uint8_t val = dev->kd.d_data; + + if ((dev->phase > 0) && (dev->cmd == 0xff)) { + dev->phase++; + if (dev->phase == RESET_DELAY_TIME) { + kbd_send_to_host(dev, 0xaa); + dev->phase = 0; + dev->cmd = 0x00; + } + return; + } + + if (dev->phase == 2) { + dev->phase = 0; + + switch (dev->cmd) { + case 0xf2: + kbd_send_to_host(dev, 0x83); + break; + default: + log_fatal(dev->log, "Invalid command for phase 2: %02X\n", dev->cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->phase == 0) + dev->cmd = 0x00; + return; + } else if (dev->phase == 1) { + dev->phase = 0; + + switch (dev->cmd) { + case 0xf0: + kbd_log(dev, "Get scan code set: %02X\n", keyboard_mode & 3); + kbd_send_to_host(dev, keyboard_mode & 3); + break; + case 0xf2: + kbd_send_to_host(dev, 0xab); + dev->phase = 2; + break; + default: + log_fatal(dev->log, "Invalid command for phase 1: %02X\n", dev->cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->phase == 0) + dev->cmd = 0x00; + return; + } + + if (dev->in && (val < 0xed)) { + dev->in = 0; + dev->phase = 0; + + switch (dev->cmd) { + case 0xed: /* set/reset LEDs */ + kbd_log(dev, "Set LEDs: %02X\n", val); + kbd_send_to_host(dev, 0xfa); + break; + + case 0xf0: /* get/set scancode set */ + kbd_send_to_host(dev, 0xfa); + if (val == 0) + dev->phase = 1; + else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log(dev, "Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_send_to_host(dev, 0xfa); + break; + + default: + kbd_log(dev, "Bad keyboard 0060 write %02X command %02X\n", val, dev->cmd); + kbd_send_to_host(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + if (dev->phase == 0) + dev->cmd = 0x00; + } else { + /* No keyboard command in progress. */ + dev->in = 0; + dev->cmd = 0x00; + dev->phase = 0; + + switch (val) { + case 0x00: + kbd_log(dev, "Command 00\n"); + kbd_send_to_host(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log(dev, "Command 05 (NT 4.0)\n"); + kbd_send_to_host(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log(dev, "Set/reset LEDs\n"); + kbd_send_to_host(dev, 0xfa); + + dev->in = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log(dev, "Diagnostic echo\n"); + kbd_send_to_host(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log(dev, "NOP (reserved for future use)\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log(dev, "Get/set scan code set\n"); + kbd_send_to_host(dev, 0xfa); + dev->in = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log(dev, "Read keyboard ID\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + kbd_send_to_host(dev, 0xfa); + dev->phase = 1; + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log(dev, "Set typematic rate/delay\n"); + kbd_send_to_host(dev, 0xfa); + dev->in = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log(dev, "Enable keyboard\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log(dev, "Set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log(dev, "val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + val, keyboard_scan, dev->mem[0x20]); + kbd_send_to_host(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log(dev, "Set all keys to repeat\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log(dev, "Set all keys to give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log(dev, "Set all keys to give make codes only\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log(dev, "Set all keys to repeat and give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log(dev, "Reset last scan code\n"); + kbd_send_to_host(dev, dev->last_byte); + break; + + case 0xff: /* reset */ + kbd_log(dev, "Reset\n"); + kbd_reset(dev); + kbd_send_to_host(dev, 0xfa); + dev->phase = 1; + break; + + default: + kbd_log(dev, "Bad keyboard command %02X\n", val); + kbd_send_to_host(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if ((dev->in == 1) || (dev->phase > 0)) + dev->cmd = val; + } +} + + +static void +kbd_do_command(atkbd_t *dev) +{ + kbd_command(dev); + if (dev->kd.d_in) + dev->state = KBD_CMD_PROCESS; + else if ((dev->phase == 0) && !dev->in) { + dev->in_cmd = 0; + if (dev->kd.d_data != 0xf5) + keyboard_scan = 1; + dev->state = KBD_MAIN_LOOP; + } else { + keyboard_scan = 0; + dev->in_cmd = 1; + dev->state = KBD_CMD_PROCESS; + } +} + + +static void +kbd_nack(atkbd_t *dev) +{ + kbd_send_to_host(dev, 0xfe); + dev->state = KBD_MAIN_LOOP; +} + + +static void +kbd_main_loop(atkbd_t *dev) +{ + uint8_t scan = !dev->kd.inhibit && keyboard_scan; + + if (dev->kd.d_in) { + dev->kd.d_in = 0; + kbd_cmd_process(dev); + } else if (scan && (dev->queue_start != dev->queue_end)) { + /* Scan here. */ + kbd_log(dev, "Get %02X from FIFO\n", dev->queue[dev->queue_start]); + kbd_send_to_host(dev, dev->queue[dev->queue_start]); + dev->queue_start = (dev->queue_start + 1) & 0xf; + } +} + + +static void +kbd_cmd_process(atkbd_t *dev) +{ + uint8_t written = dev->kd.d_in; + + /* We want data, nothing has been written yet, return. */ + if (dev->in && !dev->kd.d_in) + return; + + dev->kd.d_in = 0; + + if (!written && !keyboard_scan && dev->in_cmd && (dev->phase > 0)) { + kbd_log(dev, "Keyboard not written, not scanning, in command, and phase > 0\n"); + kbd_do_command(dev); + } else if (dev->kd.d_data == 0xfe) { + kbd_log(dev, "Send last byte: %02X\n", dev->last_byte); + kbd_send_to_host(dev, dev->last_byte); + dev->state = KBD_MAIN_LOOP; + } else if (dev->kd.d_data == 0xee) { + kbd_log(dev, "Diagnostic echo: EE\n"); + kbd_send_to_host(dev, 0xee); + dev->state = KBD_MAIN_LOOP; + } else if (dev->kd.d_data >= 0xed) { + kbd_log(dev, "Command %02X\n", dev->kd.d_data); + if (!keyboard_scan && dev->in_cmd && (dev->cmd == 0xed)) { + kbd_log(dev, "Not scanning, in command, old command is ED\n"); + keyboard_scan = 1; + dev->in_cmd = 0; + } + kbd_do_command(dev); + } else { + if (!keyboard_scan && dev->in_cmd) { + if ((dev->cmd == 0xf3) && (dev->kd.d_data & 0x80)) { + kbd_log(dev, "Command F3 data %02X has bit 7 set\n", dev->kd.d_data); + kbd_nack(dev); + } else { + kbd_log(dev, "Command %02X data %02X\n", dev->cmd, dev->kd.d_data); + kbd_do_command(dev); + } + } else { + kbd_log(dev, "Scanning or not in command, NACK\n"); + kbd_nack(dev); + } + } +} + + +/* Keyboard processing */ +static void +kbd_process(atkbd_t *dev) +{ + /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ + if (dev->kd.c_in && dev->kd.d_in) + dev->kd.c_in = 0; + + /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ + if (!dev->kd.c_in) switch (dev->state) { + case KBD_MAIN_LOOP: + kbd_main_loop(dev); + break; + case KBD_CMD_PROCESS: + kbd_cmd_process(dev); + break; + } +} + + +static void +add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) +{ + int i; + + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, val[i]); +} + + +static void +add_data_kbd(uint16_t val) +{ + atkbd_t *dev = SavedKbd; + uint8_t fake_shift[4]; + uint8_t num_lock = 0, shift_states = 0; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if (dev->in || (dev->phase > 0)) + return; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && + (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) + t3100e_notify_set((val + 2) & 0x0f); + + switch(val) { + case FAKE_LSHIFT_ON: + kbd_log(dev, "Fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbd_log(dev, "N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + kbd_log(dev, shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + case FAKE_LSHIFT_OFF: + kbd_log(dev, "Fake left shift off, scan code: "); + if (num_lock) { + if (shift_states) { + kbd_log(dev, "N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x36; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x59; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + kbd_log(dev, shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + default: + add_data_kbd_queue(dev, val); + break; + } +} + + +static void +kbd_close(void *priv) +{ + atkbd_t *dev = (atkbd_t *)priv; + + kbd_reset(dev); + + keyboard_scan = 0; + keyboard_send = NULL; + + /* Disable the scancode maps. */ + keyboard_set_table(NULL); + +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) + log_close(dev->log); +#endif + + kbc_dev_attach(NULL, 1); + + SavedKbd = NULL; + free(dev); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *dev; + + dev = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(dev, 0x00, sizeof(atkbd_t)); + + kbc_dev_attach(&(dev->kd), 1); + + kbd_send_to_host(dev, 0xaa); + + keyboard_send = add_data_kbd; + +#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) + dev->kbd_log = log_open("AT KBD"); +#endif + + kbd_reset(dev); + + /* We need this, sadly. */ + SavedKbd = dev; + + return(dev); +} + + +const device_t keyboard_at_kbd_device = { + "PC/AT Keyboard (Actual keyboard!)", + 0, + 0, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index c3fb5b93e..92690db1f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,9 +57,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - -#define RESET_DELAY_TIME (100 * 10) /* 600ms */ +#define RESET_DELAY_TIME 1000 /* 100 ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -74,49 +72,136 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ -#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ -#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x03 +#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ +/* This only differs in that translation is forced off. */ +#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x07 +#define KBC_FLAG_PS2 0x04 + +/* We need to redefine this: + Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 + for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling + controller mode, normally set according to the flags, but togglable on + AMIKey: + 0000 0000 0x00 IBM, AT + 0000 0001 0x01 MR + 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 + 0001 0000 0x10 Olivetti + 0010 0000 0x20 Toshiba + 0011 0000 0x30 Quadtel + 0100 0000 0x40 Phoenix MultiKey/42 + 0101 0000 0x50 AMI KF + 0101 0001 0x51 AMI KH + 0101 0010 0x52 AMIKey + 0101 0011 0x53 AMIKey-2 + 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) + 0110 0000 0x60 Award + 0110 0001 0x61 Award 286 (has some AMI commands apparently) + 0111 0000 0x70 Siemens +*/ + +/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -#define KBC_VEN_AMI 0x04 +/* All commands are standard PS/2 */ #define KBC_VEN_IBM_MCA 0x08 -#define KBC_VEN_QUADTEL 0x0c -#define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_MASK 0x3c +/* Standard IBM commands, differs in input port bits */ +#define KBC_VEN_IBM_PS1 0x10 +/* Olivetti - proprietary commands and port 62h with switches + readout */ +#define KBC_VEN_OLIVETTI 0x20 +/* Toshiba T3100e - has a bunch of proprietary commands, also sets + IFULL on command AA */ +#define KBC_VEN_TOSHIBA 0x28 +/* Standard IBM commands, uses input port as a switches readout */ +#define KBC_VEN_NCR 0x30 +/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the + polarity of the video type bit in the input port is inverted */ +#define KBC_VEN_XI8088 0x38 +/* QuadtelKey - currently guesswork */ +#define KBC_VEN_QUADTEL 0x40 +/* Phoenix MultiKey/42 - not yet implemented */ +#define KBC_VEN_PHOENIX 0x48 +/* Generic commands, XI8088-like input port handling of video type, + maybe we just need a flag for that? */ +#define KBC_VEN_ACER 0x50 +/* AMI KF/KH/AMIKey/AMIKey-2 */ +#define KBC_VEN_AMI 0xf0 +/* Standard AMI commands, differs in input port bits */ +#define KBC_VEN_INTEL_AMI 0xf8 +#define KBC_VEN_MASK 0xf8 + + +/* Flags should be fully 32-bit: + Bits 7- 0: Vendor and revision/variant; + Bits 15- 8: Input port mask; + Bits 23-16: Input port bits that are always on; + Bits 31-24: Flags: + Bit 0: Invert P1 video type bit polarity; + Bit 1: Is PS/2; + Bit 2: Translation forced always off. + + So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ typedef struct { - uint8_t command, status, old_status, out, old_out, secr_phase, - mem_addr, input_port, output_port, old_output_port, - key_command, output_locked, ami_stat, want60, - wantirq, key_wantdata, refresh, first_write; + uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, + secr_phase, mem_index, ami_stat, ami_mode, + kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, + kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, + kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, + mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, + kbc_written[3], kbc_data[3]; - uint8_t mem[0x100]; + uint8_t mem_int[0x40], mem[0x240]; - int last_irq, old_last_irq, - reset_delay, - out_new, out_delayed; + uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb, send_delay_timer; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - - pc_timer_t send_delay_timer; } atkbd_t; +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbd_cmd_process(atkbd_t *dev); + +static void kbc_wait(atkbd_t *dev, uint8_t flags); + + /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -125,9 +210,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; +uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; + -static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -568,9 +653,27 @@ static const scancode scancode_set3[512] = { }; +#define UISTR_LEN 256 +static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); +extern void ui_sb_bugui(char *__str); + + +static void +kbd_status(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(kbd_str, fmt, ap); + ui_sb_bugui(kbd_str); + va_end(ap); +} + + +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -631,9 +734,6 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); - } else { - key_ctrl_queue_start = key_ctrl_queue_end = 0; - memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -641,15 +741,6 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - dev->status = (dev->status & 0x0f) | stat_hi; - if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -658,82 +749,1042 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else { - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - } -} - - -static void -add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - kbd_log("ATkbc: Adding %02X to front...\n", val); - dev->wantirq = 0; - if (channel == 2) { - if (dev->mem[0] & 0x02) - picint(0x1000); - } else { - if (dev->mem[0] & 0x01) - picint(2); - } - dev->out = val; - if (channel == 2) - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; - else - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; - dev->last_irq = 0x0000; + } else + fatal("Adding %02X to invalid channel %02X\n", val, channel); } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); return; } - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } - static void -add_data_kbd_direct(atkbd_t *dev, uint8_t val) +kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); - uint8_t send; - - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - if (translate) - send = nont_to_t[val]; - else - send = val; - - add_data_kbd_queue(dev, 1, send); + dev->kbc_written[channel] = 1; + dev->kbc_data[channel] = val; } static void -add_data_kbd_raw(atkbd_t *dev, uint8_t val) +kbd_send_to_host(atkbd_t *dev, uint8_t val) { - add_data_kbd_queue(dev, 1, val); + kbc_send(dev, val, CHANNEL_KBD); +} + + +static void +kbd_chip_reset(atkbd_t *dev) +{ + kbc_queue_reset(1); + dev->kbc_written[1] = 0x00; + kbd_last_scan_code = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->kbd_phase = 0; + dev->kbd_in = 0; +} + + +static void +kbd_command(atkbd_t *dev) +{ + uint8_t val = dev->kbd_data; + + if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { + dev->kbd_phase++; + if (dev->kbd_phase == RESET_DELAY_TIME) { + kbd_send_to_host(dev, 0xaa); + dev->kbd_phase = 0; + dev->kbd_cmd = 0x00; + } + return; + } + + if (dev->kbd_phase == 2) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf2: + kbd_send_to_host(dev, 0x83); + break; + default: + fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } else if (dev->kbd_phase == 1) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf0: + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + kbd_send_to_host(dev, keyboard_mode & 3); + break; + case 0xf2: + kbd_send_to_host(dev, 0xab); + dev->kbd_phase = 2; + break; + default: + fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } + + if (dev->kbd_in && (val < 0xed)) { + dev->kbd_in = 0; + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set LEDs [%02x]\n", val); + kbd_send_to_host(dev, 0xfa); + break; + + case 0xf0: /* get/set scancode set */ + kbd_send_to_host(dev, 0xfa); + if (val == 0) + dev->kbd_phase = 1; + else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_send_to_host(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); + kbd_send_to_host(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + } else { + /* No keyboard command in progress. */ + dev->kbd_in = 0; + dev->kbd_cmd = 0x00; + dev->kbd_phase = 0; + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + kbd_send_to_host(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + kbd_send_to_host(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + kbd_send_to_host(dev, 0xfa); + + dev->kbd_in = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + kbd_send_to_host(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + val, keyboard_scan, dev->mem[0x20]); + kbd_send_to_host(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + kbd_send_to_host(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbd_chip_reset(dev); + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + kbd_send_to_host(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) + dev->kbd_cmd = val; + } +} + + +static void +kbd_do_command(atkbd_t *dev) +{ + kbd_command(dev); + if (dev->kbd_written) + dev->kbd_poll_phase = KBD_CMD_PROCESS; + else if ((dev->kbd_phase == 0) && !dev->kbd_in) { + dev->kbd_in_cmd = 0; + if (dev->kbd_data != 0xf5) + keyboard_scan = 1; + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else { + keyboard_scan = 0; + dev->kbd_in_cmd = 1; + dev->kbd_poll_phase = KBD_CMD_PROCESS; + } +} + + +static void +kbd_nack(atkbd_t *dev) +{ + kbd_send_to_host(dev, 0xfe); + dev->kbd_poll_phase = KBD_MAIN_LOOP; +} + + +static void +kbd_main_loop(atkbd_t *dev) +{ + uint8_t scan = !dev->kbd_inhibit && keyboard_scan; + + if (dev->kbd_written) { + dev->kbd_written = 0; + kbd_cmd_process(dev); + } else if (scan && (key_queue_start != key_queue_end)) { + /* Scan here. */ + kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); + kbd_send_to_host(dev, key_queue[key_queue_start]); + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +kbd_cmd_process(atkbd_t *dev) +{ + uint8_t written = dev->kbd_written; + + /* We want data, nothing has been written yet, return. */ + if (dev->kbd_in && !dev->kbd_written) + return; + + dev->kbd_written = 0; + + if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { + kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); + kbd_do_command(dev); + } else if (dev->kbd_data == 0xfe) { + kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); + kbd_send_to_host(dev, kbd_last_scan_code); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data == 0xee) { + kbd_log("ATkbd: Echo EE\n"); + kbd_send_to_host(dev, 0xee); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data >= 0xed) { + kbd_log("ATkbd: Command %02X\n", dev->kbd_data); + if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { + kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); + keyboard_scan = 1; + dev->kbd_in_cmd = 0; + } + kbd_do_command(dev); + } else { + if (!keyboard_scan && dev->kbd_in_cmd) { + if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { + kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); + kbd_nack(dev); + } else { + kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); + kbd_do_command(dev); + } + } else { + kbd_log("ATkbd: Scanning or not in command, NACK\n"); + kbd_nack(dev); + } + } +} + + +/* Keyboard processing */ +static void +kbd_process(atkbd_t *dev) +{ + /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ + if (dev->kbc_written[1] && dev->kbd_written) + dev->kbc_written[1] = 0; + + /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ + if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { + case KBD_MAIN_LOOP: + kbd_main_loop(dev); + break; + case KBD_CMD_PROCESS: + kbd_cmd_process(dev); + break; + } +} + + +static void +kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t ch = (channel > 0) ? channel : 1; + uint8_t do_irq = (dev->mem[0x20] & ch); + int translate = (channel == 1) && (keyboard_mode & 0x60); + + if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) + return; + + stat_hi |= dev->inhibit; + + if (!dev->kbc_send_pending) { + dev->kbc_send_pending = 1; + dev->kbc_to_send = val; + dev->kbc_channel = channel; + dev->kbc_stat_hi = stat_hi; + return; + } + + if (translate) { + /* Allow for scan code translation. */ + if (val == 0xf0) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if ((sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + } + + dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; + if (do_irq) { + kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); + picint(dev->last_irq); + } + kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); + dev->ob = translate ? (nont_to_t[val] | sc_or) : val; + + dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); + if (ch == 2) + dev->status |= STAT_MFULL; + + if (translate && (sc_or == 0x80)) + sc_or = 0; +} + + +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); + + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + val |= ((dev->mem[0x20] << 4) & 0x30); + + dev->kbd_inhibit = (val & 0x40); + dev->mouse_inhibit = (val & 0x08); + + if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) { + kbd_log("ATkbc: write_output(): IRQ 12\n"); + picint(1 << 12); + } else + picintc(1 << 12); + } + if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) { + kbd_log("ATkbc: write_output(): IRQ 1\n"); + picint(1 << 1); + } else + picintc(1 << 1); + } + if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->p2 ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->p2 = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + val &= ~CCB_TRANSLATE; + + dev->mem[0x20] = val; + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { + keyboard_mode &= ~CCB_PCMODE; + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + + +static void +kbc_transmit(atkbd_t *dev, uint8_t val) +{ + kbc_send_to_ob(dev, val, 0, 0x00); +} + + +static void +kbc_command(atkbd_t *dev) +{ + uint8_t mask, val = dev->ib; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int bad = 1; + + if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { + if (dev-> kbc_phase < 16) + kbc_transmit(dev, dev->mem[dev->kbc_phase]); + else if (dev-> kbc_phase == 16) + kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); + else if (dev-> kbc_phase == 17) + kbc_transmit(dev, dev->p2); + else if (dev-> kbc_phase == 18) + kbc_transmit(dev, dev->status); + + dev->kbc_phase++; + if (dev->kbc_phase == 19) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } + return; + } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { + val = ami_copr[dev->kbc_phase]; + kbc_transmit(dev, val); + if (val == 0x00) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } else + dev->kbc_phase++; + return; + } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { + /* load security */ + kbd_log("ATkbc: load security\n"); + dev->mem[0x50 + dev->kbc_in - 0x01] = val; + if ((dev->kbc_in == 0x80) && (val != 0x00)) { + /* Security string too long, set it to 0x00. */ + dev->mem[0x50] = 0x00; + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else if (val == 0x00) { + /* Security string finished. */ + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else /* Increase pointer and request another byte. */ + dev->kbc_in++; + return; + } + + /* If the written port is 64, go straight to the beginning of the command. */ + if (!(dev->status & STAT_CD) && dev->kbc_in) { + /* Write data to controller. */ + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (dev->kbc_cmd) { + case 0x60 ... 0x7f: + if (dev->kbc_cmd == 0x60) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + break; + + case 0xc7: /* or input port with system data */ + dev->p1 |= val; + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("New AMIKey mode: %02X\n", val); + dev->ami_mode = val; + dev->flags &= ~KBC_FLAG_PS2; + if (val & 1) + dev->flags |= KBC_FLAG_PS2; + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->p2_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->p2 & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + // kbc_send_to_ob(dev, val, 1, 0x00); + /* Should be channel 1, but we send to 0 to avoid translation, + since bytes output using this command do *NOT* get translated. */ + kbc_send_to_ob(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + kbc_send_to_ob(dev, val, 2, 0x00); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (dev->flags & KBC_FLAG_PS2) { + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x20; + if (mouse_write && !dev->kbc_written[2]) { + kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); + dev->mouse_data = val; + dev->mouse_written = 1; + dev->kbc_wait_for_response = 2; + } else + kbc_send_to_ob(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + +#ifdef ENABLE_KEYBOARD_AT_LOG + if (bad) + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); +#endif + } + } else { + /* Controller command. */ + kbd_log("ATkbc: Controller command: %02X\n", val); + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->kbc_in = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->kbd_in_cmd = dev->mouse_in_cmd = 0; + dev->status &= ~STAT_OFULL; + dev->last_irq = 0; + dev->kbc_phase = 0; + + /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ + if (dev->flags & KBC_FLAG_PS2) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + kbc_transmit(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + /* No error. */ + kbc_transmit(dev, 0x00); + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + kbc_transmit(dev, dev->mem[0x20]); + dev->kbc_phase = 1; + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* or input port with system data */ + kbd_log("ATkbc: Phoenix - or input port with system data\n"); + dev->kbc_in = 1; + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + kbc_transmit(dev, dev->ami_mode); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->kbc_in = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (dev->mem[0x20] & 0x10) + mask &= 0xbf; + if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) + mask &= 0xf7; + kbc_transmit(dev, dev->p2 & mask); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->kbc_in = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + dev->kbc_in = 1; + else + kbc_transmit(dev, 0x00); /* NCR */ + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + kbc_transmit(dev, 0x00); + break; + + case 0xe1: case 0xea: + kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); + write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); + } + + /* If the command needs data, remember the command. */ + if (dev->kbc_in || (dev->kbc_phase > 0)) + dev->kbc_cmd = val; + } +} + + +static void +kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) +{ + dev->kbc_written[channel] = 0; + kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); + kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); +} + + +static void +kbc_main_loop_scan(atkbd_t *dev) +{ + uint8_t port_dis = dev->mem[0x20] & 0x30; + uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); + + if (!ps2) + port_dis |= 0x20; + + if (!(dev->status & STAT_OFULL)) { + if (port_dis & 0x20) { + if (!(port_dis & 0x10)) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); + /* Enable communication with keyboard. */ + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 1); + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); + } +#endif + } else { + /* Enable communication with mouse. */ + dev->p2 &= 0xf7; + dev->mouse_inhibit = 0; + if (dev->mem[0x20] & 0x10) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); + kbc_wait(dev, 2); + } else { + /* Enable communication with keyboard. */ + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 3); + } + } + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + } +#endif +} + + +static void +kbc_process_ib(atkbd_t *dev) +{ + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + } else { + dev->mem[0x20] &= ~0x10; + dev->kbd_data = dev->ib; + dev->kbd_written = 1; + dev->kbc_wait_for_response = 1; + } + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response) + kbc_main_loop_scan(dev); +} + + +static void +kbc_wait(atkbd_t *dev, uint8_t flags) +{ + if ((flags & 1) && dev->kbc_written[1]) { + /* Disable communication with mouse. */ + dev->p2 |= 0x08; + dev->mouse_inhibit = 1; + /* Send keyboard byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_KBD); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if ((flags & 2) && dev->kbc_written[2]) { + /* Disable communication with keyboard. */ + dev->p2 |= 0x40; + dev->kbd_inhibit = 1; + /* Send mouse byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if (dev->status & STAT_IFULL) { + /* Disable communication with keyboard and mouse. */ + dev->p2 |= 0x48; + dev->kbd_inhibit = dev->mouse_inhibit = 1; + kbc_process_ib(dev); + } else + dev->kbc_poll_phase = KBC_WAIT | flags; +} + + +/* Controller processing */ +static void +kbc_process(atkbd_t *dev) +{ + // kbd_log("ATkbc: kbc_process()\n"); + + /* If we're waiting for the response from the keyboard or mouse, do nothing + until the device has repsonded back. */ + if (dev->kbc_wait_for_response > 0) { + if (dev->kbc_written[dev->kbc_wait_for_response]) + dev->kbc_wait_for_response = 0; + else + return; + } + + if (dev->kbc_send_pending) { + kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", + dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + dev->kbc_send_pending = 0; + } + + if (dev->kbc_poll_phase == KBC_RESET) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Reset loop()\n"); + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } + } + + return; + } + + if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: In a command\n"); + if (!dev->kbc_in && (dev->status & STAT_OFULL)) { + kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); + return; /* We do not want input and we're waiting for the host to read the data + we transmitted, but it has not done that yet, do nothing. */ + } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { + kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); + return; /* We want input and the host has not provided us with any yet, do nothing. */ + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: Normal condition\n"); +#endif + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + kbd_log("ATkbc: Resetting command\n"); + dev->kbc_phase = 0; + dev->kbc_in = 0; + } + } + + /* Process command. */ + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + + if (!(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ + } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { + case KBC_MAIN_LOOP: + // kbd_log("ATkbc: Main loop\n"); + if (dev->status & STAT_IFULL) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: IBF full, process\n"); + kbc_process_ib(dev); + } else + kbc_main_loop_scan(dev); + break; + case KBC_WAIT_FOR_KBD: + case KBC_WAIT_FOR_MOUSE: + case KBC_WAIT_FOR_BOTH: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); + kbc_wait(dev, dev->kbc_poll_phase & 3); + break; + default: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); + break; + } } @@ -741,105 +1792,29 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; -#ifdef ENABLE_KEYBOARD_AT_LOG - const uint8_t channels[4] = { 1, 2, 0, 0 }; -#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - if (dev->out_new != -1 && !dev->last_irq) { - dev->wantirq = 0; - if (dev->out_new & 0x100) { - if (dev->mem[0] & 0x02) - picint(0x1000); - kbd_log("ATkbc: %02X coming from channel 2\n"); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; - dev->last_irq = 2; - } - } + /* We process all three devices at the same time, in an arbitrary order. */ - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); - dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new = mouse_queue[mouse_queue_start] | 0x100; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { - kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - } + /* Keyboard processing */ + kbd_process(dev); - if (dev->reset_delay) { - dev->reset_delay--; - if (!dev->reset_delay) { - kbd_log("ATkbc: Sending AA on keyboard reset...\n"); - add_data_kbd_direct(dev, 0xaa); - } - } -} + /* TODO: Mouse processing */ + // mouse_process(dev); - -static void -add_data(atkbd_t *dev, uint8_t val) -{ - kbd_log("ATkbc: add to queue\n"); - - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - kbc_queue_add(dev, val, 0, 0x00); - - if (!(dev->out_new & 0x300)) { - dev->out_delayed = dev->out_new; - dev->out_new = -1; - } + /* Controller processing */ + kbc_process(dev); } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); int i; - uint8_t or = 0; - uint8_t send; - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - for (i = 0; i < len; i++) { - if (translate) { - if (val[i] == 0xf0) { - or = 0x80; - continue; - } - send = nont_to_t[val[i]] | or; - if (or == 0x80) - or = 0; - } else - send = val[i]; - - add_data_kbd_queue(dev, 0, send); - } + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, 0, val[i]); } @@ -847,56 +1822,21 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->reset_delay) + if (dev->kbd_in || (dev->kbd_phase > 0)) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Allow for scan code translation. */ - if (translate && (val == 0xf0)) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && - (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { - case 0x4f: t3100e_notify_set(0x01); break; /* End */ - case 0x50: t3100e_notify_set(0x02); break; /* Down */ - case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ - case 0x52: t3100e_notify_set(0x04); break; /* Ins */ - case 0x53: t3100e_notify_set(0x05); break; /* Del */ - case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ - case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ - case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ - case 0x47: t3100e_notify_set(0x09); break; /* Home */ - case 0x48: t3100e_notify_set(0x0a); break; /* Up */ - case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ - case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ - case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ - case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ - case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ - } + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && + (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) + t3100e_notify_set((val + 2) & 0x0f); - kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1029,18 +1969,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("scan code: "); - if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) - kbd_log("F0 "); - kbd_log("%02X)\n", val); - } else - kbd_log("%02X\n", val); -#endif - - add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); + add_data_kbd_queue(dev, 0, val); break; } @@ -1049,121 +1978,13 @@ add_data_kbd(uint16_t val) } -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - val |= ((dev->mem[0] << 4) & 0x30); - - if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) - picint(1 << 12); - else - picintc(1 << 12); - } - if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) - picint(1 << 1); - else - picintc(1 << 1); - } - if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->output_port ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->output_port = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); - - if ((val & 1) && (dev->status & STAT_OFULL)) - dev->wantirq = 1; - if (!(val & 1) && dev->wantirq) - dev->wantirq = 0; - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { - val &= ~CCB_TRANSLATE; - dev->mem[0] &= ~CCB_TRANSLATE; - } - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || - ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { - keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->output_port); - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_output_port = dev->output_port & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); - write_output(dev, dev->output_port & (0xf0 | mask)); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); - write_output(dev, dev->output_port | dev->old_output_port); -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xef; - dev->mem[0] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xdf; - dev->mem[0] |= (enable ? 0x00 : 0x20); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); + write_output(dev, dev->p2 | dev->old_p2); } @@ -1172,49 +1993,70 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; switch (val) { case 0xa4: /* check if password installed */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: check if password installed\n"); - add_data(dev, 0xf1); + kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); + return 0; + } + break; + + case 0xa5: /* load security */ + if (dev->flags & KBC_FLAG_PS2) { + kbd_log("ATkbc: load security\n"); + dev->kbc_in = 1; return 0; } break; case 0xa7: /* disable mouse port */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: disable mouse port\n"); - set_enable_mouse(dev, 0); + // kbc_transmit(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: enable mouse port\n"); - set_enable_mouse(dev, 1); + // kbc_transmit(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ + if (dev->flags & KBC_FLAG_PS2) { + /* No error, this is testing the channel 2 interface. */ + kbc_transmit(dev, 0x00); return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - add_data(dev, 0x00); + kbc_transmit(dev, 0x00); return 0; case 0xc0: /* read input port */ + /* IBM PS/1: + Bit 2 and 4 ignored (we return always 0), + Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". + Intel AMI: + Bit 2 ignored (we return always 1), + Bit 4 must be 1, + Bit 6 must be 1 or else error in SMM. + Acer: + Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), + Bit 4 must be 0, + Bit 6 ignored. + P6RP4: + Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -1222,11 +2064,8 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc) | - (fdd_is_525(current_drive) ? 0x40 : 0x00); + kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -1238,39 +2077,34 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && - ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); + pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); + // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); else - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, dev->p1 | fixed_bits); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -1285,35 +2119,168 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; - switch(dev->command) { - /* 0x40 - 0x5F are aliases for 0x60-0x7F */ - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) + switch(dev->kbc_cmd) { + /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + if (dev->kbc_cmd == 0x40) write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM\n"); - if (dev->secr_phase == 1) { - dev->mem_addr = val; - dev->want60 = 1; - dev->secr_phase = 2; - } else if (dev->secr_phase == 2) { - dev->mem[dev->mem_addr] = val; + kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); + if (dev->secr_phase == 0) { + dev->mem_index = val; + dev->kbc_in = 1; + dev->secr_phase++; + } else if (dev->secr_phase == 1) { + if (dev->mem_index == 0x20) + write_cmd(dev, val); + else + dev->mem[dev->mem_index] = val; dev->secr_phase = 0; } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); + dev->mem_index = val; + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + dev->mem[index + dev->mem_index] = val; + } else if (dev->mem_index == 0x60) + write_cmd(dev, val); + else if (dev->mem_index == 0x42) + dev->status = val; + else if (dev->mem_index >= 0x40) + dev->mem[dev->mem_index - 0x40] = val; + else + dev->mem_int[dev->mem_index] = val; + return 0; + + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + dev->status = val; + break; + case 0x01: /* Password_ptr */ + dev->mem[0x1c] = val; + break; + case 0x02: /* Wakeup_Tsk_Reg */ + dev->mem[0x1e] = val; + break; + case 0x03: /* CCB */ + write_cmd(dev, val); + break; + case 0x04: /* Debounce_time */ + dev->mem[0x4d] = val; + break; + case 0x05: /* Pulse_Width */ + dev->mem[0x4e] = val; + break; + case 0x06: /* Pk_sel_byte */ + dev->mem[0x4c] = val; + break; + case 0x07: /* Func_Tsk_Reg */ + dev->mem[0x7e] = val; + break; + case 0x08: /* TypematicRate */ + dev->mem[0x80] = val; + break; + case 0x09: /* Led_Flag_Byte */ + dev->mem[0x81] = val; + break; + case 0x0a: /* Kbms_Command_St */ + dev->mem[0x87] = val; + break; + case 0x0b: /* Delay_Count_Byte */ + dev->mem[0x86] = val; + break; + case 0x0c: /* KBC_Flags */ + dev->mem[0x9b] = val; + break; + case 0x0d: /* SCODE_HK1 */ + dev->mem[0x50] = val; + break; + case 0x0e: /* SCODE_HK2 */ + dev->mem[0x51] = val; + break; + case 0x0f: /* SCODE_HK3 */ + dev->mem[0x52] = val; + break; + case 0x10: /* SCODE_HK4 */ + dev->mem[0x53] = val; + break; + case 0x11: /* SCODE_HK5 */ + dev->mem[0x54] = val; + break; + case 0x12: /* SCODE_HK6 */ + dev->mem[0x55] = val; + break; + case 0x13: /* TASK_HK1 */ + dev->mem[0x56] = val; + break; + case 0x14: /* TASK_HK2 */ + dev->mem[0x57] = val; + break; + case 0x15: /* TASK_HK3 */ + dev->mem[0x58] = val; + break; + case 0x16: /* TASK_HK4 */ + dev->mem[0x59] = val; + break; + case 0x17: /* TASK_HK5 */ + dev->mem[0x5a] = val; + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + dev->mem[0x5b] = val; + break; + case 0x19: /* Batt_Alarm_Reg1 */ + dev->mem[0x5c] = val; + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + dev->mem[0x5d] = val; + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + dev->mem[0x5e] = val; + break; + case 0x1c: /* Kbc_State1 */ + dev->mem[0x9d] = val; + break; + case 0x1d: /* Aux_Config */ + dev->mem[0x75] = val; + break; + case 0x1e: /* Kbc_State3 */ + dev->mem[0x73] = val; + break; + } + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->p1 = val; + return 0; + case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -1327,62 +2294,50 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; switch (val) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x00 ... 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - add_data(dev, dev->mem[val]); + kbc_transmit(dev, dev->mem[val + 0x20]); return 0; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->want60 = 1; + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + dev->kbc_in = 1; return 0; case 0xa0: /* copyright message */ - add_data(dev, 0x28); - add_data(dev, 0x00); - break; + kbc_transmit(dev, ami_copr[0]); + dev->kbc_phase = 1; + return 0; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - add_data(dev, 'H'); + // kbc_transmit(dev, 'H'); + kbc_transmit(dev, '5'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->output_port & 0xf3); - add_data(dev, 0x00); + write_output(dev, dev->p2 & 0xf3); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->output_port | 0x0c); - add_data(dev, 0x00); + write_output(dev, dev->p2 | 0x0c); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -1390,7 +2345,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -1398,15 +2353,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read clock\n"); - add_data(dev, !!(dev->ami_stat & 1)); + kbc_transmit(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -1414,7 +2369,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -1422,68 +2377,237 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read cache\n"); - add_data(dev, !!(dev->ami_stat & 2)); + kbc_transmit(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->want60 = 1; - dev->secr_phase = 1; + dev->kbc_in = 1; return 0; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb0 ... 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!PCI || (val > 0xb1)) - dev->input_port &= ~(1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { + dev->p1 &= ~(1 << (val & 0x03)); + } + kbc_transmit(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (! PCI) - write_output(dev, dev->output_port & ~(4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 & ~(4 << (val & 0x01))); + kbc_transmit(dev, 0x00); return 0; - case 0xb8: case 0xb9: case 0xba: case 0xbb: +#if 0 + case 0xb8 ... 0xbb: +#else + case 0xb9: +#endif /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!PCI || (val > 0xb9)) { - dev->input_port |= (1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + kbc_transmit(dev, 0x00); } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index\n"); + dev->kbc_in = 1; + return 0; + + case 0xba: + kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + kbc_transmit(dev, dev->mem[index + dev->mem_index]); + } else if (dev->mem_index == 0x42) + kbc_transmit(dev, dev->status); + else if (dev->mem_index >= 0x40) + kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); + else + kbc_transmit(dev, dev->mem_int[dev->mem_index]); + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + +#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (! PCI) - write_output(dev, dev->output_port | (4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 | (4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; +#endif + + case 0xbc: + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + kbc_transmit(dev, dev->status); + break; + case 0x01: /* Password_ptr */ + kbc_transmit(dev, dev->mem[0x1c]); + break; + case 0x02: /* Wakeup_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x1e]); + break; + case 0x03: /* CCB */ + kbc_transmit(dev, dev->mem[0x20]); + break; + case 0x04: /* Debounce_time */ + kbc_transmit(dev, dev->mem[0x4d]); + break; + case 0x05: /* Pulse_Width */ + kbc_transmit(dev, dev->mem[0x4e]); + break; + case 0x06: /* Pk_sel_byte */ + kbc_transmit(dev, dev->mem[0x4c]); + break; + case 0x07: /* Func_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x7e]); + break; + case 0x08: /* TypematicRate */ + kbc_transmit(dev, dev->mem[0x80]); + break; + case 0x09: /* Led_Flag_Byte */ + kbc_transmit(dev, dev->mem[0x81]); + break; + case 0x0a: /* Kbms_Command_St */ + kbc_transmit(dev, dev->mem[0x87]); + break; + case 0x0b: /* Delay_Count_Byte */ + kbc_transmit(dev, dev->mem[0x86]); + break; + case 0x0c: /* KBC_Flags */ + kbc_transmit(dev, dev->mem[0x9b]); + break; + case 0x0d: /* SCODE_HK1 */ + kbc_transmit(dev, dev->mem[0x50]); + break; + case 0x0e: /* SCODE_HK2 */ + kbc_transmit(dev, dev->mem[0x51]); + break; + case 0x0f: /* SCODE_HK3 */ + kbc_transmit(dev, dev->mem[0x52]); + break; + case 0x10: /* SCODE_HK4 */ + kbc_transmit(dev, dev->mem[0x53]); + break; + case 0x11: /* SCODE_HK5 */ + kbc_transmit(dev, dev->mem[0x54]); + break; + case 0x12: /* SCODE_HK6 */ + kbc_transmit(dev, dev->mem[0x55]); + break; + case 0x13: /* TASK_HK1 */ + kbc_transmit(dev, dev->mem[0x56]); + break; + case 0x14: /* TASK_HK2 */ + kbc_transmit(dev, dev->mem[0x57]); + break; + case 0x15: /* TASK_HK3 */ + kbc_transmit(dev, dev->mem[0x58]); + break; + case 0x16: /* TASK_HK4 */ + kbc_transmit(dev, dev->mem[0x59]); + break; + case 0x17: /* TASK_HK5 */ + kbc_transmit(dev, dev->mem[0x5a]); + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + kbc_transmit(dev, dev->mem[0x5b]); + break; + case 0x19: /* Batt_Alarm_Reg1 */ + kbc_transmit(dev, dev->mem[0x5c]); + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + kbc_transmit(dev, dev->mem[0x5d]); + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x5e]); + break; + case 0x1c: /* Kbc_State1 */ + kbc_transmit(dev, dev->mem[0x9d]); + break; + case 0x1d: /* Aux_Config */ + kbc_transmit(dev, dev->mem[0x75]); + break; + case 0x1e: /* Kbc_State3 */ + kbc_transmit(dev, dev->mem[0x73]); + break; + default: + kbc_transmit(dev, 0x00); + break; + } + kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); return 0; - case 0xc8: + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->kbc_in = 1; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->p1 &= 0xef; + kbc_transmit(dev, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->p1 &= 0xdf; + kbc_transmit(dev, 0x00); + return 0; + + case 0xc8: case 0xc9: /* - * unblock KBC lines P22/P23 + * (un)block KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); - dev->output_locked = 1; + kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); + dev->p2_locked = (val & 1); return 0; - case 0xc9: - /* - * block KBC lines P22/P23 - * (disallow command D1 from changing bits 2/3 of the port) - */ - kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); - dev->output_locked = 1; + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->p1 |= 0x10; + kbc_transmit(dev, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->p1 |= 0x20; + kbc_transmit(dev, 0x00); return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -1504,23 +2628,20 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -1535,7 +2656,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -1544,12 +2665,34 @@ write60_quadtel(void *priv, uint8_t val) return 1; } + static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { + /* This appears to be a clone of "Read input port", in which case, the bis would be: + 7: M290 (AT KBC): + Keyboard lock (1 = unlocked, 0 = locked); + M300 (PS/2 KBC): + Bus expansion board present (1 = present, 0 = not present); + 6: Usually: + Display (1 = MDA, 0 = CGA, but can have its polarity inverted); + 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); + 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); + 3: Fast Ram check (if inactive keyboard works erratically); + 2: Keyboard fuse present + This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; + 1: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Mouse data in; + 0: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Key data in. + */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -1558,11 +2701,9 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); return 0; - } + } return write64_generic(dev, val); } @@ -1580,7 +2721,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } @@ -1593,7 +2734,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -1636,29 +2777,30 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - add_data(dev, t3100e_config_get()); + kbc_transmit(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - add_data(dev, t3100e_mono_get()); + kbc_transmit(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_TYPE_MASK; + dev->flags &= ~KBC_FLAG_PS2; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_TYPE_PS2_NOREF; - } else { - kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); - dev->flags |= KBC_TYPE_ISA; + dev->flags |= KBC_FLAG_PS2; } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); +#endif return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -1668,8 +2810,9 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - add_data(dev, 0x04); - else add_data(dev, 0x00); + kbc_transmit(dev, 0x04); + else + kbc_transmit(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -1682,8 +2825,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - add_data(dev, dev->input_port); + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + kbc_transmit(dev, dev->p1); return 0; } @@ -1696,425 +2839,46 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i = 0, bad = 1; - uint8_t mask, kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - - kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); + kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); switch (port) { case 0x60: - dev->status &= ~STAT_CD; - if (dev->want60) { - /* Write data to controller. */ - dev->want60 = 0; + dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (dev->command) { - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) - write_cmd(dev, val); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->output_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->output_port & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - add_data_kbd_direct(dev, val); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - keyboard_at_adddata_mouse(val); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (val == 0xbb) - break; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - set_enable_mouse(dev, 1); - if (mouse_write) - mouse_write(val, mouse_p); - else - add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - - if (bad) { - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); - add_data_kbd(0xfe); - } - } - } else { - /* Write data to keyboard. */ - dev->mem[0] &= ~0x10; - - if (dev->key_wantdata) { - dev->key_wantdata = 0; - - /* - * Several system BIOSes and OS device drivers - * mess up with this, and repeat the command - * code many times. Fun! - */ - if (val == dev->key_command) { - /* Respond NAK and ignore it. */ - add_data_kbd(0xfe); - dev->key_command = 0x00; - break; - } - - switch (dev->key_command) { - case 0xed: /* set/reset LEDs */ - add_data_kbd_direct(dev, 0xfa); - kbd_log("ATkbd: set LEDs [%02x]\n", val); - break; - - case 0xf0: /* get/set scancode set */ - add_data_kbd_direct(dev, 0xfa); - if (val == 0) { - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - add_data_kbd_direct(dev, keyboard_mode & 3); - } else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - add_data_kbd_direct(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); - add_data_kbd_direct(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - dev->key_command = 0x00; - } else { - /* No keyboard command in progress. */ - dev->key_command = 0x00; - - set_enable_kbd(dev, 1); - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - add_data_kbd_direct(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - add_data_kbd_direct(dev, 0xfe); - break; - - /* Sent by Pentium-era AMI BIOS'es.*/ - case 0x71: case 0x82: - kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - add_data_kbd_direct(dev, 0xfa); - - dev->key_wantdata = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - add_data_kbd_direct(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - add_data_kbd_direct(dev, 0xfa); - add_data_kbd_direct(dev, 0xab); - add_data_kbd_direct(dev, 0x83); - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", - val, keyboard_scan, dev->mem[0]); - add_data_kbd_direct(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_raw(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbc_queue_reset(1); - kbd_last_scan_code = 0x00; - add_data_kbd_direct(dev, 0xfa); - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->reset_delay = RESET_DELAY_TIME; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - add_data_kbd_direct(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if (dev->key_wantdata == 1) - dev->key_command = val; - } +#if 0 + if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { + dev->status &= ~STAT_IFULL; + write_output(dev, val); + dev->fast_a20_phase = 0; } +#endif break; - - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if (kbc_ven == KBC_VEN_XI8088) - xi8088_turbo_set(!!(val & 0x04)); - break; - case 0x64: - /* Controller command. */ - dev->want60 = 0; - dev->status |= STAT_CD; + dev->status |= (STAT_CD | STAT_IFULL); + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (val) { - /* Read data from KBC memory. */ - case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - add_data(dev, dev->mem[val & 0x1f]); - break; - - /* Write data to KBC memory. */ - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->want60 = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) - dev->status |= STAT_IFULL; - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - dev->last_irq = dev->old_last_irq = 0; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_data(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - add_data(dev, 0x00); /*no error*/ - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - for (i = 0; i < 16; i++) - add_data(dev, dev->mem[i]); - add_data(dev, (dev->input_port & 0xf0) | 0x80); - add_data(dev, dev->output_port); - add_data(dev, dev->status); - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->want60 = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (dev->mem[0] & 0x10) - mask &= 0xbf; - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x20)) - mask &= 0xf7; - add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->want60 = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - dev->want60 = 1; - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - add_data(dev, 0x00); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); +#if 0 + if (val == 0xd1) { + dev->status &= ~STAT_IFULL; + dev->fast_a20_phase = 1; + } else if (val == 0xfe) { + dev->status &= ~STAT_IFULL; + pulse_output(dev, 0x0e); + } else if ((val == 0xad) || (val == 0xae)) { + dev->status &= ~STAT_IFULL; + if (val & 0x01) + dev->mem[0x20] |= 0x10; + else + dev->mem[0x20] &= ~0x10; + } else if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); } - - /* If the command needs data, remember the command. */ - if (dev->want60) - dev->command = val; +#endif break; } } @@ -2125,83 +2889,20 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - cycles -= ISA_CYCLES(8); - - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; + // if (dev->flags & KBC_FLAG_PS2) + // cycles -= ISA_CYCLES(8); switch (port) { case 0x60: - ret = dev->out; + ret = dev->ob; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if (kbc_ven == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) - ret |= 0x04; - else - ret &= ~0x04; - } - break; - - case 0x62: - ret = 0xff; - if (kbc_ven == KBC_VEN_OLIVETTI) { - /* SWA on Olivetti M240 mainboard (off=1) */ - ret = 0x00; - if (ppi.pb & 0x8) { - /* Switches 4, 5 - floppy drives (number) */ - int i, fdd_count = 0; - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } - if (!fdd_count) - ret |= 0x00; - else - ret |= ((fdd_count - 1) << 2); - /* Switches 6, 7 - monitor type */ - if (video_is_mda()) - ret |= 0x3; - else if (video_is_cga()) - ret |= 0x2; /* 0x10 would be 40x25 */ - else - ret |= 0x0; - } else { - /* bit 2 always on */ - ret |= 0x4; - /* Switch 8 - 8087 FPU. */ - if (hasfpu) - ret |= 0x02; - } - } - break; case 0x64: - ret = (dev->status & 0xfb); - if (dev->mem[0] & STAT_SYSFLAG) - ret |= STAT_SYSFLAG; - /* Only clear the transmit timeout flag on non-PS/2 controllers, as on - PS/2 controller, it is the keyboard/mouse output source bit. */ - // dev->status &= ~STAT_RTIMEOUT; - if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && - (kbc_ven != KBC_VEN_IBM_MCA)) - dev->status &= ~STAT_TTIMEOUT; + ret = dev->status; break; default: @@ -2209,22 +2910,12 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); + kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); return(ret); } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { @@ -2233,25 +2924,26 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; - dev->first_write = 1; - // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0] = 0x01; - dev->mem[0] |= CCB_TRANSLATE; - dev->wantirq = 0; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; write_output(dev, 0xcf); - dev->last_irq = dev->old_last_irq = 0; + dev->last_irq = 0; dev->secr_phase = 0; - dev->key_wantdata = 0; + dev->kbd_in = 0; + dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); /* Set up the correct Video Type bits. */ + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + dev->p1 ^= 0x40; + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + dev->inhibit = ((dev->p1 & 0x80) >> 3); else - dev->input_port = video_is_mda() ? 0xf0 : 0xb0; - kbd_log("ATkbc: input port = %02x\n", dev->input_port); + dev->inhibit = 0x10; + kbd_log("ATkbc: input port = %02x\n", dev->p1); - keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2259,16 +2951,18 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0; + dev->ob = 0xff; sc_or = 0; + for (i = 1; i <= 2; i++) + kbc_queue_reset(i); + memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->mem[0x31] = 0xfe; } @@ -2290,7 +2984,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2314,17 +3007,14 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - kbd_reset(dev); + dev->kbc_poll_phase = KBC_RESET; + kbd_send_to_host(dev, 0xaa); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -2340,12 +3030,14 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: + /* The Olivetti controller is a special case - starts directly in the + main loop instead of the reset loop. */ + dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2365,6 +3057,8 @@ kbd_init(const device_t *info) break; } + kbd_reset(dev); + /* We need this, sadly. */ SavedKbd = dev; @@ -2392,16 +3086,6 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; -const device_t keyboard_at_samsung_device = { - "PC/AT Keyboard (Samsung)", - 0, - KBC_TYPE_ISA | KBC_VEN_SAMSUNG, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -2433,16 +3117,6 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -2455,7 +3129,7 @@ const device_t keyboard_ps2_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2465,7 +3139,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2485,7 +3159,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2495,7 +3169,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -2525,7 +3199,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -2535,7 +3209,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2545,7 +3219,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2555,7 +3229,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -2565,7 +3239,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + KBC_TYPE_PS2_1 | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -2576,17 +3250,8 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - mouse_write = func; - mouse_p = priv; -} - - -void -keyboard_at_adddata_keyboard_raw(uint8_t val) -{ - atkbd_t *dev = SavedKbd; - - add_data_kbd_queue(dev, 0, val); + // mouse_write = func; + // mouse_p = priv; } @@ -2599,10 +3264,30 @@ keyboard_at_adddata_mouse(uint8_t val) } +void +keyboard_at_adddata_mouse_direct(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + void keyboard_at_mouse_reset(void) { - kbc_queue_reset(2); + // atkbd_t *dev = SavedKbd; + + return; } @@ -2613,13 +3298,22 @@ keyboard_at_mouse_pos(void) } +int +keyboard_at_fixed_channel(void) +{ + // atkbd_t *dev = SavedKbd; + + return 0x000; +} + + void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -2633,7 +3327,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); } @@ -2642,5 +3336,17 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); + write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); +} + + +void +keyboard_at_set_mode(int ps2) +{ + atkbd_t *dev = SavedKbd; + + if (ps2) + dev->flags |= KBC_FLAG_PS2; + else + dev->flags &= ~KBC_FLAG_PS2; } diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index e68718c68..96a27de42 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -591,20 +591,18 @@ kbd_read(uint16_t port, void *priv) case 0x62: if (kbd->type == 0) ret = 0x00; - else if (kbd->type == 1) { + else if (kbd->type == 1) { if (kbd->pb & 0x04) - ret = ((mem_size-64) / 32) & 0x0f; + ret = ((mem_size - 64) / 32) & 0x0f; else - ret = ((mem_size-64) / 32) >> 4; - } - else if (kbd->type == 8 || kbd->type == 9) { - /* Olivetti M19 or Zenith Data Systems Z-151 */ - if (kbd->pb & 0x04) + ret = ((mem_size - 64) / 32) >> 4; + } else if (kbd->type == 8 || kbd->type == 9) { + /* Olivetti M19 or Zenith Data Systems Z-151 */ + if (kbd->pb & 0x04) ret = kbd->pd & 0xbf; - else - ret = kbd->pd >> 4; - } - else { + else + ret = kbd->pd >> 4; + } else { if (kbd->pb & 0x08) ret = kbd->pd >> 4; else { @@ -632,7 +630,6 @@ kbd_read(uint16_t port, void *priv) case 0x63: if ((kbd->type == 2) || (kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) ret = kbd->pd; - break; } @@ -682,119 +679,116 @@ kbd_init(const device_t *info) video_reset(gfxcard); - if (kbd->type <= 3 || kbd-> type == 8) { - + if ((kbd->type <= 3) || (kbd->type == 4) || (kbd->type == 6)) { /* DIP switch readout: bit set = OFF, clear = ON. */ - if (kbd->type != 8) - /* Switches 7, 8 - floppy drives. */ - kbd->pd = get_fdd_switch_settings(); - else - /* Olivetti M19 - * Jumpers J1, J2 - monitor type. - * 01 - mono (high-res) - * 10 - color (low-res, disables 640x400x2 mode) - * 00 - autoswitching - */ - kbd->pd |= 0x00; - - kbd->pd |= get_videomode_switch_settings(); - - /* Switches 3, 4 - memory size. */ - // Note to Compaq/Toshiba keyboard maintainers: type 4 and 6 will never be activated in this block - // Should the top if be closed right after setting floppy drive count? - if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { - switch (mem_size) { - case 256: - kbd->pd |= 0x00; - break; - case 512: - kbd->pd |= 0x04; - break; - case 576: - kbd->pd |= 0x08; - break; - case 640: - default: - kbd->pd |= 0x0c; - break; - } - } else if (kbd->type >= 1) { - switch (mem_size) { - case 64: - kbd->pd |= 0x00; - break; - case 128: - kbd->pd |= 0x04; - break; - case 192: - kbd->pd |= 0x08; - break; - case 256: - default: - kbd->pd |= 0x0c; - break; - } - } else { - switch (mem_size) { - case 16: - kbd->pd |= 0x00; - break; - case 32: - kbd->pd |= 0x04; - break; - case 48: - kbd->pd |= 0x08; - break; - case 64: - default: - kbd->pd |= 0x0c; - break; - } - } + if (kbd->type == 8) + /* Olivetti M19 + * Jumpers J1, J2 - monitor type. + * 01 - mono (high-res) + * 10 - color (low-res, disables 640x400x2 mode) + * 00 - autoswitching + */ + kbd->pd |= 0x00; + else + /* Switches 7, 8 - floppy drives. */ + kbd->pd = get_fdd_switch_settings(); - /* Switch 2 - 8087 FPU. */ - if (hasfpu) - kbd->pd |= 0x02; + kbd->pd |= get_videomode_switch_settings(); - /* Switch 1 - always off. */ - kbd->pd |= 0x01; + /* Switches 3, 4 - memory size. */ + if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { + switch (mem_size) { + case 256: + kbd->pd |= 0x00; + break; + case 512: + kbd->pd |= 0x04; + break; + case 576: + kbd->pd |= 0x08; + break; + case 640: + default: + kbd->pd |= 0x0c; + break; + } + } else if (kbd->type >= 1) { + switch (mem_size) { + case 64: + kbd->pd |= 0x00; + break; + case 128: + kbd->pd |= 0x04; + break; + case 192: + kbd->pd |= 0x08; + break; + case 256: + default: + kbd->pd |= 0x0c; + break; + } + } else { + switch (mem_size) { + case 16: + kbd->pd |= 0x00; + break; + case 32: + kbd->pd |= 0x04; + break; + case 48: + kbd->pd |= 0x08; + break; + case 64: + default: + kbd->pd |= 0x0c; + break; + } + } + + /* Switch 2 - 8087 FPU. */ + if (hasfpu) + kbd->pd |= 0x02; + + /* Switch 1 - always off. */ + kbd->pd |= 0x01; } else if (kbd-> type == 9) { - /* Zenith Data Systems Z-151 - * SW2 switch settings: - * bit 7: monitor frequency - * bits 5-6: autoboot (00-11 resident monitor, 10 hdd, 01 fdd) - * bits 0-4: installed memory - */ - kbd->pd = 0x20; - switch (mem_size) { - case 128: - kbd->pd |= 0x02; - break; - case 192: - kbd->pd |= 0x04; - break; - case 256: - kbd->pd |= 0x02|0x04; - break; - case 320: - kbd->pd |= 0x08; - break; - case 384: - kbd->pd |= 0x02|0x08; - break; - case 448: - kbd->pd |= 0x04|0x08; - break; - case 512: - kbd->pd |= 0x02|0x04|0x08; - break; - case 576: - kbd->pd |= 0x10; - break; - case 640: - default: - kbd->pd |= 0x02|0x10; - break; + /* Zenith Data Systems Z-151 + * SW2 switch settings: + * bit 7: monitor frequency + * bits 5-6: autoboot (00-11 resident monitor, 10 hdd, 01 fdd) + * bits 0-4: installed memory + */ + kbd->pd = 0x20; + switch (mem_size) { + case 128: + kbd->pd |= 0x02; + break; + case 192: + kbd->pd |= 0x04; + break; + case 256: + kbd->pd |= 0x06; + break; + case 320: + kbd->pd |= 0x08; + break; + case 384: + kbd->pd |= 0x0a; + break; + case 448: + kbd->pd |= 0x0c; + break; + case 512: + kbd->pd |= 0x0e; + break; + case 576: + kbd->pd |= 0x10; + break; + case 640: + default: + kbd->pd |= 0x12; + break; } } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index b31ffdd52..f8ba676e0 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -93,22 +93,27 @@ ps2_write(uint8_t val, void *priv) mouse_t *dev = (mouse_t *)priv; uint8_t temp; + pclog("ps2_write(%02X)\n", val); + if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; + if (val == 0xff) + goto mouse_reset; + switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xf3: /* set sample rate */ dev->sample_rate = val; - keyboard_at_adddata_mouse(0xfa); /* Command response */ + keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ break; default: - keyboard_at_adddata_mouse(0xfc); + keyboard_at_adddata_mouse_cmd(0xfc); } } else { dev->command = val; @@ -116,21 +121,21 @@ ps2_write(uint8_t val, void *priv) switch (dev->command) { case 0xe6: /* set scaling to 1:1 */ dev->flags &= ~FLAG_SCALED; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe7: /* set scaling to 2:1 */ dev->flags |= FLAG_SCALED; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe8: /* set mouse resolution */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe9: /* status request */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); temp = (dev->flags & 0x30); if (mouse_buttons & 0x01) temp |= 0x01; @@ -138,13 +143,13 @@ ps2_write(uint8_t val, void *priv) temp |= 0x02; if (mouse_buttons & 0x04) temp |= 0x03; - keyboard_at_adddata_mouse(temp); - keyboard_at_adddata_mouse(dev->resolution); - keyboard_at_adddata_mouse(dev->sample_rate); + keyboard_at_adddata_mouse_cmd(temp); + keyboard_at_adddata_mouse_cmd(dev->resolution); + keyboard_at_adddata_mouse_cmd(dev->sample_rate); break; case 0xeb: /* Get mouse data */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); temp = 0; if (dev->x < 0) @@ -157,50 +162,51 @@ ps2_write(uint8_t val, void *priv) temp |= 2; if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI)) temp |= 4; - keyboard_at_adddata_mouse(temp); - keyboard_at_adddata_mouse(dev->x & 0xff); - keyboard_at_adddata_mouse(dev->y & 0xff); + keyboard_at_adddata_mouse_cmd(temp); + keyboard_at_adddata_mouse_cmd(dev->x & 0xff); + keyboard_at_adddata_mouse_cmd(dev->y & 0xff); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse(dev->z); + keyboard_at_adddata_mouse_cmd(dev->z); break; case 0xf2: /* read ID */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse(0x03); + keyboard_at_adddata_mouse_cmd(0x03); else - keyboard_at_adddata_mouse(0x00); + keyboard_at_adddata_mouse_cmd(0x00); break; case 0xf3: /* set command mode */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */ + keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ break; case 0xf4: /* enable */ dev->flags |= FLAG_ENABLED; mouse_scan = 1; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xf5: /* disable */ dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xff: /* reset */ +mouse_reset: dev->mode = MODE_STREAM; dev->flags &= 0x88; - mouse_scan = 0; + mouse_scan = 1; keyboard_at_mouse_reset(); - keyboard_at_adddata_mouse(0xfa); - keyboard_at_adddata_mouse(0xaa); - keyboard_at_adddata_mouse(0x00); + keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); break; default: - keyboard_at_adddata_mouse(0xfe); + keyboard_at_adddata_mouse_cmd(0xfe); } } @@ -232,6 +238,9 @@ ps2_poll(int x, int y, int z, int b, void *priv) return(0xff); #endif + if ((keyboard_at_fixed_channel() & 0xf00) == 0x200) + return(0xff); + if (!mouse_scan) return(0xff); diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 6953bda83..611ac2978 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -916,13 +916,14 @@ ide_atapi_attach(ide_t *ide) void ide_set_callback(ide_t *ide, double callback) { - ide_log("ide_set_callback(%i)\n", ide->channel); if (!ide) { - ide_log("Set callback failed\n"); + ide_log("ide_set_callback(NULL): Set callback failed\n"); return; } + ide_log("ide_set_callback(%i)\n", ide->channel); + if (callback == 0.0) timer_stop(&ide->timer); else @@ -2500,6 +2501,60 @@ id_not_found: } +uint8_t +ide_read_ali_75(void) +{ + ide_t *ide0, *ide1; + int ch0, ch1; + uint8_t ret = 0x00; + + ch0 = ide_boards[0]->cur_dev; + ch1 = ide_boards[1]->cur_dev; + ide0 = ide_drives[ch0]; + ide1 = ide_drives[ch1]; + + if (ch1) + ret |= 0x08; + if (ch0) + ret |= 0x04; + if (ide1->irqstat) + ret |= 0x02; + if (ide0->irqstat) + ret |= 0x01; + + return ret; +} + + +uint8_t +ide_read_ali_76(void) +{ + ide_t *ide0, *ide1; + int ch0, ch1; + uint8_t ret = 0x00; + + ch0 = ide_boards[0]->cur_dev; + ch1 = ide_boards[1]->cur_dev; + ide0 = ide_drives[ch0]; + ide1 = ide_drives[ch1]; + + if (ide1->atastat & BSY_STAT) + ret |= 0x40; + if (ide1->atastat & DRQ_STAT) + ret |= 0x20; + if (ide1->atastat & ERR_STAT) + ret |= 0x10; + if (ide0->atastat & BSY_STAT) + ret |= 0x04; + if (ide0->atastat & DRQ_STAT) + ret |= 0x02; + if (ide0->atastat & ERR_STAT) + ret |= 0x01; + + return ret; +} + + static void ide_set_handlers(uint8_t board) { diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 97a77388c..023883720 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -370,30 +370,49 @@ void sff_bus_master_set_irq(int channel, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; - dev->status &= ~4; + dev->status &= ~0x04; dev->status |= (channel >> 4); channel &= 0x01; - if (dev->status & 0x04) { - sff_log("SFF8038i: Channel %i IRQ raise\n", channel); - if (dev->irq_mode[channel] == 3) - picintlevel(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_set_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_set_irq(dev->slot, dev->irq_pin); - else - picint(1 << (14 + channel)); - } else { - sff_log("SFF8038i: Channel %i IRQ lower\n", channel); - if (dev->irq_mode[channel] == 3) - picintc(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_clear_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_clear_irq(dev->slot, dev->irq_pin); - else - picintc(1 << (14 + channel)); + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + if (dev->status & 0x04) + picint(1 << (14 + channel)); + else + picintc(1 << (14 + channel)); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + if (dev->status & 0x04) + pci_set_irq(dev->slot, dev->irq_pin); + else + pci_clear_irq(dev->slot, dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + if (dev->status & 0x04) + pci_set_mirq(dev->irq_mode[channel] & 1, 0); + else + pci_clear_mirq(dev->irq_mode[channel] & 1, 0); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + if (dev->status & 0x04) + picintlevel(1 << dev->irq_line); + else + picintc(1 << dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + if (dev->status & 0x04) + pci_set_mirq(channel + 2, dev->irq_level[channel]); + else + pci_clear_mirq(channel + 2, dev->irq_level[channel]); + break; } } @@ -466,10 +485,42 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } +void +sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) +{ + dev->irq_level[channel] = 0; +} + + void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); + break; + } } @@ -506,9 +557,11 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = dev->irq_mode[1] = 2; + dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ + dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ dev->irq_pin = PCI_INTA; dev->irq_line = 14; + dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; diff --git a/src/dma.c b/src/dma.c index 54e97f9e6..aa91ad988 100644 --- a/src/dma.c +++ b/src/dma.c @@ -166,6 +166,28 @@ dma_block_transfer(int channel) } +static void +dma_mem_to_mem_transfer(void) +{ + int i; + + if ((dma[0].mode & 0x0c) != 0x08) + fatal("DMA memory to memory transfer: channel 0 mode not read\n"); + if ((dma[1].mode & 0x0c) != 0x04) + fatal("DMA memory to memory transfer: channel 1 mode not write\n"); + + dma_req_is_soft = 1; + + for (i = 0; i <= dma[0].cb; i++) + dma_buffer[i] = dma_channel_read(0); + + for (i = 0; i <= dma[1].cb; i++) + dma_channel_write(1, dma_buffer[i]); + + dma_req_is_soft = 0; +} + + static void dma_sg_write(uint16_t port, uint8_t val, void *priv) { @@ -506,14 +528,18 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ dma_command[0] = val; if (val & 0x01) - fatal("Memory-to-memory enable\n"); + pclog("[%08X:%04X] Memory-to-memory enable\n", CS, cpu_state.pc); return; case 9: /*Request register */ channel = (val & 3); if (val & 4) { dma_stat_rq_pc |= (1 << channel); - dma_block_transfer(channel); + if ((channel == 0) && (dma_command[0] & 0x01)) { + pclog("Memory to memory transfer start\n"); + dma_mem_to_mem_transfer(); + } else + dma_block_transfer(channel); } else dma_stat_rq_pc &= ~(1 << channel); break; diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 08019d352..bcaf89610 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -54,7 +54,7 @@ typedef struct { uint8_t acpitst, auxen, auxsts, plvl2, plvl3, smicmd, gpio_dir, - gpio_val, muxcntrl, pad, + gpio_val, muxcntrl, ali_soft_smi, timer32, smireg, gpireg[3], gporeg[4]; uint16_t pmsts, pmen, @@ -83,7 +83,8 @@ typedef struct uint16_t io_base, aux_io_base; int vendor, slot, irq_mode, - irq_pin, irq_line; + irq_pin, irq_line, + mirq_is_level; pc_timer_t timer; nvr_t *nvr; apm_t *apm; @@ -111,8 +112,11 @@ extern void acpi_set_slot(acpi_t *dev, int slot); extern void acpi_set_irq_mode(acpi_t *dev, int irq_mode); extern void acpi_set_irq_pin(acpi_t *dev, int irq_pin); extern void acpi_set_irq_line(acpi_t *dev, int irq_line); +extern void acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level); extern void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default); extern void acpi_set_nvr(acpi_t *dev, nvr_t *nvr); +extern uint8_t acpi_ali_soft_smi_status_read(acpi_t *dev); +extern void acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi); #ifdef __cplusplus } diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 2cc8078b1..b0a3cb71f 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -25,10 +25,8 @@ extern const device_t acc2168_device; extern const device_t ali1217_device; extern const device_t ali1429_device; extern const device_t ali1489_device; -#if defined(DEV_BRANCH) && defined(USE_M154X) extern const device_t ali1531_device; extern const device_t ali1543_device; -#endif #if defined(DEV_BRANCH) && defined(USE_M6117) extern const device_t ali6117d_device; #endif @@ -44,9 +42,6 @@ extern const device_t scat_sx_device; extern const device_t cs8230_device; extern const device_t cs4031_device; -/* ETEQ */ -extern const device_t et6000_device; - /* G2 */ extern const device_t gc100_device; extern const device_t gc100a_device; @@ -60,6 +55,7 @@ extern const device_t headland_ht18c_device; /* Intel */ extern const device_t intel_82335_device; extern const device_t i420ex_device; +extern const device_t i420ex_ide_device; extern const device_t i420tx_device; extern const device_t i420zx_device; extern const device_t i430lx_device; @@ -114,7 +110,6 @@ extern const device_t sis_85c496_ls486e_device; extern const device_t sis_85c50x_device; extern const device_t sis_5511_device; extern const device_t sis_5571_device; -extern const device_t sis_5598_device; /* ST */ extern const device_t stpc_client_device; @@ -124,13 +119,6 @@ extern const device_t stpc_atlas_device; extern const device_t stpc_serial_device; extern const device_t stpc_lpt_device; -/* UMC */ -extern const device_t umc_hb4_device; -extern const device_t umc_8890_device; - -extern const device_t umc_8886f_device; -extern const device_t umc_8886af_device; - /* VIA */ extern const device_t via_vt82c49x_device; extern const device_t via_vt82c49x_pci_device; @@ -151,6 +139,7 @@ extern const device_t via_vt82c686b_device; /* VLSI */ extern const device_t vl82c480_device; +extern const device_t vl82c486_device; extern const device_t vlsi_scamp_device; /* WD */ diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 48b7c8939..c6a7a49f0 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -150,5 +150,8 @@ extern int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; +extern uint8_t ide_read_ali_75(void); +extern uint8_t ide_read_ali_76(void); + #endif /*EMU_IDE_H*/ diff --git a/src/include/86box/hdc_ide_sff8038i.h b/src/include/86box/hdc_ide_sff8038i.h index 43288aa99..305d2d40c 100644 --- a/src/include/86box/hdc_ide_sff8038i.h +++ b/src/include/86box/hdc_ide_sff8038i.h @@ -25,8 +25,8 @@ typedef struct addr; int count, eot, slot, - irq_mode[2], irq_pin, - irq_line; + irq_mode[2], irq_level[2], + irq_pin, irq_line; } sff8038i_t; @@ -47,3 +47,5 @@ extern void sff_set_irq_line(sff8038i_t *dev, int irq_line); extern void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode); extern void sff_set_irq_pin(sff8038i_t *dev, int irq_pin); + +extern void sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level); diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 3ca6089cc..206feeefc 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -72,14 +72,12 @@ extern const device_t keyboard_xt_olivetti_device; extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; -extern const device_t keyboard_at_samsung_device; extern const device_t keyboard_at_toshiba_device; extern const device_t keyboard_at_olivetti_device; extern const device_t keyboard_at_ncr_device; extern const device_t keyboard_ps2_device; extern const device_t keyboard_ps2_ps1_device; extern const device_t keyboard_ps2_ps1_pci_device; -extern const device_t keyboard_ps2_ps2_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_olivetti_device; @@ -108,12 +106,15 @@ extern int keyboard_isfsexit(void); extern int keyboard_ismsexit(void); extern void keyboard_set_is_amstrad(int ams); -extern void keyboard_at_adddata_keyboard_raw(uint8_t val); extern void keyboard_at_adddata_mouse(uint8_t val); +extern void keyboard_at_adddata_mouse_direct(uint8_t val); +extern void keyboard_at_adddata_mouse_cmd(uint8_t val); extern void keyboard_at_mouse_reset(void); extern uint8_t keyboard_at_mouse_pos(void); +extern int keyboard_at_fixed_channel(void); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); extern void keyboard_at_set_a20_key(int state); +extern void keyboard_at_set_mode(int ps2); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); extern void keyboard_at_reset(void); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index f40745a05..c63a3b991 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -96,9 +96,11 @@ enum { MACHINE_TYPE_8086, MACHINE_TYPE_286, MACHINE_TYPE_386SX, + MACHINE_TYPE_486SLC, MACHINE_TYPE_386DX, MACHINE_TYPE_386DX_486, MACHINE_TYPE_486, + MACHINE_TYPE_486_S2, MACHINE_TYPE_486_S3, MACHINE_TYPE_486_MISC, MACHINE_TYPE_SOCKET4, @@ -250,6 +252,8 @@ extern int machine_at_mr286_init(const machine_t *); extern int machine_at_neat_init(const machine_t *); extern int machine_at_neat_ami_init(const machine_t *); +extern int machine_at_quadt386sx_init(const machine_t *); + extern int machine_at_award286_init(const machine_t *); extern int machine_at_gdc212m_init(const machine_t *); extern int machine_at_gw286ct_init(const machine_t *); @@ -283,16 +287,12 @@ extern int machine_at_pja511m_init(const machine_t *); extern int machine_at_pc916sx_init(const machine_t *); -extern int machine_at_m30008_init(const machine_t *); -extern int machine_at_m30015_init(const machine_t *); - #ifdef EMU_DEVICE_H extern const device_t *at_ama932j_get_device(void); extern const device_t *at_flytech386_get_device(void); extern const device_t *at_cmdsl386sx25_get_device(void); extern const device_t *at_spc4620p_get_device(void); extern const device_t *at_spc6033p_get_device(void); -extern const device_t *at_m30008_get_device(void); #endif /* m_at_386dx_486.c */ @@ -310,6 +310,8 @@ extern int machine_at_cs4031_init(const machine_t *); extern int machine_at_pb410a_init(const machine_t *); +extern int machine_at_acerv10_init(const machine_t *); + extern int machine_at_acera1g_init(const machine_t *); extern int machine_at_ali1429_init(const machine_t *); extern int machine_at_winbios1429_init(const machine_t *); @@ -321,9 +323,9 @@ extern int machine_at_opti495_mr_init(const machine_t *); extern int machine_at_vect486vl_init(const machine_t *); extern int machine_at_d824_init(const machine_t *); -extern int machine_at_pcs46c_init(const machine_t *); - extern int machine_at_403tg_init(const machine_t *); +extern int machine_at_403tg_rev_d_init(const machine_t *); +extern int machine_at_403tg_rev_d_mr_init(const machine_t *); extern int machine_at_pc330_6573_init(const machine_t *); extern int machine_at_mvi486_init(const machine_t *); @@ -345,18 +347,16 @@ extern int machine_at_4dps_init(const machine_t *); extern int machine_at_4sa2_init(const machine_t *); extern int machine_at_m4li_init(const machine_t *); extern int machine_at_alfredo_init(const machine_t *); +extern int machine_at_ninja_init(const machine_t *); extern int machine_at_486sp3_init(const machine_t *); extern int machine_at_486sp3c_init(const machine_t *); extern int machine_at_486sp3g_init(const machine_t *); extern int machine_at_486ap4_init(const machine_t *); +extern int machine_at_g486vpa_init(const machine_t *); extern int machine_at_486vipio2_init(const machine_t *); extern int machine_at_abpb4_init(const machine_t *); extern int machine_at_win486pci_init(const machine_t *); -extern int machine_at_atc1415_init(const machine_t *); -extern int machine_at_ecs486_init(const machine_t *); -extern int machine_at_hot433_init(const machine_t *); - extern int machine_at_itoxstar_init(const machine_t *); extern int machine_at_arb1479_init(const machine_t *); extern int machine_at_pcm9340_init(const machine_t *); @@ -381,113 +381,122 @@ extern int machine_at_portableiii386_init(const machine_t *); extern const device_t *at_cpqiii_get_device(void); #endif -/* m_at_socket4_5.c */ -extern int machine_at_excalibur_init(const machine_t *); +/* m_at_socket4.c */ +extern void machine_at_premiere_common_init(const machine_t *, int); +extern void machine_at_award_common_init(const machine_t *); -extern int machine_at_pat54pv_init(const machine_t *); +extern void machine_at_sp4_common_init(const machine_t *model); -extern int machine_at_hot543_init(const machine_t *); -extern int machine_at_p54vl_init(const machine_t *); - -extern int machine_at_batman_init(const machine_t *); -extern int machine_at_ambradp60_init(const machine_t *); +extern int machine_at_p5mp3_init(const machine_t *); extern int machine_at_dellxp60_init(const machine_t *); extern int machine_at_opti560l_init(const machine_t *); +extern int machine_at_ambradp60_init(const machine_t *); extern int machine_at_valuepointp60_init(const machine_t *); -extern int machine_at_p5mp3_init(const machine_t *); -extern int machine_at_pb520r_init(const machine_t *); +extern int machine_at_revenge_init(const machine_t *); extern int machine_at_586mc1_init(const machine_t *); +extern int machine_at_pb520r_init(const machine_t *); +extern int machine_at_excalibur_init(const machine_t *); + +extern int machine_at_p5vl_init(const machine_t *); + +extern int machine_at_p5sp4_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *at_pb520r_get_device(void); +#endif + +/* m_at_socket5.c */ extern int machine_at_plato_init(const machine_t *); extern int machine_at_ambradp90_init(const machine_t *); extern int machine_at_430nx_init(const machine_t *); -extern int machine_at_p54tp4xe_init(const machine_t *); -extern int machine_at_endeavor_init(const machine_t *); -extern int machine_at_zappa_init(const machine_t *); -extern int machine_at_mb500n_init(const machine_t *); -extern int machine_at_apollo_init(const machine_t *); -extern int machine_at_vectra54_init(const machine_t *); -extern int machine_at_powermatev_init(const machine_t *); extern int machine_at_acerv30_init(const machine_t *); +extern int machine_at_apollo_init(const machine_t *); +extern int machine_at_exp8551_init(const machine_t *); +extern int machine_at_vectra54_init(const machine_t *); +extern int machine_at_zappa_init(const machine_t *); +extern int machine_at_powermatev_init(const machine_t *); +extern int machine_at_mb500n_init(const machine_t *); +extern int machine_at_hawk_init(const machine_t *); + +extern int machine_at_pat54pv_init(const machine_t *); + +extern int machine_at_hot543_init(const machine_t *); -extern int machine_at_p5sp4_init(const machine_t *); extern int machine_at_p54sp4_init(const machine_t *); extern int machine_at_sq588_init(const machine_t *); -extern int machine_at_hot539_init(const machine_t *); +#ifdef EMU_DEVICE_H +#define at_vectra54_get_device at_endeavor_get_device +#endif + +/* m_at_socket7_3v.c */ +extern int machine_at_p54tp4xe_init(const machine_t *); +extern int machine_at_mr586_init(const machine_t *); +extern int machine_at_gw2katx_init(const machine_t *); +extern int machine_at_thor_init(const machine_t *); +extern int machine_at_mrthor_init(const machine_t *); +extern int machine_at_endeavor_init(const machine_t *); +extern int machine_at_ms5119_init(const machine_t *); +extern int machine_at_pb640_init(const machine_t *); +extern int machine_at_fmb_init(const machine_t *); + +extern int machine_at_acerm3a_init(const machine_t *); +extern int machine_at_ap53_init(const machine_t *); +extern int machine_at_8500tuc_init(const machine_t *); +extern int machine_at_p55t2s_init(const machine_t *); + +extern int machine_at_gw2kte_init(const machine_t *); + +extern int machine_at_ap5s_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *at_endeavor_get_device(void); -#define at_vectra54_get_device at_endeavor_get_device -extern const device_t *at_pb520r_get_device(void); extern const device_t *at_thor_get_device(void); +extern const device_t *at_pb640_get_device(void); #endif -/* m_at_socket7_s7.c */ -extern int machine_at_ap5s_init(const machine_t *); - -extern int machine_at_chariot_init(const machine_t *); -extern int machine_at_mr586_init(const machine_t *); -extern int machine_at_thor_init(const machine_t *); -extern int machine_at_gw2katx_init(const machine_t *); -extern int machine_at_mrthor_init(const machine_t *); -extern int machine_at_pb640_init(const machine_t *); - -extern int machine_at_acerm3a_init(const machine_t *); +/* m_at_socket7.c */ extern int machine_at_acerv35n_init(const machine_t *); -extern int machine_at_ap53_init(const machine_t *); extern int machine_at_p55t2p4_init(const machine_t *); -extern int machine_at_p55t2s_init(const machine_t *); -extern int machine_at_8500tuc_init(const machine_t *); extern int machine_at_m7shi_init(const machine_t *); extern int machine_at_tc430hx_init(const machine_t *); extern int machine_at_equium5200_init(const machine_t *); extern int machine_at_pcv240_init(const machine_t *); extern int machine_at_p65up5_cp55t2d_init(const machine_t *); -extern int machine_at_mb520n_init(const machine_t *); extern int machine_at_p55tvp4_init(const machine_t *); -extern int machine_at_p55va_init(const machine_t *); -extern int machine_at_i430vx_init(const machine_t *); extern int machine_at_5ivg_init(const machine_t *); -extern int machine_at_brio80xx_init(const machine_t *); extern int machine_at_8500tvxa_init(const machine_t *); extern int machine_at_presario2240_init(const machine_t *); extern int machine_at_presario4500_init(const machine_t *); -extern int machine_at_gw2kte_init(const machine_t *); +extern int machine_at_p55va_init(const machine_t *); +extern int machine_at_brio80xx_init(const machine_t *); extern int machine_at_pb680_init(const machine_t *); +extern int machine_at_mb520n_init(const machine_t *); +extern int machine_at_i430vx_init(const machine_t *); extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); -extern int machine_at_ym430tx_init(const machine_t *); #if defined(DEV_BRANCH) && defined(NO_SIO) extern int machine_at_an430tx_init(const machine_t *); #endif +extern int machine_at_ym430tx_init(const machine_t *); extern int machine_at_mb540n_init(const machine_t *); extern int machine_at_p5mms98_init(const machine_t *); -extern int machine_at_r534f_init(const machine_t *); -extern int machine_at_ms5146_init(const machine_t *); - -#if defined(DEV_BRANCH) && defined(USE_M154X) -extern int machine_at_m560_init(const machine_t *); -extern int machine_at_ms5164_init(const machine_t *); -#endif - extern int machine_at_ficva502_init(const machine_t *); extern int machine_at_ficpa2012_init(const machine_t *); -extern int machine_at_sp97xv_init(const machine_t *); -extern int machine_at_m571_init(const machine_t *); +extern int machine_at_r534f_init(const machine_t *); +extern int machine_at_ms5146_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_thor_get_device(void); -extern const device_t *at_pb640_get_device(void); -#endif +extern int machine_at_m560_init(const machine_t *); +extern int machine_at_ms5164_init(const machine_t *); -/* m_at_super7_ss7.c */ +/* m_at_sockets7.c */ extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); extern int machine_at_ficva503a_init(const machine_t *); @@ -526,9 +535,6 @@ extern int machine_at_atc6310bxii_init(const machine_t *); extern int machine_at_686bx_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(NO_SIO) -extern int machine_at_ergox365_init(const machine_t *); -#endif extern int machine_at_ficka6130_init(const machine_t *); extern int machine_at_p3v133_init(const machine_t *); extern int machine_at_p3v4x_init(const machine_t *); @@ -560,7 +566,6 @@ extern int machine_at_apas3_init(const machine_t *); extern int machine_at_wcf681_init(const machine_t *); extern int machine_at_cuv4xls_init(const machine_t *); extern int machine_at_6via90ap_init(const machine_t *); -extern int machine_at_603tcf_init(const machine_t *); extern int machine_at_trinity371_init(const machine_t *); extern int machine_at_p6bap_init(const machine_t *); @@ -649,10 +654,6 @@ extern int machine_xt_pc700_init(const machine_t *); extern int machine_xt_iskra3104_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_HEDAKA) -extern int machine_xt_hed919_init(const machine_t *); -#endif - /* m_xt_compaq.c */ extern int machine_xt_compaq_deskpro_init(const machine_t *); extern int machine_xt_compaq_portable_init(const machine_t *); diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 210ff1d4e..8e28fbbdf 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -45,6 +45,10 @@ #define PCI_MIRQ1 1 #define PCI_MIRQ2 2 #define PCI_MIRQ3 3 +#define PCI_MIRQ4 4 +#define PCI_MIRQ5 5 +#define PCI_MIRQ6 6 +#define PCI_MIRQ7 7 #define PCI_IRQ_DISABLED -1 diff --git a/src/include/86box/pic.h b/src/include/86box/pic.h index 50ed0914e..139aa5195 100644 --- a/src/include/86box/pic.h +++ b/src/include/86box/pic.h @@ -33,6 +33,11 @@ typedef struct pic { extern pic_t pic, pic2; +extern void pic_reset_smi_irq_mask(void); +extern void pic_set_smi_irq_mask(int irq, int set); +extern uint16_t pic_get_smi_irq_status(void); +extern void pic_clear_smi_irq_status(int irq); + extern int pic_elcr_get_enabled(void); extern void pic_elcr_set_enabled(int enabled); extern void pic_elcr_io_handler(int set); diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index bf8d71048..93f6c594e 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -18,33 +18,34 @@ # define EMU_PIT_H -typedef struct { +typedef struct ctr_s { uint8_t m, ctrl, read_status, latch, s1_det, l_det, - bcd, pad; + bcd, flag_64k; - uint16_t rl; - - int rm, wm, gate, out, - newcount, clock, using_timer, latched, - state, null_count, do_read_status; + uint16_t l, rl; union { - int count; + uint16_t count; struct { - int units :4; - int tens :4; - int hundreds :4; - int thousands :4; - int myriads :4; + uint16_t units :4; + uint16_t tens :4; + uint16_t hundreds :4; + uint16_t thousands :4; + uint16_t myriads :4; }; }; - uint32_t l; + int rm, wm, gate, out, + newcount, clock, using_timer, latched, + state, null_count, do_read_status, do_load; + void (*tick_func)(struct ctr_s *ctr); void (*load_func)(uint8_t new_m, int new_count); void (*out_func)(int new_out, int old_out); + + struct PIT *pit; } ctr_t; diff --git a/src/include/86box/port_6x.h b/src/include/86box/port_6x.h new file mode 100644 index 000000000..74172728a --- /dev/null +++ b/src/include/86box/port_6x.h @@ -0,0 +1,38 @@ +/* + * 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. + * + * Header for the implementation of Port 6x used by various + * machines. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#ifndef EMU_PORT_6X_H +# define EMU_PORT_6X_H + + +#ifdef _TIMER_H_ +typedef struct +{ + uint8_t refresh, flags; + + pc_timer_t refresh_timer; +} port_6x_t; +#endif + + +extern const device_t port_6x_device; +extern const device_t port_6x_xi8088_device; +extern const device_t port_6x_ps2_device; +extern const device_t port_6x_olivetti_device; + + +#endif /*EMU_PORT_6X_H*/ diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index bf9f5526c..1786a9569 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -27,6 +27,7 @@ extern const device_t fdc37c663_ide_device; extern const device_t fdc37c665_device; extern const device_t fdc37c665_ide_device; extern const device_t fdc37c666_device; +extern const device_t fdc37c67x_device; extern const device_t fdc37c669_device; extern const device_t fdc37c669_370_device; extern const device_t fdc37c931apm_device; @@ -53,6 +54,7 @@ extern const device_t pc87311_ide_device; extern const device_t pc87332_device; extern const device_t pc87332_398_device; extern const device_t pc87332_398_ide_device; +extern const device_t pc87332_398_ide_sec_device; extern const device_t pc87332_398_ide_fdcon_device; extern const device_t pc97307_device; extern const device_t prime3b_device; diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 53492d0e8..db283cc87 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -106,6 +106,7 @@ typedef struct { extern void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size); extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); #endif /*EMU_SPD_H*/ diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 73c176742..78a13b346 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -23,8 +23,9 @@ #define FLAG_EXT_WRITE 4 #define FLAG_LATCH8 8 #define FLAG_NOSKEW 16 -#define FLAG_ADDR_BY16 32 +#define FLAG_ADDR_BY16 32 +#define FLAG_128K_MASK 64 typedef struct { int ena, @@ -49,7 +50,8 @@ typedef struct svga_t lowres, interlace, linedbl, rowcount, set_reset_disabled, bpp, ramdac_type, fb_only, readmode, writemode, readplane, - hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven; + hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven, + fcr, hblank_overscan; int dac_addr, dac_pos, dac_r, dac_g, vtotal, dispend, vsyncstart, split, vblankstart, @@ -59,8 +61,9 @@ typedef struct svga_t con, cursoron, blink, scrollcache, char_width, firstline, lastline, firstline_draw, lastline_draw, displine, fullchange, x_add, y_add, pan, - vram_display_mask, vidclock, - hwcursor_on, dac_hwcursor_on, overlay_on, set_override; + vram_display_mask, vidclock, dots_per_clock, hblank_ext, + hwcursor_on, dac_hwcursor_on, overlay_on, set_override, + hblankstart, hblankend, hblank_sub, hblank_end_val, hblank_end_len; /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : 0MB-1MB - VRAM diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 46c37f655..1bae05385 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -44,6 +44,8 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); +void svga_render_8bpp_tseng_lowres(svga_t *svga); +void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga); void svga_render_8bpp_gs_highres(svga_t *svga); void svga_render_8bpp_rgb_lowres(svga_t *svga); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index a28aecffb..d2cfec0dd 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -252,7 +252,11 @@ extern const device_t ogc_m24_device; /* NCR NGA */ extern const device_t nga_device; +/* Tseng ET3000AX */ +extern const device_t et3000_isa_device; + /* Tseng ET4000AX */ +extern const device_t et4000_tc6058af_isa_device; extern const device_t et4000_isa_device; extern const device_t et4000k_isa_device; extern const device_t et4000k_tg286_isa_device; @@ -304,7 +308,6 @@ extern const device_t oti037c_device; extern const device_t oti067_device; extern const device_t oti067_acer386_device; extern const device_t oti067_ama932j_device; -extern const device_t oti067_m300_device; extern const device_t oti077_device; /* Paradise/WD (S)VGA */ diff --git a/src/log.c b/src/log.c index a20a8d520..99bab97a5 100644 --- a/src/log.c +++ b/src/log.c @@ -43,6 +43,9 @@ typedef struct } log_t; +extern FILE *stdlog; /* file to log output to */ + + void log_set_suppr_seen(void *priv, int suppr_seen) { diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 9b16413f6..f7b276ba7 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -19,8 +19,9 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_amstrad.c m_europc.c m_xt_olivetti.c m_tandy.c m_at.c m_at_commodore.c m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c - m_at_socket4_5.c m_at_socket7.c m_at_sockets7.c m_at_socket8.c - m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_misc.c) + m_at_socket4.c m_at_socket5.c m_at_socket7_3v.c m_at_socket7.c + m_at_sockets7.c m_at_socket8.c m_at_slot1.c m_at_slot2.c m_at_socket370.c + m_at_misc.c) if(HEDAKA) target_compile_definitions(mch PRIVATE USE_HEDAKA) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 0e5589927..dc47b6207 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -56,6 +56,7 @@ #include <86box/lpt.h> #include <86box/rom.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/machine.h> @@ -69,6 +70,10 @@ machine_at_common_init_ex(const machine_t *model, int type) pic2_init(); dma16_init(); + if (!(type & 4)) + device_add(&port_6x_device); + type &= 3; + if (type == 1) device_add(&ibmat_nvr_device); else if (type == 0) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 3d691c159..7c9bea86b 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -37,6 +37,7 @@ #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/sio.h> #include <86box/serial.h> #include <86box/video.h> @@ -141,7 +142,7 @@ machine_at_quadt286_init(const machine_t *model) return ret; machine_at_common_init(model); - device_add(&keyboard_at_device); + device_add(&keyboard_at_device); if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); @@ -152,6 +153,30 @@ machine_at_quadt286_init(const machine_t *model) } +int +machine_at_quadt386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/quadt386sx/QTC-SXM-EVEN-U3-05-07.BIN", + "roms/machines/quadt386sx/QTC-SXM-ODD-U3-05-07.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&headland_gc10x_device); + + return ret; +} + + int machine_at_neat_init(const machine_t *model) { @@ -723,6 +748,7 @@ machine_at_pja511m_init(const machine_t *model) return ret; } + #endif /* @@ -750,6 +776,7 @@ machine_at_pc8_init(const machine_t *model) return ret; } + /* * Current bugs: * - ctrl-alt-del produces an 8042 error @@ -783,6 +810,7 @@ machine_at_3302_init(const machine_t *model) return ret; } + /* * Current bugs: * - soft-reboot after saving CMOS settings/pressing ctrl-alt-del produces an 8042 error @@ -810,6 +838,7 @@ machine_at_pc916sx_init(const machine_t *model) return ret; } + #if defined(DEV_BRANCH) && defined(USE_OLIVETTI) int machine_at_m290_init(const machine_t *model) @@ -822,9 +851,10 @@ machine_at_m290_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 4); device_add(&keyboard_at_olivetti_device); - + device_add(&port_6x_olivetti_device); + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); @@ -833,58 +863,3 @@ machine_at_m290_init(const machine_t *model) return ret; } #endif - -const device_t * -at_m30008_get_device(void) -{ - return &oti067_m300_device; -} - -int -machine_at_m30008_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/m30008/BIOS.ROM", - 0x000f0000, 65536, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - device_add(&opti283_device); - device_add(&keyboard_ps2_olivetti_device); - device_add(&pc87310_ide_device); - - if (gfxcard == VID_INTERNAL) - device_add(&oti067_m300_device); - - return ret; -} - -/* Almost identical to M300-08, save for CPU speed, VRAM, and BIOS identification string */ -int -machine_at_m30015_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/m30015/BIOS.ROM", - 0x000f0000, 65536, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - device_add(&opti283_device); - device_add(&keyboard_ps2_olivetti_device); - device_add(&pc87310_ide_device); - - /* Stock VRAM is maxed out, so no need to expose video card config */ - if (gfxcard == VID_INTERNAL) - device_add(&oti067_m300_device); - - return ret; -} - diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index aebfa45ee..eb6efeb96 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -32,12 +32,17 @@ #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> +#include <86box/dma.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> +#include <86box/gameport.h> +#include <86box/pic.h> +#include <86box/pit.h> #include <86box/rom.h> #include <86box/sio.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/video.h> #include <86box/flash.h> #include <86box/scsi_ncr53c8xx.h> @@ -229,7 +234,7 @@ machine_at_spc6000a_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&keyboard_at_samsung_device); + device_add(&keyboard_at_ami_device); return ret; } @@ -297,7 +302,7 @@ machine_at_cs4031_init(const machine_t *model) device_add(&keyboard_at_ami_device); if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); return ret; } @@ -359,6 +364,7 @@ at_vect486vl_get_device(void) return &gd5428_onboard_device; } + int machine_at_d824_init(const machine_t *model) { @@ -382,39 +388,13 @@ machine_at_d824_init(const machine_t *model) return ret; } + const device_t * at_d824_get_device(void) { return &gd5428_onboard_device; } -int -machine_at_pcs46c_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/pcs46c/OLIVETTI.BIN", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_ide_init(model); - - device_add(&et6000_device); - device_add(&keyboard_ps2_device); - - if (gfxcard == VID_INTERNAL) - device_add(&gd5428_onboard_device); - - return ret; -} - -const device_t * -at_pcs46c_get_device(void) -{ - return &gd5428_onboard_device; -} int machine_at_acera1g_init(const machine_t *model) @@ -437,7 +417,7 @@ machine_at_acera1g_init(const machine_t *model) device_add(&ide_isa_2ch_device); if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); return ret; } @@ -450,6 +430,30 @@ at_acera1g_get_device(void) } +int +machine_at_acerv10_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerv10/ALL.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&sis_85c461_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_isa_2ch_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + static void machine_at_ali1429_common_init(const machine_t *model) { @@ -569,6 +573,25 @@ machine_at_opti495_mr_init(const machine_t *model) return ret; } + +static void +machine_at_403tg_common_init(const machine_t *model, int nvr_hack) +{ + if (nvr_hack) { + machine_at_common_init_ex(model, 2); + device_add(&ls486e_nvr_device); + } else + machine_at_common_init(model); + + device_add(&opti895_device); + + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); +} + + int machine_at_403tg_init(const machine_t *model) { @@ -580,14 +603,41 @@ machine_at_403tg_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_403tg_common_init(model, 0); - device_add(&opti895_device); + return ret; +} - device_add(&keyboard_at_device); - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); +int +machine_at_403tg_rev_d_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/403tg_rev_d/J403TGRevD.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_403tg_common_init(model, 1); + + return ret; +} + + +int +machine_at_403tg_rev_d_mr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/403tg_rev_d/MRBiosOPT895.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_403tg_common_init(model, 0); return ret; } @@ -685,7 +735,7 @@ machine_at_vli486sv2g_init(const machine_t *model) machine_at_sis_85c471_common_init(model); device_add(&ide_vlb_2ch_device); - device_add(&keyboard_at_device); + device_add(&keyboard_ps2_ami_device); return ret; } @@ -884,7 +934,7 @@ machine_at_4dps_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&w83787f_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_at_ami_device); device_add(&intel_flash_bxt_device); @@ -940,10 +990,13 @@ machine_at_4sa2_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - device_add(&w83787f_device); - device_add(&keyboard_ps2_pci_device); + // device_add(&w83787f_device); + device_add(&prime3b_device); + // device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); - device_add(&intel_flash_bxt_device); + // device_add(&intel_flash_bxt_device); + device_add(&sst_flash_29ee010_device); return ret; } @@ -970,7 +1023,7 @@ machine_at_alfredo_init(const machine_t *model) pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_pci_device); device_add(&sio_device); device_add(&fdc37c663_device); device_add(&intel_flash_bxt_ami_device); @@ -981,6 +1034,34 @@ machine_at_alfredo_init(const machine_t *model) } +int +machine_at_ninja_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/ninja/1008AY0_.BIO", + "roms/machines/ninja/1008AY0_.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x05, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 2, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 1, 2, 1); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i420ex_device); + device_add(&i82091aa_device); + + return ret; +} + + int machine_at_486sp3_init(const machine_t *model) { @@ -1071,7 +1152,7 @@ machine_at_486ap4_init(const machine_t *model) device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */ if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); device_add(&i420ex_device); @@ -1079,6 +1160,36 @@ machine_at_486ap4_init(const machine_t *model) } +int +machine_at_g486vpa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/g486vpa/3.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&via_vt82c49x_pci_ide_device); + device_add(&via_vt82c505_device); + device_add(&pc87332_398_ide_sec_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + int machine_at_486vipio2_init(const machine_t *model) { @@ -1165,99 +1276,6 @@ machine_at_win486pci_init(const machine_t *model) } -int -machine_at_atc1415_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/atc1415/1415V330.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - - device_add(&umc_hb4_device); - device_add(&umc_8886af_device); - device_add(&keyboard_at_ami_device); - - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); - - return ret; -} - - -int -machine_at_ecs486_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ecs486/8810AIO.32J", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0d, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0f, PCI_CARD_IDE, 0, 0, 0, 0); - - device_add(&umc_hb4_device); - device_add(&umc_8886f_device); - device_add(&ide_cmd640_pci_legacy_only_device); - device_add(&fdc37c665_device); - device_add(&keyboard_at_ami_device); - - return ret; -} - - -int -machine_at_hot433_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/hot433/433AUS33.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0d, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0f, PCI_CARD_NORMAL, 2, 3, 4, 1); - - device_add(&umc_hb4_device); - device_add(&umc_8886af_device); - device_add(&um8669f_device); - device_add(&intel_flash_bxt_device); - device_add(&keyboard_at_ami_device); - - return ret; -} - - int machine_at_itoxstar_init(const machine_t *model) { diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 1ab48f7b4..abc6a6a85 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -486,37 +486,6 @@ at_tsunamiatx_get_device(void) return &es1371_onboard_device; } -#if defined(DEV_BRANCH) && defined(NO_SIO) -int -machine_at_ergox365_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ergox365/M63v115.rom", - 0x00080000, 524288, 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, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x08, PCI_CARD_VIDEO, 3, 0, 0, 0); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c665_device); /* Placeholder for the SM(S)C FDC37C675 */ - device_add(&sst_flash_39sf040_device); /* Placeholder for the Intel 28F004 flash chip */ - spd_register(SPD_TYPE_SDRAM, 0xF, 256); - - return ret; -} -#endif int machine_at_ficka6130_init(const machine_t *model) @@ -648,8 +617,10 @@ machine_at_vei8_init(const machine_t *model) device_add(&piix4e_device); device_add(&fdc37m60x_370_device); device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9250_08)); device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0x3, 512); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ return ret; } diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index b7a83befb..a6d8a9a09 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -100,7 +100,7 @@ machine_at_trinity371_init(const machine_t *model) device_add(&i440bx_device); device_add(&piix4e_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&w83977f_370_device); + device_add(&w83977ef_370_device); device_add(&intel_flash_bxt_device); return ret; @@ -453,39 +453,3 @@ machine_at_6via90ap_init(const machine_t *model) return ret; } - - -int -machine_at_603tcf_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/603tcf/603tcfA4.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, 1, 2, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - device_add(&via_vt8601_device); - device_add(&via_vt82c686b_device); - device_add(&via_vt82c686_sio_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 512); - device_add(&via_vt82c686_hwm_device); /* fans: 1, 2; temperatures: CPU, System, unused */ - hwm_values.temperatures[0] += 2; /* CPU offset */ - hwm_values.temperatures[1] += 2; /* System offset */ - hwm_values.temperatures[2] = 0; /* unused */ - - return ret; -} diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c new file mode 100644 index 000000000..16673b22f --- /dev/null +++ b/src/machine/m_at_socket4.c @@ -0,0 +1,406 @@ +/* + * 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 Socket 4 machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/fdc_ext.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> +#include <86box/sio.h> +#include <86box/video.h> +#include <86box/machine.h> + + +void +machine_at_premiere_common_init(const machine_t *model, int pci_switch) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | pci_switch); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); +} + + +void +machine_at_award_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ + pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + // device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); +} + + +void +machine_at_sp4_common_init(const machine_t *model) +{ + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + /* Excluded: 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11, 12, 13, 14 */ + pci_register_slot(0x0D, PCI_CARD_IDE, 1, 2, 3, 4); + /* Excluded: 02, 03*, 04*, 05*, 06*, 07*, 08* */ + /* Slots: 09 (04), 0A (03), 0B (02), 0C (07) */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&sis_85c50x_device); + device_add(&ide_cmd640_pci_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); +} + + +int +machine_at_p5mp3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5mp3/0205.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 05 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x03, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 03 = Slot 3 */ + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_pci_device); + + device_add(&sio_zb_device); + device_add(&catalyst_flash_device); + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_dellxp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/dellxp60/XP60-A08.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + /* Not: 00, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F. */ + /* Yes: 01, 10, 11, 12, 13, 14. */ + pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 4, 4, 3, 3); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 4, 3, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_opti560l_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/opti560l/560L_A06.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 4, 4, 3, 3); + pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 4, 3, 2); + pci_register_slot(0x08, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&i82091aa_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_ambradp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/ambradp60/1004AF1P.BIO", + "roms/machines/ambradp60/1004AF1P.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, 0); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_valuepointp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/valuepointp60/1006AV0M.BIO", + "roms/machines/valuepointp60/1006AV0M.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ps1_pci_device); + device_add(&sio_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_revenge_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/revenge/1009af2_.bio", + "roms/machines/revenge/1009af2_.bi1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, 0); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_586mc1_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/586mc1/IS.34", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&sio_device); + device_add(&intel_flash_bxt_device); + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_pb520r_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/pb520r/1009bc0r.bio", + "roms/machines/pb520r/1009bc0r.bi1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_VIDEO, 3, 3, 3, 3); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&ide_cmd640_pci_single_channel_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5434_onboard_pci_device); + + device_add(&keyboard_ps2_pci_device); + device_add(&sio_zb_device); + device_add(&i82091aa_ide_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + +const device_t * +at_pb520r_get_device(void) +{ + return &gd5434_onboard_pci_device; +} + + +int +machine_at_excalibur_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excalibur/S75P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti5x7_device); + device_add(&ide_opti611_vlb_device); + device_add(&fdc37c661_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + + return ret; +} + + +int +machine_at_p5vl_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5vl/SM507.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_p5sp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5sp4/0106.001", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sp4_common_init(model); + + return ret; +} diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c new file mode 100644 index 000000000..2748210e0 --- /dev/null +++ b/src/machine/m_at_socket5.c @@ -0,0 +1,446 @@ +/* + * 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 Socket 5 machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/fdc_ext.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> +#include <86box/sio.h> +#include <86box/video.h> +#include <86box/machine.h> + + +int +machine_at_plato_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/plato/1016ax1_.bio", + "roms/machines/plato/1016ax1_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, PCI_CAN_SWITCH_TYPE); + + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_ambradp90_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/ambradp90/1002AX1P.BIO", + "roms/machines/ambradp90/1002AX1P.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, PCI_CAN_SWITCH_TYPE); + + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_430nx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/430nx/IP.20", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&sio_device); + device_add(&intel_flash_bxt_device); + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_acerv30_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerv30/V30R01N9.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_acer_pci_device); + device_add(&fdc37c665_device); + + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_apollo_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/apollo/S728P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_apollo_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87332_398_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_exp8551_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/exp8551/AMI20.BIO", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&w83787f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_vectra54_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vectra54/GT0724.22", + 0x000e0000, 131072, 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(0x0F, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_VIDEO, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c931apm_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_zappa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/zappa/1006bs0_.bio", + "roms/machines/zappa/1006bs0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_powermatev_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/powermatev/BIOS.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_mb500n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mb500n/031396s.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_hawk_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hawk/HAWK.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_pat54pv_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pat54pv/pat54pv.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti5x7_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_hot543_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hot543/543_R21.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_p54sp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54sp4/SI5I0204.AWD", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sp4_common_init(model); + + return ret; +} + + +int +machine_at_sq588_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sq588/sq588b03.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + /* Correct: 0D (01), 0F (02), 11 (03), 13 (04) */ + pci_register_slot(0x02, PCI_CARD_IDE, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&sis_85c50x_device); + device_add(&ide_cmd640_pci_single_channel_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_ide_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} \ No newline at end of file diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 5ba8a69a3..112be1c60 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of Socket 7 machines. + * Implementation of Socket 7 (Dual Voltage) machines. * * * @@ -45,239 +45,6 @@ #include <86box/fdc.h> #include <86box/nvr.h> -int -machine_at_ap5s_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ap5s/AP5S150.BIN", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 3, 2, 1); - - device_add(&sis_5511_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c665_device); - device_add(&sst_flash_29ee010_device); - - return ret; -} - -int -machine_at_chariot_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/chariot/P5IV183.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - 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, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 3, 2, 1); - - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -int -machine_at_mr586_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/mr586/TRITON.BIO", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - 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, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -static void -machine_at_thor_common_init(const machine_t *model, int mr) -{ - machine_at_common_init_ex(model, mr); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - - device_add(&keyboard_ps2_ami_pci_device); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); -} - - -int -machine_at_thor_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined("roms/machines/thor/1006cn0_.bio", - "roms/machines/thor/1006cn0_.bi1", 0x20000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 0); - - return ret; -} - - -int -machine_at_gw2katx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined("roms/machines/gw2katx/1003cn0t.bio", - "roms/machines/gw2katx/1003cn0t.bi1", 0x20000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 0); - - return ret; -} - - -int -machine_at_mrthor_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/mrthor/mr_atx.bio", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 1); - - return ret; -} - - -int -machine_at_pb640_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined("roms/machines/pb640/1007CP0R.BIO", - "roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430fx_rev02_device); - device_add(&piix_rev02_device); - - if (gfxcard == VID_INTERNAL) - device_add(&gd5440_onboard_pci_device); - - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - -const device_t * -at_pb640_get_device(void) -{ - return &gd5440_onboard_pci_device; -} - - -int -machine_at_acerm3a_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/acerm3a/r01-b3.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - 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, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_pci_device); - device_add(&fdc37c932fr_device); - - device_add(&sst_flash_29ee010_device); - - return ret; -} - int machine_at_acerv35n_init(const machine_t *model) @@ -311,37 +78,6 @@ machine_at_acerv35n_init(const machine_t *model) } -int -machine_at_ap53_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ap53/ap53r2c0.rom", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_VIDEO, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c669_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - - int machine_at_p55t2p4_init(const machine_t *model) { @@ -372,66 +108,6 @@ machine_at_p55t2p4_init(const machine_t *model) } -int -machine_at_p55t2s_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/p55t2s/s6y08t.rom", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - - -int -machine_at_8500tuc_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/8500tuc/Tuc0221b.rom", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&um8669f_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - - int machine_at_m7shi_init(const machine_t *model) { @@ -461,6 +137,7 @@ machine_at_m7shi_init(const machine_t *model) return ret; } + int machine_at_tc430hx_init(const machine_t *model) { @@ -496,8 +173,9 @@ machine_at_tc430hx_init(const machine_t *model) } +/* Information about that machine on machine.h */ int -machine_at_equium5200_init(const machine_t *model) // Information about that machine on machine.h +machine_at_equium5200_init(const machine_t *model) { int ret; @@ -530,6 +208,7 @@ machine_at_equium5200_init(const machine_t *model) // Information about that mac return ret; } + int machine_at_pcv240_init(const machine_t *model) { @@ -564,6 +243,7 @@ machine_at_pcv240_init(const machine_t *model) return ret; } + int machine_at_p65up5_cp55t2d_init(const machine_t *model) { @@ -581,36 +261,6 @@ machine_at_p65up5_cp55t2d_init(const machine_t *model) } -int -machine_at_mb520n_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/mb520n/520n503s.rom", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c669_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - - int machine_at_p55tvp4_init(const machine_t *model) { @@ -640,6 +290,7 @@ machine_at_p55tvp4_init(const machine_t *model) return ret; } + int machine_at_5ivg_init(const machine_t *model) { @@ -668,92 +319,6 @@ machine_at_5ivg_init(const machine_t *model) return ret; } -int -machine_at_i430vx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/430vx/55xwuq0e.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_pci_device); - device_add(&um8669f_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -int -machine_at_p55va_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/p55va/va021297.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c932fr_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -int -machine_at_brio80xx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/brio80xx/Hf0705.rom", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_VIDEO, 4, 0, 0, 0); - pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c935_device); - device_add(&sst_flash_29ee020_device); - - return ret; -} int machine_at_8500tvxa_init(const machine_t *model) @@ -843,6 +408,66 @@ machine_at_presario4500_init(const machine_t *model) } +int +machine_at_p55va_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p55va/va021297.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_brio80xx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/brio80xx/Hf0705.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c935_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + int machine_at_pb680_init(const machine_t *model) { @@ -878,16 +503,12 @@ machine_at_pb680_init(const machine_t *model) int -machine_at_gw2kte_init(const machine_t *model) +machine_at_mb520n_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined2("roms/machines/gw2kte/1008CY1T.BIO", - "roms/machines/gw2kte/1008CY1T.BI1", - "roms/machines/gw2kte/1008CY1T.BI2", - "roms/machines/gw2kte/1008CY1T.BI3", - "roms/machines/gw2kte/1008CY1T.RCV", - 0x3a000, 128); + ret = bios_load_linear("roms/machines/mb520n/520n503s.rom", + 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; @@ -896,17 +517,46 @@ machine_at_gw2kte_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c932fr_device); - device_add(&intel_flash_bxt_ami_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_i430vx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/430vx/55xwuq0e.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); return ret; } @@ -949,6 +599,7 @@ machine_at_nupro592_init(const machine_t *model) return ret; } + int machine_at_tx97_init(const machine_t *model) { @@ -989,39 +640,6 @@ machine_at_tx97_init(const machine_t *model) } -int -machine_at_ym430tx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ym430tx/YM430TX.003", - 0x000e0000, 131072, 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(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i430tx_device); - device_add(&piix4_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977tf_device); - device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} - - #if defined(DEV_BRANCH) && defined(NO_SIO) int machine_at_an430tx_init(const machine_t *model) @@ -1060,6 +678,39 @@ machine_at_an430tx_init(const machine_t *model) #endif +int +machine_at_ym430tx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ym430tx/YM430TX.003", + 0x000e0000, 131072, 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(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430tx_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83977tf_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + int machine_at_mb540n_init(const machine_t *model) { @@ -1123,132 +774,6 @@ machine_at_p5mms98_init(const machine_t *model) return ret; } -#if defined(DEV_BRANCH) && defined(USE_M154X) -int -machine_at_m560_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/m560/5600410s.ami", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&ali1531_device); - device_add(&ali1543_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} - -int -machine_at_ms5164_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ms5164/W564MS43.005", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); - - device_add(&ali1531_device); - device_add(&ali1543_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} -#endif - -int -machine_at_r534f_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/r534f/r534f008.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - - device_add(&sis_5571_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&w83877f_device); - device_add(&sst_flash_29ee010_device); - - return ret; -} - -int -machine_at_ms5146_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ms5146/A546MS11.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); - - device_add(&sis_5571_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&w83877f_device); - device_add(&sst_flash_29ee010_device); - - return ret; -} int machine_at_ficva502_init(const machine_t *model) @@ -1313,12 +838,73 @@ machine_at_ficpa2012_init(const machine_t *model) return ret; } + int -machine_at_sp97xv_init(const machine_t *model) +machine_at_r534f_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/sp97xv/0109XV.005", + ret = bios_load_linear("roms/machines/r534f/r534f008.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&sis_5571_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_ms5146_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms5146/A546MS11.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&sis_5571_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_m560_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m560/5600410s.ami", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -1328,22 +914,31 @@ machine_at_sp97xv_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - device_add(&sis_5598_device); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&ali1531_device); + device_add(&ali1543_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&w83877f_device); device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); return ret; } + int -machine_at_m571_init(const machine_t *model) +machine_at_ms5164_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/m571/2k0621s.rom", - 0x000c0000, 262144, 0); + ret = bios_load_linear("roms/machines/ms5164/W564MS43.005", + 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; @@ -1352,15 +947,21 @@ machine_at_m571_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); - device_add(&sis_5598_device); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE, 5, 6, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&ali1531_device); + device_add(&ali1543_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&it8661f_device); - device_add(&sst_flash_29ee020_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); return ret; } diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c new file mode 100644 index 000000000..f31aeed33 --- /dev/null +++ b/src/machine/m_at_socket7_3v.c @@ -0,0 +1,514 @@ +/* + * 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 Socket 7 (Single Voltage) machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2010-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/sio.h> +#include <86box/hwm.h> +#include <86box/video.h> +#include <86box/spd.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/nvr.h> + + +static void +machine_at_thor_common_init(const machine_t *model, int mr) +{ + machine_at_common_init_ex(model, mr); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + // device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); +} + + +int +machine_at_p54tp4xe_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54tp4xe/t15i0302.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + /* Award BIOS, SMC FDC37C665. */ + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_mr586_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mr586/TRITON.BIO", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_gw2katx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/gw2katx/1003cn0t.bio", + "roms/machines/gw2katx/1003cn0t.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + + +int +machine_at_thor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/thor/1006cn0_.bio", + "roms/machines/thor/1006cn0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + + +int +machine_at_mrthor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mrthor/mr_atx.bio", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 1); + + return ret; +} + + +int +machine_at_endeavor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/endeavor/1006cb0_.bio", + "roms/machines/endeavor/1006cb0_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +const device_t * +at_endeavor_get_device(void) +{ + return &s3_phoenix_trio64_onboard_pci_device; +} + + +int +machine_at_ms5119_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms5119/A37E.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x0d, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0e, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0f, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83787f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_pb640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/pb640/1007CP0R.BIO", + "roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430fx_rev02_device); + device_add(&piix_rev02_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5440_onboard_pci_device); + + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +const device_t * +at_pb640_get_device(void) +{ + return &gd5440_onboard_pci_device; +} + + +int +machine_at_fmb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/fmb/P5IV183.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 3, 2, 1); + + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83787f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_acerm3a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerm3a/r01-b3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + 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, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_ap53_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ap53/ap53r2c0.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_VIDEO, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_8500tuc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/8500tuc/Tuc0221b.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p55t2s/s6y08t.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_gw2kte_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2("roms/machines/gw2kte/1008CY1T.BIO", + "roms/machines/gw2kte/1008CY1T.BI1", + "roms/machines/gw2kte/1008CY1T.BI2", + "roms/machines/gw2kte/1008CY1T.BI3", + "roms/machines/gw2kte/1008CY1T.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_ap5s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ap5s/AP5S150.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 3, 2, 1); + + device_add(&sis_5511_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 1aa892415..572d6ec48 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -62,6 +62,8 @@ machine_at_p6rp4_init(const machine_t *model) pci_register_slot(0x08, PCI_CARD_IDE, 0, 0, 0, 0); device_add(&i450kx_device); device_add(&sio_zb_device); + // device_add(&keyboard_ps2_ami_pci_device); + /* Input port bit 2 must be 1 or CMOS Setup is disabled. */ device_add(&keyboard_ps2_ami_pci_device); device_add(&fdc37c665_device); device_add(&ide_cmd640_pci_device); diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 33b67aabe..ca444421c 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -59,6 +59,7 @@ #include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/port_6x.h> #include <86box/sound.h> #include <86box/snd_sn76489.h> #include <86box/video.h> @@ -514,6 +515,7 @@ ps1_common_init(const machine_t *model) pic2_init(); device_add(&keyboard_ps2_ps1_device); + device_add(&port_6x_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ standalone_gameport_type = &gameport_201_device; diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 0b9dbaeb4..987b29f2e 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -15,6 +15,7 @@ #include <86box/nvr.h> #include <86box/keyboard.h> #include <86box/lpt.h> +#include <86box/port_6x.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/hdc.h> @@ -186,7 +187,8 @@ machine_ps2_m30_286_init(const machine_t *model) refresh_at_enable = 1; pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); dma16_init(); - device_add(&keyboard_ps2_ps2_device); + device_add(&keyboard_ps2_device); + device_add(&port_6x_ps2_device); device_add(&ps_nvr_device); pic2_init(); ps2board_init(); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 59a3fe535..b1b611d94 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -63,6 +63,7 @@ #include <86box/keyboard.h> #include <86box/lpt.h> #include <86box/mouse.h> +#include <86box/port_6x.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/video.h> @@ -793,7 +794,8 @@ static void ps2_mca_board_common_init() io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - device_add(&port_92_device); + device_add(&port_6x_ps2_device); + device_add(&port_92_device); ps2.setup = 0xff; diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 127495259..e356d1cbb 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -290,28 +290,6 @@ machine_xt_pcxt_init(const machine_t *model) } -#if defined(DEV_BRANCH) && defined(USE_HEDAKA) -int -machine_xt_hed919_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/hed919/Hedaka_HED-919_bios_version_3.28f.bin", - 0x000fe000, 8192, 0); - - if (bios_only || !ret) - return ret; - - machine_xt_clone_init(model); - - if (mem_size > 640) - mem_remap_top(mem_size - 640); - - return ret; -} -#endif - - int machine_xt_pxxt_init(const machine_t *model) { diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index bc9edb672..3a5c6da80 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -44,6 +44,7 @@ #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/gameport.h> +#include <86box/port_6x.h> #include <86box/sound.h> #include <86box/snd_speaker.h> #include <86box/video.h> @@ -765,6 +766,9 @@ machine_xt_m240_init(const machine_t *model) pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + /* Address 66-67 = mainboard dip-switch settings */ + io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, NULL); + /* * port 60: should return jumper settings only under unknown conditions * SWB on mainboard (off=1) @@ -772,6 +776,7 @@ machine_xt_m240_init(const machine_t *model) * bit 6 - use OCG/CGA display adapter (on) / other display adapter (off) */ device_add(&keyboard_at_olivetti_device); + device_add(&port_6x_olivetti_device); /* FIXME: make sure this is correct?? */ device_add(&at_nvr_device); diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index d7a127119..891469cc5 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -19,6 +19,7 @@ #include <86box/lpt.h> #include <86box/rom.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/video.h> #include <86box/machine.h> #include "cpu.h" @@ -178,6 +179,7 @@ machine_xt_xi8088_init(const machine_t *model) device_add(&fdc_at_device); device_add(&keyboard_ps2_xi8088_device); + device_add(&port_6x_xi8088_device); nmi_init(); device_add(&ibmat_nvr_device); pic2_init(); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index a952c2b4e..75dad8e60 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -39,10 +39,12 @@ const machine_type_t machine_types[] = { { "8086", MACHINE_TYPE_8086 }, { "80286", MACHINE_TYPE_286 }, { "i386SX", MACHINE_TYPE_386SX }, + { "486SLC", MACHINE_TYPE_486SLC }, { "i386DX", MACHINE_TYPE_386DX }, { "i386DX/i486", MACHINE_TYPE_386DX_486 }, { "i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, - { "i486 (Socket 2 and 3)", MACHINE_TYPE_486_S3 }, + { "i486 (Socket 2)", MACHINE_TYPE_486_S2 }, + { "i486 (Socket 3)", MACHINE_TYPE_486_S3 }, { "i486 (Miscellaneous)", MACHINE_TYPE_486_MISC }, { "Socket 4", MACHINE_TYPE_SOCKET4 }, { "Socket 5", MACHINE_TYPE_SOCKET5 }, @@ -58,6 +60,49 @@ const machine_type_t machine_types[] = { }; +/* Machines to add before machine freeze: + - Jetway J-403TG MR BIOS v2.02; + - Matsonic MS6260S (AMI Super Socket 7 with Aladdin V chipset); + - PCChips M773 (440BX + SMSC with AMI BIOS); + - Rise R418 (was removed on my end, has to be re-added); + - TMC Mycomp PCI54ST; + - Zeos Quadtel 486. + + NOTE: The AMI MegaKey tests were done on a real Intel Advanced/ATX + (thanks, MrKsoft for running my AMIKEY.COM on it), but the + technical specifications of the other Intel machines confirm + that the other boards also have the MegaKey. + + NOTE: The later (ie. not AMI Color) Intel AMI BIOS'es execute a + sequence of commands (B8, BA, BB) during one of the very first + phases of POST, in a way that is only valid on the AMIKey-3 + KBC firmware, that includes the Classic PCI/ED (Ninja) BIOS + which otherwise does not execute any AMI KBC commands, which + indicates that the sequence is a leftover of whatever AMI + BIOS (likely a laptop one since the AMIKey-3 is a laptop KBC + firmware!) Intel forked. + + NOTE: The VIA VT82C42N returns 0x46 ('F') in command 0xA1 (so it + emulates the AMI KF/AMIKey KBC firmware), and 0x42 ('B') in + command 0xAF. + The version on the VIA VT82C686B southbridge also returns + 'F' in command 0xA1, but 0x45 ('E') in command 0xAF. + + NOTE: The AMI MegaKey commands blanked in the technical reference + are CC and and C4, which are Set P14 High and Set P14 Low, + respectively. Also, AMI KBC command C1, mysteriously missing + from the technical references of AMI MegaKey and earlier, is + Write Input Port, same as on AMIKey-3. + + Machines to remove: + - Hedaka HED-919; + - A-Trend ATC-1415; + - ECS Elite UM8810PAIO; + - Shuttle HOT-433A; + - Azza 5IVG (if a more interesting machine with Prime3C is found). +*/ + + const machine_t machines[] = { /* 8088 Machines */ { "[8088] IBM PC (1981)", "ibmpc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 16, 64, 16, 0, machine_pc_init, NULL }, @@ -69,10 +114,10 @@ const machine_t machines[] = { { "[8088] AMI XT clone", "amixt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, { "[8088] Columbia Data Products MPC-1600", "mpc1600", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 512, 64, 0, machine_xt_mpc1600_init, NULL }, { "[8088] Compaq Portable", "portable", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_portable_init, NULL }, - { "[8088] DTK XT clone", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] DTK PIM-TB10-Z", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, { "[8088] Eagle PC Spirit", "pcspirit", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pcspirit_init, NULL }, { "[8088] Generic XT clone", "genxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_genxt_init, NULL }, - { "[8088] Juko XT clone", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] Juko ST", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, { "[8088] Multitech PC-700", "pc700", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pc700_init, NULL }, { "[8088] NCR PC4i", "pc4i", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_pc4i_init, NULL }, { "[8088] Olivetti M19", "m19", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 256, 640, 256, 0, machine_xt_m19_init, NULL }, @@ -87,6 +132,7 @@ const machine_t machines[] = { #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", "ltxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, #endif + /* Has a standard PS/2 KBC (so, use IBM PS/2 Type 1). */ { "[8088] Xi8088", "xi8088", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, { "[8088] Zenith Data Systems Z-151/152/161","zdsz151", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z151_init, NULL }, { "[8088] Zenith Data Systems Z-159", "zdsz159", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z159_init, NULL }, @@ -102,6 +148,7 @@ const machine_t machines[] = { { "[8086] Amstrad PPC512/640", "ppc512", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, { "[8086] Compaq Deskpro", "deskpro", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_deskpro_init, NULL }, { "[8086] Olivetti M21/24/24SP", "m24", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_xt_m24_init, m24_get_device }, + /* Has Olivetti KBC firmware. */ { "[8086] Olivetti M240", "m240", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_m240_init, NULL }, { "[8086] Schetmash Iskra-3104", "iskra3104", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_iskra3104_init, NULL }, { "[8086] Tandy 1000 SL/2", "tandy1000sl2", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, tandy1k_sl_get_device }, @@ -111,360 +158,693 @@ const machine_t machines[] = { { "[8086] VTech Laser XT3", "lxt3", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, #endif - /* 286 XT machines */ -#if defined(DEV_BRANCH) && defined(USE_HEDAKA) - { "[Citygate D30 XT] Hedaka HED-919", "hed919", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 1024, 64, 0, machine_xt_hed919_init, NULL }, -#endif - /* 286 AT machines */ + /* Has IBM AT KBC firmware. */ { "[ISA] IBM AT", "ibmat", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibm_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/1 model 2011", "ibmps1es", MACHINE_TYPE_286, CPU_PKG_286, 0, 10000000, 10000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 512, 16384, 512, 63, machine_ps1_m2011_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 1024, 16384,1024, 127, machine_ps2_m30_286_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[ISA] IBM XT Model 286", "ibmxt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 6000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 127, machine_at_ibmxt286_init, NULL }, + /* AMI BIOS for a chipset-less machine, most likely has AMI 'F' KBC firmware. */ { "[ISA] AMI IBM AT", "ibmatami", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatami_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to the + IBM AT KBC firmware unless evidence emerges of any proprietary commands. */ { "[ISA] Commodore PC 30 III", "cmdpc30", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_cmdpc_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable II", "portableii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_portableii_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III", "portableiii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 640, 16384, 128, 127, machine_at_portableiii_init, at_cpqiii_get_device }, + /* Has IBM AT KBC firmware. */ { "[ISA] MR 286 clone", "mr286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_mr286_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[ISA] NCR PC8/810/710/3390/3392", "pc8", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_pc8_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_OLIVETTI) + /* Has Olivetti KBC firmware. */ { "[ISA] Olivetti M290", "m290", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_m290_init, NULL }, #endif - #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + /* Has IBM AT KBC firmware. */ { "[ISA] OpenAT", "openat", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_openat_init, NULL }, #endif + /* Has IBM AT KBC firmware. */ { "[ISA] Phoenix IBM AT", "ibmatpx", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatpx_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[ISA] Quadtel IBM AT", "ibmatquadtel", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, + /* This has a Siemens proprietary KBC which is completely undocumented. */ { "[ISA] Siemens PCD-2L", "siemens", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_siemens_init, NULL }, + /* This has Toshiba's proprietary KBC, which is already implemented. */ { "[ISA] Toshiba T3100e", "t3100e", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO_FIXED, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[GC103] Quadtel 286 clone", "quadt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_quadt286_init, NULL }, + /* Most likely has AMI 'F' KBC firmware. */ { "[GC103] Trigem 286M", "tg286m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, - { "[NEAT] AMI 286 clone", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + /* This has "AMI KEYBOARD BIOS", most likely 'F'. */ + { "[NEAT] Dataexpert 286", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] NCR 3302", "3302", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 512, 16384, 128, 127, machine_at_3302_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] Phoenix 286 clone", "px286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_px286_init, NULL }, - { "[SCAT] Award 286 clone", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, + /* Has Chips & Technologies KBC firmware. */ { "[SCAT] GW-286CT GEAR", "gw286ct", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_gw286ct_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Goldstar GDC-212M", "gdc212m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2, 512, 4096, 512, 127, machine_at_gdc212m_init, NULL }, + /* Has a VIA VT82C42N KBC. */ + { "[SCAT] Hyundai Solomon 286KP", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[SCAT] Hyundai Super-286TR", "super286tr", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_super286tr_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4200P", "spc4200p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4216P", "spc4216p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 1024, 5120,1024, 127, machine_at_spc4216p_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4620P", "spc4620p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 5120,1024, 127, machine_at_spc4620p_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[SCAT] Samsung Deskmaster 286", "deskmaster286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_deskmaster286_init, NULL }, /* 286 machines that utilize the MCA bus */ + /* Has IBM PS/2 Type 2 KBC firmware. */ { "[MCA] IBM PS/2 model 50", "ibmps2_m50", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 10240,1024, 63, machine_ps2_model_50_init, NULL }, /* 386SX machines */ - { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO_FIXED, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, - { "[ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, - { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, + /* ISA slots available because an official IBM expansion for that existed. */ + /* Has IBM PS/2 Type 1 KBC firmware. */ + { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, + /* Has IBM AT KBC firmware. */ + { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, + /* Has Quadtel KBC firmware. */ + { "[ISA] QTC-SXM KT X20T02/HI", "quadt386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_quadt386sx_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_M6117) + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser AR-B1375", "arb1375", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_arb1375_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, #endif - { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ + { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ { "[HT18] AMA-932J", "ama932j", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, - { "[Intel 82335] ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, + /* Has an unknown KBC firmware with commands B8 and BB in the style of + Phoenix MultiKey and AMIKey-3(!), but also commands E1 and EA with + unknown functions. */ + { "[Intel 82335 ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[Intel 82335] Shuttle 386SX", "shuttle386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_shuttle386sx_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ { "[NEAT] Commodore SL386SX-16", "cmdsl386sx16", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 8192, 512, 127, machine_at_cmdsl386sx16_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] DTK 386SX clone", "dtk386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_init, NULL }, - { "[OPTi 283] Olivetti M300-08", "m30008", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 20000000, 20000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30008_init, at_m30008_get_device }, - { "[OPTi 283] Olivetti M300-15", "m30015", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 25000000, 25000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30015_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[OPTi 291] DTK PPM-3333P", "awardsx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_awardsx_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ { "[SCAMP] Commodore SL386SX-25", "cmdsl386sx25", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 8192, 512, 127, machine_at_cmdsl386sx25_init, at_cmdsl386sx25_get_device }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAMP] Samsung SPC-6033P", "spc6033p", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 12288, 2048, 127, machine_at_spc6033p_init, at_spc6033p_get_device }, + /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a + photo or real hardware BIOS string is found. */ { "[SCAT] KMX-C-02", "kmxc02", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 512, 127, machine_at_kmxc02_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[WD76C10] Amstrad MegaPC", "megapc", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_wd76c10_init, NULL }, /* 386SX machines which utilize the MCA bus */ + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 8192, 1024, 63, machine_ps2_model_55sx_init, NULL }, + /* 486SLC machines */ + /* 486SLC machines with just the ISA slot */ + /* Has AMIKey H KBC firmware. */ + { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486SLC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, + /* 386DX machines */ { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_acc386_init, NULL }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_ecs386_init, NULL }, { "[C&T 386] Samsung SPC-6000A", "spc6000a", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_spc6000a_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 1024, 14336, 1024, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, - { "[ISA] Micronics 386 clone", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, - { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, + /* Has IBM AT KBC firmware. */ + { "[ISA] Micronics 09-00021", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, + /* Has AMIKey F KBC firmware. */ + { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 32768, 1024, 127, machine_at_asus386_init, NULL }, /* 386DX machines which utilize the MCA bus */ + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 16384, 2048, 63, machine_ps2_model_70_type3_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 80", "ibmps2_m80", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 12288, 1024, 63, machine_ps2_model_80_init, NULL }, - { "[MCA] IBM PS/2 model 80 (type 3)", "ibmps2_m80_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 12288, 2048, 63, machine_ps2_model_80_axx_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { "[MCA] IBM PS/2 model 80 (type 3)", "ibmps2_m80_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 12288, 2048, 63, machine_ps2_model_80_axx_init, NULL }, /* 386DX/486 machines */ - { "[OPTi 495] Award 486 clone", "award486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, - { "[OPTi 495] Dataexpert SX495 (486)", "ami486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, - { "[OPTi 495] MR 486 clone", "mr486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, + /* The BIOS sends commands C9 without a parameter and D5, both of which are + Phoenix MultiKey commands. */ + { "[OPTi 495] Award 486 clone", "award495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, + /* Has AMIKey F KBC firmware. */ + { "[OPTi 495] Dataexpert SX495", "ami495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, + /* Has AMIKey F KBC firmware (it's just the MR BIOS for the above machine). */ + { "[OPTi 495] Dataexpert SX495 (MR BIOS)", "mr495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, /* 486 machines - Socket 1 */ + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. + It also has those Ex commands also seen on the VIA VT82C42N (the BIOS + supposedly sends command EF. + The board was also seen in 2003 with a -H string - perhaps someone swapped + the KBC? */ { "[ALi M1429] Olystar LIL1429", "ali1429", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_ali1429_init, NULL }, + /* Has JetKey 5 KBC Firmware - but the BIOS string ends in a hardcoded -F, and + the BIOS also explicitly expects command A1 to return a 'F', so it looks like + the JetKey 5 is a clone of AMIKey type F. */ { "[CS4031] AMI 486 CS4031", "cs4031", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_cs4031_init, NULL }, - { "[ETEQ ET6000] Olivetti PCS-46C", "pcs46c", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE | MACHINE_VIDEO, 4096, 32768, 4096, 127, machine_at_pcs46c_init, at_pcs46c_get_device }, + /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix + copyright. */ { "[OPTi 895] Mylex MVI486", "mvi486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_mvi486_init, NULL }, + /* Has AMI KF KBC firmware. */ + { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, + /* Has AMIKey H KBC firmware, per the screenshot in "How computers & MS-DOS work". */ + { "[SiS 401] Chaintech 433SC", "sis401", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, + /* Has AMIKey F KBC firmware, per a photo of a monitor with the BIOS screen on + eBay. */ + { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, + /* Has a MR (!) KBC firmware, which is a clone of the standard IBM PS/2 KBC firmware. */ + { "[SiS 471] SiS VL-BUS 471 REV. A1", "px471", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, + /* The chip is a Lance LT38C41, a clone of the Intel 8041, and the BIOS sends + commands BC, BD, and C9 which exist on both AMIKey and Phoenix MultiKey/42, + but it does not write a byte after C9, which is consistent with AMIKey, so + this must have some form of AMIKey. */ { "[VIA VT82C495] FIC 486-VC-HD", "486vchd", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 64512, 1024, 127, machine_at_486vchd_init, NULL }, + /* According to Deksor on the Win3x.org forum, the BIOS string ends in a -0, + indicating an unknown KBC firmware. But it does send the AMIKey get version + command, so it must expect an AMIKey. */ { "[VLSI 82C480] HP Vectra 486VL", "vect486vl", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_vect486vl_init, at_vect486vl_get_device }, - { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, + /* Has a standard IBM PS/2 KBC firmware or a clone thereof. */ + { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, + + /* 486 machines - Socket 2 */ + /* 486 machines with just the ISA slot */ + /* Uses some variant of Phoenix MultiKey/42 as the BIOS sends keyboard controller + command C7 (OR input byte with received data byte). */ + { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V4.01H). */ + { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, + /* There are two similar BIOS strings with -H, and one with -U, so I'm going to + give it an AMIKey H KBC firmware. */ + { "[ALi M1429G] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, + /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ + { "[SiS 461] Acer V10", "acerv10", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_acerv10_init, NULL }, + /* The BIOS does not send any non-standard keyboard controller commands and wants + a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */ + { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, + /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an + 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. + The photo of the board shows an AMIKey KBC which is indeed F. */ + { "[SiS 471] ABit AB-AH4", "win471", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, /* 486 machines - Socket 3 */ /* 486 machines with just the ISA slot */ - { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, - { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, - { "[ALi M1429] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[OPTi 895] Jetway J-403TG", "403tg", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_init, NULL }, - { "[SiS 401] AMI 486 Clone", "sis401", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, - { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, - { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, - { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, - { "[SiS 471] AMI 486 Clone", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, - { "[SiS 471] AMI WinBIOS 486 clone", "win471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { "[OPTi 895] Jetway J-403TG Rev D", "403tg_rev_d", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { "[OPTi 895] Jetway J-403TG Rev D (MR BIOS)","403tg_rev_d_mr", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_mr_init, NULL }, + /* Has AMIKey H keyboard BIOS. */ { "[SiS 471] AOpen Vi15G", "vi15g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_vi15g_init, NULL }, - { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, - { "[SiS 471] Phoenix SiS 471", "px471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, + /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ + { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, /* 486 machines which utilize the PCI bus */ + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. + The BIOS string always ends in -U, but the BIOS will send AMIKey commands 0xCA + and 0xCB if command 0xA1 returns a letter in the 0x5x or 0x7x ranges, so I'm + going to give it an AMI 'U' KBC. */ { "[ALi M1489] AMI WinBIOS 486 PCI", "win486pci", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_win486pci_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_486ap4_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { "[i420EX] Intel Classic/PCI ED", "ninja", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_ninja_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. Also has a + SST 29EE010 Flash chip. */ { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3g_init, NULL }, + /* I'm going to assume this as an AMIKey-2 like the other two 486SP3's. */ { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] Lucky Star LS-486E", "ls486e", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ls486e_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, so it has a standard PS/2 KBC. */ { "[SiS 496] Micronics M4Li", "m4li", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_m4li_init, NULL }, + /* Has a BestKey KBC which clones AMI type 'H'. */ { "[SiS 496] Rise Computer R418", "r418", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_r418_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[SiS 496] Soyo 4SA2", "4sa2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4sa2_init, NULL }, + /* According to MrKsoft, his real 4DPS has an AMIKey-2, which is an updated version + of type 'H'. */ { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, - { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, - { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, - { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, + /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ + { "[VIA VT82C496G] DFI G486VPA", "g486vpa", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_g486vpa_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[VIA VT82C496G] FIC VIP-IO2", "486vipio2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_486vipio2_init, NULL }, /* 486 machines - Miscellaneous */ - /* 486 machines with just the ISA slot */ - { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486_MISC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, - /* 486 machines which utilize the PCI bus */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Client] ITOX STAR", "itoxstar", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 75000000, 0, 0, 1.0, 1.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_itoxstar_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Consumer-II] Acrosser AR-B1479", "arb1479", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 163840, 8192, 255, machine_at_arb1479_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Elite] Advantech PCM-9340", "pcm9340", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 98304, 8192, 255, machine_at_pcm9340_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Atlas] AAEON PCM-5330", "pcm5330", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 131072,32768, 255, machine_at_pcm5330_init, NULL }, /* Socket 4 machines */ /* 430LX */ + /* Has AMIKey F KBC firmware (AMIKey). */ { "[i430LX] ASUS P/I-P5MP3", "p5mp3", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 196608, 2048, 127, machine_at_p5mp3_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell Dimension XPS P60", "dellxp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 131072, 2048, 127, machine_at_dellxp60_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell OptiPlex 560/L", "opti560l", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_opti560l_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Batman (*NOT* Batman's Revenge) with a fancier + POST screen */ { "[i430LX] AMBRA DP60 PCI", "ambradp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp60_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] IBM PS/ValuePoint P60", "valuepointp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_valuepointp60_init, NULL }, - { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_batman_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_revenge_init, NULL }, + /* Has AMI MegaKey KBC firmware. */ { "[i430LX] Micro Star 586MC1", "586mc1", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_586mc1_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430LX] Packard Bell PB520R", "pb520r", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 139264, 2048, 127, machine_at_pb520r_init, at_pb520r_get_device }, /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_VLB | MACHINE_IDE, 2048, 65536, 2048, 127, machine_at_excalibur_init, NULL }, + /* OPTi 596/597/822 */ + /* This has AMIKey 'F' KBC firmware. */ + { "[OPTi 597] Supermicro P5VL-PCI", "p5vl", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p5vl_init, NULL }, + /* SiS 85C50x */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, /* Socket 5 machines */ /* 430NX */ + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430NX] Intel Premiere/PCI II", "plato", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_plato_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Premiere/PCI II with a fancier POST screen. */ { "[i430NX] AMBRA DP90 PCI", "ambradp90", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp90_init, NULL }, + /* Has AMI MegaKey KBC firmware. */ { "[i430NX] Gigabyte GA-586IP", "430nx", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_430nx_init, NULL }, /* 430FX */ + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V5.0). */ { "[i430FX] Acer V30", "acerv30", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_acerv30_init, NULL }, + /* Has AMIKey F KBC firmware. */ { "[i430FX] AMI Apollo", "apollo", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_apollo_init, NULL }, + /* Has AMIKey H KBC firmware. */ + { "[i430FX] Dataexpert EXP8551", "exp8551", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_exp8551_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 511, machine_at_vectra54_init, at_vectra54_get_device }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ZP", "zappa", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_zappa_init, NULL }, + /* The BIOS sends KBC command B3 which indicates an AMI (or VIA VT82C42N) KBC. */ { "[i430FX] NEC PowerMate V", "powermatev", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_powermatev_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[i430FX] PC Partner MB500N", "mb500n", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb500n_init, NULL }, + /* Has AMIKey Z(!) KBC firmware. */ + { "[i430FX] Trigem Hawk", "hawk", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_hawk_init, NULL }, /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] TMC PAT54PV", "pat54pv", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_VLB, 2048, 65536, 2048, 127, machine_at_pat54pv_init, NULL }, /* OPTi 596/597/822 */ { "[OPTi 597] Shuttle HOT-543", "hot543", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_hot543_init, NULL }, - { "[OPTi 597] Supermicro P54VL-PCI", "p54vl", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p54vl_init, NULL }, /* SiS 85C50x */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P54SP4", "p54sp4", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54sp4_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] BCM SQ-588", "sq588", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_PENTIUMMMX), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_sq588_init, NULL }, - /* UMC 889x */ - { "[UMC 889x] Shuttle HOT-539", "hot539", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3600, 1.5, 2.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_hot539_init, NULL }, - /* Socket 7 (Single Voltage) machines */ /* 430FX */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54tp4xe_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE (MR BIOS)", "mr586", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mr586_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_gw2katx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_thor_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/EV", "endeavor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_endeavor_init, at_endeavor_get_device }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[i430FX] MSI MS-5119", "ms5119", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ms5119_init, NULL }, + /* This most likely uses AMI MegaKey KBC firmware as well due to having the same + Super I/O chip (that has the KBC firmware on it) as eg. the Advanced/EV. */ { "[i430FX] Packard Bell PB640", "pb640", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[i430FX] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_chariot_init, NULL }, + /* Has an AMI 'H' KBC firmware (1992). */ + { "[i430FX] QDI FMB", "fmb", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_fmb_init, NULL }, /* 430HX */ + /* I can't determine what KBC firmware this has, but given that the Acer V35N and + V60 have Phoenix MultiKey KBC firmware on the chip, I'm going to assume so + does the M3A. */ { "[i430HX] Acer M3A", "acerm3a", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerm3a_init, NULL }, + /* Has AMIKey F KBC firmware. */ { "[i430HX] AOpen AP53", "ap53", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3450, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap53_init, NULL }, + /* [TEST] Has a VIA 82C42N KBC, with AMIKey F KBC firmware. */ { "[i430HX] Biostar MB-8500TUC", "8500tuc", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_8500tuc_init, NULL }, + /* [TEST] Unable to determine what KBC this has. A list on a Danish site shows + the BIOS as having a -0 string, indicating non-AMI KBC firmware. */ { "[i430HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_p55t2s_init, NULL }, /* 430VX */ + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Gateway 2000 Tigereye", "gw2kte", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_gw2kte_init, NULL }, /* SiS 5511 */ - { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, /* Socket 7 (Dual Voltage) machines */ /* 430HX */ + /* Has SST flash and the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Acer V35N", "acerv35n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_Cx6x86MX), 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerv35n_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_p55t2p4_init, NULL }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Micronics M7S-Hi", "m7shi", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 511, machine_at_m7shi_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Intel TC430HX", "tc430hx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_tc430hx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Toshiba Equium 5200D", "equium5200", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_equium5200_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . + Yes, this is an Intel AMI BIOS with a fancy splash screen. */ { "[i430HX] Sony Vaio PCV-240", "pcv240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_pcv240_init, NULL }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p65up5_cp55t2d_init, NULL }, /* 430VX */ + /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55tvp4_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, so it must have a standard IBM + PS/2 KBC firmware or a clone thereof. */ { "[i430VX] Azza 5IVG", "5ivg", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_5ivg_init, NULL }, + /* [TEST] Has AMIKey 'F' KBC firmware. */ { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_8500tvxa_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430VX] Compaq Presario 2240", "presario2240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario2240_init, NULL }, + /* This most likely has AMI MegaKey as above. */ { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario4500_init, NULL }, + /* The BIOS sends KBC command CB which is an AMI KBC command, so it has an AMI KBC firmware. */ { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55va_init, NULL }, + /* The BIOS does not send a single non-standard KBC command. */ { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL }, + /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it + likely clones the behavior of AMIKey 'H'. */ { "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, /* 430TX */ + /* The BIOS sends KBC command B8, CA, and CB, so it has an AMI KBC firmware. */ { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL }, + /* This has the AMIKey KBC firmware, which is an updated 'F' type (YM430TX is based on the TX97). */ { "[i430TX] ASUS TX97", "tx97", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_tx97_init, NULL }, #if defined(DEV_BRANCH) && defined(NO_SIO) + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430TX] Intel AN430TX", "an430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_an430tx_init, NULL }, #endif + /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ { "[i430TX] Intel YM430TX", "ym430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ym430tx_init, NULL }, + /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. */ { "[i430TX] PC Partner MB540N", "mb540n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2700, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_mb540n_init, NULL }, + /* [TEST] Has AMIKey 'H' KBC firmware. */ { "[i430TX] SuperMicro Super P5MMS98", "p5mms98", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_p5mms98_init, NULL }, /* Apollo VPX */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA VPX] FIC VA-502", "ficva502", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ficva502_init, NULL }, /* Apollo VP3 */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA VP3] FIC PA-2012", "ficpa2012", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 55000000, 75000000, 2100, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_ficpa2012_init, NULL }, /* SiS 5571 */ + /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] Rise R534F", "r534f", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 127, machine_at_r534f_init, NULL }, + /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] MSI MS-5146", "ms5146", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_ms5146_init, NULL }, - /* SiS 5598 */ - { "[SiS 5598] ASUS SP97-XV", "sp97xv", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3200, 1.5, 2.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_sp97xv_init, NULL }, - { "[SiS 5598] PC Chips M571", "m571", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3500, 1.5, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m571_init, NULL }, - /* ALi ALADDiN IV */ -#if defined(DEV_BRANCH) && defined(USE_M154X) + /* Has the ALi M1543 southbridge with on-chip KBC. */ { "[ALi ALADDiN IV] PC Chips M560", "m560", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m560_init, NULL }, + /* Has the ALi M1543 southbridge with on-chip KBC. */ { "[ALi ALADDiN IV] MSI MS-5164", "ms5164", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ms5164_init, NULL }, -#endif /* Super Socket 7 machines */ /* Apollo MVP3 */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] AOpen AX59 Pro", "ax59pro", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1300, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_ax59pro_init, NULL }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] FIC VA-503+", "ficva503p", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_mvp3_init, NULL }, + /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] FIC VA-503A", "ficva503a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1800, 3100, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ficva503a_init, NULL }, /* Socket 8 machines */ /* 450KX */ #if defined(DEV_BRANCH) && defined(USE_I450KX) + /* This has an AMIKey, which is an updated version of type 'F'. */ { "[i450KX] ASUS P/I-P6RP4", "p6rp4", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p6rp4_init, NULL }, #endif /* 440FX */ + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Acer V60N", "v60n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2500, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_v60n_init, NULL }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-P6ND)", "p65up5_cp6nd", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cp6nd_init, NULL }, + /* The MB-8600TTX has an AMIKey 'F' KBC firmware, so I'm going to assume so does + the MB-8600TTC until someone can actually identify it. */ { "[i440FX] Biostar MB-8600TTC", "8600ttc", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 50000000, 66666667, 2900, 3300, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_8500ttc_init, NULL }, { "[i440FX] Gigabyte GA-686NX", "686nx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_686nx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel AP440FX", "ap440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ap440fx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel VS440FX", "vs440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_vs440fx_init, NULL }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Micronics M6Mi", "m6mi", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2900, 3300, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_m6mi_init, NULL }, + /* I found a BIOS string of it that ends in -S, but it could be a typo for -5 + (there's quite a few AMI BIOS strings around with typo'd KBC codes), so I'm + going to give it an AMI MegaKey. */ { "[i440FX] PC Partner MB600N", "mb600n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_mb600n_init, NULL }, /* Slot 1 machines */ /* 440FX */ + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-PKND)", "p65up5_cpknd", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cpknd_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i440FX] ASUS KN97", "kn97", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 83333333, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_kn97_init, NULL }, /* 440LX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440LX] ABIT LX6", "lx6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 100000000, 1500, 3500, 2.0, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_lx6_init, NULL }, + /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix + MultiKey KBC firmware. */ { "[i440LX] Micronics Spitfire", "spitfire", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_spitfire_init, NULL }, /* 440EX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440EX] QDI EXCELLENT II", "p6i440e2", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 83333333, 1800, 3500, 3.0, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_p6i440e2_init, NULL }, /* 440BX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS P2B-LS", "p2bls", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 112121212, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p2bls_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS P3B-F", "p3bf", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p3bf_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ABIT BF6", "bf6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_bf6_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AOpen AX6BC", "ax6bc", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ax6bc_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Gigabyte GA-686BX", "686bx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_686bx_init, NULL }, + /* Has a SM(S)C FDC37M60x Super I/O chip with on-chip KBC with most likely + AMIKey-2 KBC firmware. */ { "[i440BX] HP Vectra VEi 8", "vei8", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vei8_init, NULL }, + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ { "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_SOUND, 8192,1048576, 8192, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] SuperMicro Super P6SBA", "p6sba", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_p6sba_init, NULL }, -#if defined(DEV_BRANCH) && defined(NO_SIO) - { "[i440BX] Fujitsu ErgoPro x365", "ergox365", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 511, machine_at_ergox365_init, NULL }, -#endif /* 440ZX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] MSI MS-6168", "ms6168", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_ms6168_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] Packard Bell Bora Pro", "borapro", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_borapro_init, NULL }, /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC6310BXII","atc6310bxii", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_atc6310bxii_init, NULL }, /* VIA Apollo Pro */ + /* Has the VIA VT82C596B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro] FIC KA-6130", "ficka6130", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_ficka6130_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133] ASUS P3V133", "p3v133", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p3v133_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133A] ASUS P3V4X", "p3v4x", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,2097152, 8192, 255, machine_at_p3v4x_init, NULL }, /* Slot 1/2 machines */ /* 440GX */ + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ { "[i440GX] Freeway FW-6400GX", "fw6400gx", MACHINE_TYPE_SLOT1_2, CPU_PKG_SLOT1 | CPU_PKG_SLOT2, 0, 100000000, 150000000, 1800, 3500, 3.0, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2080768,16384, 511, machine_at_fw6400gx_init, NULL }, /* Slot 2 machines */ /* 440GX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440GX] Gigabyte GA-6GXU", "6gxu", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_6gxu_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440GX] SuperMicro Super S2DGE", "s2dge", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_s2dge_init, NULL }, /* PGA370 machines */ /* 440LX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440LX] SuperMicro Super 370SLM", "s370slm", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_s370slm_init, NULL }, /* 440BX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AEWIN AW-O671R", "awo671r", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_awo671r_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS CUBX", "cubx", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_cubx_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AmazePC AM-BX133", "ambx133", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ambx133_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Tyan Trinity 371", "trinity371", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_trinity371_init, NULL }, /* 440ZX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] Soltek SL-63A1", "63a", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_63a_init, NULL }, /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC7020BXII","atc7020bxii", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_atc7020bxii_init, NULL }, /* VIA Apollo Pro */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro] PC Partner APAS3", "apas3", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_apas3_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133] ECS P6BAP", "p6bap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p6bap_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133A] AEWIN WCF-681", "wcf681", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_wcf681_init, NULL }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro133A] ASUS CUV4X-LS", "cuv4xls", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,1572864, 8192, 255, machine_at_cuv4xls_init, NULL }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, - { "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL }, /* Miscellaneous/Fake/Hypervisor machines */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL }, { NULL, NULL, MACHINE_TYPE_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } diff --git a/src/mem/mem.c b/src/mem/mem.c index cac528a59..79e27f011 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -1794,7 +1794,7 @@ mem_read_ram(uint32_t addr, void *priv) mem_log("Read B %02X from %08X\n", ram[addr], addr); #endif - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return ram[addr]; @@ -1809,7 +1809,7 @@ mem_read_ramw(uint32_t addr, void *priv) mem_log("Read W %04X from %08X\n", *(uint16_t *)&ram[addr], addr); #endif - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; @@ -1824,7 +1824,7 @@ mem_read_raml(uint32_t addr, void *priv) mem_log("Read L %08X from %08X\n", *(uint32_t *)&ram[addr], addr); #endif - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; @@ -2068,7 +2068,7 @@ mem_write_ram(uint32_t addr, uint8_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write B %02X to %08X\n", val, addr); #endif - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_ramb_page(addr, val, &pages[addr >> 12]); } else @@ -2083,7 +2083,7 @@ mem_write_ramw(uint32_t addr, uint16_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write W %04X to %08X\n", val, addr); #endif - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_ramw_page(addr, val, &pages[addr >> 12]); } else @@ -2098,7 +2098,7 @@ mem_write_raml(uint32_t addr, uint32_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write L %08X to %08X\n", val, addr); #endif - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_raml_page(addr, val, &pages[addr >> 12]); } else @@ -2110,7 +2110,7 @@ static uint8_t mem_read_remapped(uint32_t addr, void *priv) { addr = 0xA0000 + (addr - remap_start_addr); - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return ram[addr]; } @@ -2120,7 +2120,7 @@ static uint16_t mem_read_remappedw(uint32_t addr, void *priv) { addr = 0xA0000 + (addr - remap_start_addr); - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; } @@ -2130,7 +2130,7 @@ static uint32_t mem_read_remappedl(uint32_t addr, void *priv) { addr = 0xA0000 + (addr - remap_start_addr); - if (AT) + if (is286 || AT) addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; } @@ -2141,7 +2141,7 @@ mem_write_remapped(uint32_t addr, uint8_t val, void *priv) { uint32_t oldaddr = addr; addr = 0xA0000 + (addr - remap_start_addr); - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); } else @@ -2154,7 +2154,7 @@ mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) { uint32_t oldaddr = addr; addr = 0xA0000 + (addr - remap_start_addr); - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); } else @@ -2167,7 +2167,7 @@ mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) { uint32_t oldaddr = addr; addr = 0xA0000 + (addr - remap_start_addr); - if (AT) { + if (is286 || AT) { addwritelookup(mem_logical_addr, addr); mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); } else @@ -2536,7 +2536,7 @@ mem_a20_init(void) flushmmucache(); mem_a20_state = mem_a20_key | mem_a20_alt; } else { - rammask = 0xfffff; + rammask = is286 ? 0xffffff : 0xfffff; flushmmucache(); mem_a20_key = mem_a20_alt = mem_a20_state = 0; } @@ -2662,15 +2662,20 @@ mem_reset(void) */ if (AT) { if (cpu_16bitbus) { - /* 80186/286; maximum address space is 16MB. */ + /* 80286/386SX; maximum address space is 16MB. */ m = 4096; } else { - /* 80386+; maximum address space is 4GB. */ + /* 80386DX+; maximum address space is 4GB. */ m = 1048576; } } else { - /* 8088/86; maximum address space is 1MB. */ - m = 256; + if (is286) { + /* 80286; maximum address space is 16MB. */ + m = 4096; + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } } /* @@ -2864,7 +2869,7 @@ mem_a20_recalc(void) int state; if (! AT) { - rammask = 0xfffff; + rammask = is286 ? 0xffffff : 0xfffff; flushmmucache(); mem_a20_key = mem_a20_alt = mem_a20_state = 0; diff --git a/src/mem/rom.c b/src/mem/rom.c index efb173d0b..2f81957bf 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -392,10 +392,12 @@ static void bios_add(void) { int temp_cpu_type, temp_cpu_16bitbus = 1; + int temp_is286 = 0; - if (AT && cpu_s) { + if (/*AT && */cpu_s) { temp_cpu_type = cpu_s->cpu_type; temp_cpu_16bitbus = (temp_cpu_type == CPU_286 || temp_cpu_type == CPU_386SX || temp_cpu_type == CPU_486SLC || temp_cpu_type == CPU_IBM386SLC || temp_cpu_type == CPU_IBM486SLC ); + temp_is286 = (temp_cpu_type == CPU_286); } if (biosmask > 0x1ffff) { @@ -417,7 +419,7 @@ bios_add(void) MEM_READ_ROMCS | MEM_WRITE_ROMCS); } - if (AT) { + if (temp_is286 || AT) { mem_mapping_add(&bios_high_mapping, biosaddr | (temp_cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, bios_read,bios_readw,bios_readl, NULL,NULL,NULL, diff --git a/src/mem/spd.c b/src/mem/spd.c index 32b49a101..821f88e71 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -384,6 +384,62 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit } +void +spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) +{ + uint8_t row, dimm, drb, apollo = 0; + uint16_t size, rows[SPD_MAX_SLOTS]; + + /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ + if (reg_max < reg_min) { + apollo = reg_max; + reg_max = reg_min + 7; + } + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 2; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2i((machines[machine].max_ram >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (row = 0; row <= (reg_max - reg_min); row += 2) { + dimm = (row >> 2); + size = 0; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = ((row >> 1) & 1) ? 0 : drb_unit; + else + size = ((row >> 1) & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + /* Determine the DRB register to write. */ + drb = reg_min + row; + if (apollo && ((drb & 0xf) < 0xa)) + drb = apollo + (drb & 0xf); + + /* Write DRB register, adding the previous DRB's value. */ + if (row == 0) + regs[drb] = 0; + else if ((apollo) && (drb == apollo)) + regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */ + else + regs[drb] = regs[drb - 1]; + if (size) + regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row >> 1, size, regs[drb]); + } +} + + static const device_t spd_device = { "Serial Presence Detect ROMs", DEVICE_ISA, diff --git a/src/pci.c b/src/pci.c index 5f1c48f50..387366a39 100644 --- a/src/pci.c +++ b/src/pci.c @@ -59,7 +59,7 @@ static uint8_t pci_pmc = 0, last_pci_card = 0, last_normal_pci_card = 0, last_p static uint8_t pci_card_to_slot_mapping[256][32], pci_bus_number_to_index_mapping[256]; static uint8_t pci_irqs[16], pci_irq_level[16]; static uint64_t pci_irq_hold[16]; -static pci_mirq_t pci_mirqs[4]; +static pci_mirq_t pci_mirqs[8]; static int pci_type, pci_switch, pci_index, @@ -74,6 +74,7 @@ static int trc_reg = 0; static void pci_reset_regs(void); +// #define ENABLE_PCI_LOG 1 #ifdef ENABLE_PCI_LOG int pci_do_log = ENABLE_PCI_LOG; diff --git a/src/pic.c b/src/pic.c index ad165ee5c..36bd4b0e2 100644 --- a/src/pic.c +++ b/src/pic.c @@ -54,6 +54,8 @@ static pc_timer_t pic_timer; static int shadow = 0, elcr_enabled = 0, tmr_inited = 0, latched = 0; +static uint16_t smi_irq_mask = 0x0000, + smi_irq_status = 0x0000; static void (*update_pending)(void); @@ -79,6 +81,39 @@ pic_log(const char *fmt, ...) #endif +void +pic_reset_smi_irq_mask(void) +{ + smi_irq_mask = 0x0000; +} + + +void +pic_set_smi_irq_mask(int irq, int set) +{ + if ((irq >= 0) && (irq <= 15)) { + if (set) + smi_irq_mask |= (1 << irq); + else + smi_irq_mask &= ~(1 << irq); + } +} + +uint16_t +pic_get_smi_irq_status(void) +{ + return smi_irq_status; +} + + +void +pic_clear_smi_irq_status(int irq) +{ + if ((irq >= 0) && (irq <= 15)) + smi_irq_status &= ~(1 << irq); +} + + void pic_elcr_write(uint16_t port, uint8_t val, void *priv) { @@ -255,6 +290,8 @@ pic_reset() update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt; pic.at = pic2.at = is_at; + + smi_irq_mask = smi_irq_status = 0x0000; } @@ -541,6 +578,11 @@ picint_common(uint16_t num, int level, int set) acpi_rtc_status = !!set; if (set) { + if (smi_irq_mask & num) { + smi_line = 1; + smi_irq_status |= num; + } + if (num & 0xff00) { if (level) pic2.lines |= (num >> 8); @@ -555,6 +597,8 @@ picint_common(uint16_t num, int level, int set) pic.irr |= num; } } else { + smi_irq_status &= ~num; + if (num & 0xff00) { pic2.lines &= ~(num >> 8); pic2.irr &= ~(num >> 8); diff --git a/src/pit.c b/src/pit.c index 9db4c45dd..fc1e91927 100644 --- a/src/pit.c +++ b/src/pit.c @@ -64,6 +64,7 @@ int64_t firsttime = 1; #define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ #define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ #define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */ +#define PIT_OLIVETTI 256 /* The PIT is that of the Olivetti 486 (has slight timing differences). */ enum { @@ -92,67 +93,214 @@ pit_log(const char *fmt, ...) #endif +#define NEW_PIT_CODE 1 + + +#ifdef NEW_PIT_CODE +typedef void (*tf_t)(ctr_t *ctr); + + +static void ctr_tick_mode_0(ctr_t *ctr); +static void ctr_tick_mode_1(ctr_t *ctr); +static void ctr_tick_mode_2_and_6(ctr_t *ctr); +static void ctr_tick_mode_3_and_7(ctr_t *ctr); +static void ctr_tick_mode_4_and_5(ctr_t *ctr); + + +static tf_t ctr_tick_funcs[8] = { ctr_tick_mode_0, ctr_tick_mode_1, ctr_tick_mode_2_and_6, + ctr_tick_mode_3_and_7, ctr_tick_mode_4_and_5, ctr_tick_mode_4_and_5, + ctr_tick_mode_2_and_6, ctr_tick_mode_3_and_7 }; + + +/* MODE 0: Interrupt on Terminal Count. */ static void -ctr_set_out(ctr_t *ctr, int out) +ctr_tick_mode_0(ctr_t *ctr) { - if (ctr == NULL) - return; + uint8_t state = ctr->state; - if (ctr->out_func != NULL) - ctr->out_func(out, ctr->out); - ctr->out = out; -} - - -static void -ctr_decrease_count(ctr_t *ctr) -{ - if (ctr->bcd) { - ctr->units--; - if (ctr->units == 0xff) { - ctr->units = 9; - ctr->tens--; - if (ctr->tens == 0xff) { - ctr->tens = 9; - ctr->hundreds--; - if (ctr->hundreds == 0xff) { - ctr->hundreds = 9; - ctr->thousands--; - if (ctr->thousands == 0xff) { - ctr->thousands = 9; - ctr->myriads--; - if (ctr->myriads == 0xff) - ctr->myriads = 0; /* 0 - 1 should wrap around to 9999. */ - } + switch (state) { + case 1: + /* Load count. */ + ctr->count = ctr->l; + ctr->null_count = 0; + /* Switch to next state. */ + ctr->state++; + case 2: case 3: + if (ctr->gate) { + /* Decrease counter. */ + if ((state == 3) || ctr->gate) + ctr->count--; + if ((state == 2) && ctr->gate && (ctr->count == 0)) { + /* Terminal count reached, switch to next state. */ + ctr->state++; + /* Set output high. */ + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; } } - } - } else - ctr->count = (ctr->count - 1) & 0xffff; + break; + } +} + + +/* MODE 1: Programmale One-Shoft. */ +static void +ctr_tick_mode_1(ctr_t *ctr) +{ + uint8_t state = ctr->state; + + switch (state) { + case 1: + /* Load count. */ + ctr->count = ctr->l; + ctr->null_count = 0; + /* Switch to next state. */ + ctr->state++; + /* Set output low. */ + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + break; + case 2: case 3: + /* Decrease counter. */ + ctr->count--; + if ((state == 2) && (ctr->count == 0)) { + /* Terminal count reached, switch to next state. */ + ctr->state++; + /* Set output high. */ + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; + } + break; + } } static void -ctr_load_count(ctr_t *ctr) +ctr_tick_mode_2_and_6(ctr_t *ctr) { - int l = ctr->l ? ctr->l : 0x10000; + uint8_t state = ctr->state; - ctr->count = l; - pit_log("ctr->count = %i\n", l); - ctr->null_count = 0; - ctr->newcount = !!(l & 1); + switch (state) { + case 1: case 3: + /* Load count. */ + ctr->count = ctr->l; + ctr->null_count = 0; + if (ctr->state == 3) { + /* Set output high. */ + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; + } + /* Switch to next state. */ + ctr->state = 2; + break; + case 2: + /* Decrease counter. */ + if (ctr->gate) { + ctr->count--; + if (ctr->count == 1) { + /* Terminal count reached, switch to previous state. */ + ctr->state = 3; + /* Set output low. */ + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + } + } + break; + } } +static void +ctr_tick_mode_3_and_7(ctr_t *ctr) +{ + uint8_t state = ctr->state; + uint16_t old_count = ctr->count; + + switch (state) { + case 1: + /* Load count. */ + ctr->count = ctr->l; + ctr->flag_64k = !ctr->count; + ctr->null_count = 0; + ctr->newcount = ctr->count & 1; + /* Switch to next state. */ + ctr->state = 2; + case 2: case 3: + if (ctr->gate) { + ctr->count -= (ctr->newcount ? ((ctr->state == 3) ? 3 : 1) : 2); + if (!ctr->flag_64k && (ctr->count > old_count)) { + /* Load count. */ + ctr->count = ctr->l; + ctr->flag_64k = !ctr->count; + ctr->null_count = 0; + ctr->newcount = ctr->count & 1; + /* Switch to next state. */ + ctr->state ^= 1; + /* Set output low. */ + if (ctr->out_func != NULL) + ctr->out_func(state & 1, ctr->out); + ctr->out = state & 1; + } else { + if (ctr->newcount) + ctr->newcount = 0; + ctr->flag_64k = 0; + } + } + break; + } +} + + +static void +ctr_tick_mode_4_and_5(ctr_t *ctr) +{ + uint8_t state = ctr->state; + + /* Software triggered strobe */ + /* Hardware triggered strobe */ + if (ctr->gate || (ctr->m != 4)) { + switch(state) { + case 0: case 2: + ctr->count--; + if ((state == 2) && (ctr->count < 1)) { + ctr->state++; + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + } + break; + case 3: + ctr->state = 0; + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; + break; + } + } +} +#else static void ctr_tick(ctr_t *ctr) { uint8_t state = ctr->state; + uint16_t old_count = ctr->count; if (state == 1) { /* This is true for all modes */ - ctr_load_count(ctr); - ctr->state = 2; + ctr->count = ctr->l; + ctr->null_count = 0; + ctr->newcount = !!(ctr->count & 1); + ctr->state++; + if ((ctr->m & 0x07) == 1) { + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + } return; } @@ -161,38 +309,35 @@ ctr_tick(ctr_t *ctr) /* Interrupt on terminal count */ switch (state) { case 2: - if (ctr->gate && (ctr->count >= 1)) { - ctr_decrease_count(ctr); + if (ctr->gate) { + ctr->count--; if (ctr->count < 1) { - ctr->state = 3; - ctr_set_out(ctr, 1); + ctr->state++; + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; } } break; case 3: - ctr_decrease_count(ctr); + ctr->count--; break; } break; case 1: /* Hardware retriggerable one-shot */ switch (state) { - case 1: - ctr_load_count(ctr); - ctr->state = 2; - ctr_set_out(ctr, 0); - break; case 2: - if (ctr->count >= 1) { - ctr_decrease_count(ctr); - if (ctr->count < 1) { - ctr->state = 3; - ctr_set_out(ctr, 1); - } + ctr->count--; + if (ctr->count < 1) { + ctr->state++; + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; } break; case 3: - ctr_decrease_count(ctr); + ctr->count--; break; } break; @@ -200,59 +345,40 @@ ctr_tick(ctr_t *ctr) /* Rate generator */ switch (state) { case 3: - ctr_load_count(ctr); - ctr->state = 2; - ctr_set_out(ctr, 1); + ctr->count = ctr->l; + ctr->null_count = 0; + ctr->state ^= 1; + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; break; case 2: - if (ctr->gate == 0) - break; - else if (ctr->count >= 2) { - ctr_decrease_count(ctr); + // if (ctr->gate) { + ctr->count--; if (ctr->count < 2) { - ctr->state = 3; - ctr_set_out(ctr, 0); + ctr->state ^= 1; + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; } - } + // } break; } break; case 3: case 7: /* Square wave mode */ switch (state) { - case 2: - if (ctr->gate == 0) - break; - else if (ctr->count >= 0) { - if (ctr->bcd) { - ctr_decrease_count(ctr); - if (!ctr->newcount) - ctr_decrease_count(ctr); - } else - ctr->count -= (ctr->newcount ? 1 : 2); - if (ctr->count < 0) { - ctr_load_count(ctr); - ctr->state = 3; - ctr_set_out(ctr, 0); - } else if (ctr->newcount) - ctr->newcount = 0; - } - break; - case 3: - if (ctr->gate == 0) - break; - else if (ctr->count >= 0) { - if (ctr->bcd) { - ctr_decrease_count(ctr); - ctr_decrease_count(ctr); - if (ctr->newcount) - ctr_decrease_count(ctr); - } else - ctr->count -= (ctr->newcount ? 3 : 2); - if (ctr->count < 0) { - ctr_load_count(ctr); - ctr->state = 2; - ctr_set_out(ctr, 1); + case 2: case 3: + if (ctr->gate != 0) { + ctr->count -= (ctr->newcount ? ((state & 1) ? 3 : 1) : 2); + if (ctr->count > old_count) { + ctr->count = ctr->l; + ctr->null_count = 0; + ctr->newcount = !!(ctr->count & 1); + ctr->state ^= 1; + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; } else if (ctr->newcount) ctr->newcount = 0; } @@ -264,21 +390,20 @@ ctr_tick(ctr_t *ctr) /* Hardware triggered strobe */ if ((ctr->gate != 0) || (ctr->m != 4)) { switch(state) { - case 0: - ctr_decrease_count(ctr); - break; - case 2: - if (ctr->count >= 1) { - ctr_decrease_count(ctr); - if (ctr->count < 1) { - ctr->state = 3; - ctr_set_out(ctr, 0); - } + case 0: case 2: + ctr->count--; + if ((state == 2) && (ctr->count < 1)) { + ctr->state++; + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; } break; case 3: ctr->state = 0; - ctr_set_out(ctr, 1); + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; break; } } @@ -287,19 +412,24 @@ ctr_tick(ctr_t *ctr) break; } } +#endif static void ctr_clock(ctr_t *ctr) { - /* FIXME: Is this even needed? */ + /* FIXME: Is this even needed? */ if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3)) return; if (ctr->using_timer) return; +#ifdef NEW_PIT_CODE + ctr->tick_func(ctr); +#else ctr_tick(ctr); +#endif } @@ -350,6 +480,11 @@ ctr_latch_count(ctr_t *ctr) { int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count; + // if ((ctr->pit->flags & PIT_OLIVETTI) && (ctr->state == 0)) + // count--; + + pit_log("PIT latch count with state %i (%i)\n", ctr->state, ctr->latch); + switch (ctr->rm & 0x03) { case 0x00: /* This should never happen. */ @@ -415,15 +550,21 @@ pit_ctr_set_gate(ctr_t *ctr, int gate) if (!old && gate) { /* Here we handle the rising edges. */ if (mode & 1) { - if (mode != 1) - ctr_set_out(ctr, 1); + if (mode != 1) { + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; + } ctr->state = 1; } else if (mode == 2) ctr->state = 3; } else if (old && !gate) { /* Here we handle the lowering edges. */ - if (mode & 2) - ctr_set_out(ctr, 1); + if (mode & 2) { + if (ctr->out_func != NULL) + ctr->out_func(1, ctr->out); + ctr->out = 1; + } } break; } @@ -437,12 +578,27 @@ pit_ctr_set_clock_common(ctr_t *ctr, int clock) ctr->clock = clock; - if (ctr->using_timer && ctr->latch) { + if (!ctr->using_timer) + return; + +#if 0 + if ((ctr->pit->flags & PIT_OLIVETTI) && !old && ctr->clock) { + if (ctr->do_load) { + if (ctr->do_load == 3) + ctr_load(ctr); + ctr->do_load++; + if (ctr->do_load == 4) + ctr->do_load = 0; + } + } +#endif + + if (ctr->latch) { if (old && !ctr->clock) { ctr_set_state_1(ctr); ctr->latch = 0; } - } else if (ctr->using_timer && !ctr->latch) { + } else if (!ctr->latch) { if (ctr->state == 1) { if (!old && ctr->clock) ctr->s1_det = 1; /* Rising edge. */ @@ -450,11 +606,19 @@ pit_ctr_set_clock_common(ctr_t *ctr, int clock) ctr->s1_det++; /* Falling edge. */ if (ctr->s1_det >= 2) { ctr->s1_det = 0; +#ifdef NEW_PIT_CODE + ctr->tick_func(ctr); +#else ctr_tick(ctr); +#endif } } } else if (old && !ctr->clock) +#ifdef NEW_PIT_CODE + ctr->tick_func(ctr); +#else ctr_tick(ctr); +#endif } } @@ -538,9 +702,14 @@ pit_write(uint16_t addr, uint8_t val, void *priv) ctr->m = (val >> 1) & 7; if (ctr->m > 5) ctr->m &= 3; +#ifdef NEW_PIT_CODE + ctr->tick_func = ctr_tick_funcs[ctr->m]; +#endif ctr->null_count = 1; ctr->bcd = (ctr->ctrl & 0x01); - ctr_set_out(ctr, !!ctr->m); + if (ctr->out_func != NULL) + ctr->out_func(!!ctr->m, ctr->out); + ctr->out = !!ctr->m; ctr->state = 0; if (ctr->latched) { pit_log("PIT %i: Reload while counter is latched\n", t); @@ -563,27 +732,44 @@ pit_write(uint16_t addr, uint8_t val, void *priv) break; case 1: ctr->l = val; - if (ctr->m == 0) - ctr_set_out(ctr, 0); - ctr_load(ctr); + if (ctr->m == 0) { + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + } + if (dev->flags & PIT_OLIVETTI) + ctr->do_load = 1; + else + ctr_load(ctr); break; case 2: ctr->l = (val << 8); - if (ctr->m == 0) - ctr_set_out(ctr, 0); - ctr_load(ctr); + if (ctr->m == 0) { + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; + } + if (dev->flags & PIT_OLIVETTI) + ctr->do_load = 1; + else + ctr_load(ctr); break; case 3: case 0x83: if (ctr->wm & 0x80) { ctr->l = (ctr->l & 0x00ff) | (val << 8); pit_log("PIT %i: Written high byte %02X, latch now %04X\n", t, val, ctr->l); - ctr_load(ctr); + if (dev->flags & PIT_OLIVETTI) + ctr->do_load = 1; + else + ctr_load(ctr); } else { ctr->l = (ctr->l & 0xff00) | val; pit_log("PIT %i: Written low byte %02X, latch now %04X\n", t, val, ctr->l); if (ctr->m == 0) { ctr->state = 0; - ctr_set_out(ctr, 0); + if (ctr->out_func != NULL) + ctr->out_func(0, ctr->out); + ctr->out = 0; } } @@ -757,7 +943,7 @@ pit_nmi_timer_ps2(int new_out, int old_out) static void -ctr_reset(ctr_t *ctr) +ctr_reset(pit_t *dev, ctr_t *ctr) { ctr->ctrl = 0; ctr->m = 0; @@ -771,6 +957,8 @@ ctr_reset(ctr_t *ctr) ctr->s1_det = 0; ctr->l_det = 0; + + ctr->pit = dev; } @@ -784,10 +972,15 @@ pit_reset(pit_t *dev) dev->clock = 0; for (i = 0; i < 3; i++) - ctr_reset(&dev->counters[i]); + ctr_reset(dev, &dev->counters[i]); /* Disable speaker gate. */ dev->counters[2].gate = 0; + +#ifdef NEW_PIT_CODE + dev->counters[0].tick_func = dev->counters[1].tick_func = + dev->counters[2].tick_func = ctr_tick_funcs[0]; +#endif } @@ -858,6 +1051,17 @@ const device_t i8254_device = }; +const device_t i8254_olivetti_device = +{ + "Intel 8254 Programmable Interval Timer (Olivetti)", + DEVICE_ISA, + PIT_8254 | PIT_OLIVETTI, + pit_init, pit_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + const device_t i8254_sec_device = { "Intel 8254 Programmable Interval Timer (Secondary)", @@ -904,6 +1108,9 @@ pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(i case PIT_8254: pit = device_add(&i8254_device); break; + case (PIT_8254 | PIT_OLIVETTI): + pit = device_add(&i8254_olivetti_device); + break; } for (i = 0; i < 3; i++) { diff --git a/src/port_6x.c b/src/port_6x.c new file mode 100644 index 000000000..98cd4350d --- /dev/null +++ b/src/port_6x.c @@ -0,0 +1,214 @@ +/* + * 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 Ports 61, 62, and 63 used by various + * machines. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/m_xt_xi8088.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/pit.h> +#include <86box/ppi.h> +#include <86box/video.h> +#include <86box/port_6x.h> + + +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + +#define PORT_6X_TURBO 1 +#define PORT_6X_EXT_REF 2 +#define PORT_6X_MIRROR 4 +#define PORT_6X_SWA 8 + + +static void +port_6x_write(uint16_t port, uint8_t val, void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + port &= 3; + + if ((port == 3) && (dev->flags & PORT_6X_MIRROR)) + port = 1; + + switch (port) { + case 1: + ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 1); + + if (dev->flags & PORT_6X_TURBO) + xi8088_turbo_set(!!(val & 0x04)); + break; + } +} + + +static uint8_t +port_6x_read(uint16_t port, void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + uint8_t ret = 0xff; + + port &= 3; + + if ((port == 3) && (dev->flags & PORT_6X_MIRROR)) + port = 1; + + switch (port) { + case 1: + if (dev->flags & PORT_6X_EXT_REF) { + ret = ppi.pb & 0x0f; + + if (dev->refresh) + ret |= 0x10; + } else + ret = ppi.pb & 0x1f; + + if (ppispeakon) + ret |= 0x20; + + if (dev->flags & PORT_6X_TURBO) + ret = (ret & 0xfb) | (xi8088_turbo_get() ? 0x04 : 0x00); + break; + case 2: + if (dev->flags & PORT_6X_SWA) { + /* SWA on Olivetti M240 mainboard (off=1) */ + ret = 0x00; + if (ppi.pb & 0x8) { + /* Switches 4, 5 - floppy drives (number) */ + int i, fdd_count = 0; + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 2); + /* Switches 6, 7 - monitor type */ + if (video_is_mda()) + ret |= 0x3; + else if (video_is_cga()) + ret |= 0x2; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + } else { + /* bit 2 always on */ + ret |= 0x4; + /* Switch 8 - 8087 FPU. */ + if (hasfpu) + ret |= 0x02; + } + } + break; + } + + return(ret); +} + + +static void +port_6x_refresh(void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_timer, PS2_REFRESH_TIME); +} + + +static void +port_6x_close(void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + timer_disable(&dev->refresh_timer); + + free(dev); +} + + +void * +port_6x_init(const device_t *info) +{ + port_6x_t *dev = (port_6x_t *) malloc(sizeof(port_6x_t)); + memset(dev, 0, sizeof(port_6x_t)); + + dev->flags = info->local & 0xff; + + io_sethandler(0x0061, 3, port_6x_read, NULL, NULL, port_6x_write, NULL, NULL, dev); + + if (dev->flags & PORT_6X_EXT_REF) + timer_add(&dev->refresh_timer, port_6x_refresh, dev, 1); + + return dev; +} + + +const device_t port_6x_device = { + "Port 6x Registers", + 0, + 0, + port_6x_init, port_6x_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + +const device_t port_6x_xi8088_device = { + "Port 6x Registers (Xi8088)", + 0, + PORT_6X_TURBO | PORT_6X_EXT_REF | PORT_6X_MIRROR, + port_6x_init, port_6x_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + +const device_t port_6x_ps2_device = { + "Port 6x Registers (IBM PS/2)", + 0, + PORT_6X_EXT_REF, + port_6x_init, port_6x_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + +const device_t port_6x_olivetti_device = { + "Port 6x Registers (Olivetti)", + 0, + PORT_6X_SWA, + port_6x_init, port_6x_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/CMakeLists.txt b/src/sio/CMakeLists.txt index 9eff04f30..902f8b231 100644 --- a/src/sio/CMakeLists.txt +++ b/src/sio/CMakeLists.txt @@ -14,7 +14,7 @@ # add_library(sio OBJECT sio_acc3221.c sio_f82c710.c sio_82091aa.c sio_fdc37c651.c sio_fdc37c661.c - sio_fdc37c66x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c + sio_fdc37c66x.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c sio_it8661f.c sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c sio_prime3b.c sio_prime3c.c diff --git a/src/sio/sio_fdc37c67x.c b/src/sio/sio_fdc37c67x.c new file mode 100644 index 000000000..d6905a72d --- /dev/null +++ b/src/sio/sio_fdc37c67x.c @@ -0,0 +1,613 @@ +/* + * 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 FDC37C67X Super I/O Chip. + * + * + * + * Author: Miran Grca, + * Copyright 2016-2018 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/pic.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 "cpu.h" +#include <86box/sio.h> + + +#define AB_RST 0x80 + + +typedef struct { + uint8_t chip_id, is_apm, + tries, + gpio_regs[2], auxio_reg, + regs[48], + ld_regs[11][256]; + uint16_t gpio_base, /* Set to EA */ + auxio_base, sio_base; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c67x_t; + + +static void fdc37c67x_write(uint16_t port, uint8_t val, void *priv); +static uint8_t fdc37c67x_read(uint16_t port, void *priv); + + +static uint16_t +make_port(fdc37c67x_t *dev, uint8_t ld) +{ + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static uint8_t +fdc37c67x_auxio_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + return dev->auxio_reg; +} + + +static void +fdc37c67x_auxio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + dev->auxio_reg = val; +} + + +static uint8_t +fdc37c67x_gpio_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t ret = 0xff; + + ret = dev->gpio_regs[port & 1]; + + return ret; +} + + +static void +fdc37c67x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + if (!(port & 1)) + dev->gpio_regs[0] = (dev->gpio_regs[0] & 0xfc) | (val & 0x03); +} + + +static void +fdc37c67x_fdc_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +fdc37c67x_lpt_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3) & 0xFFFC; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } + lpt1_irq(lpt_irq); +} + + +static void +fdc37c67x_serial_handler(fdc37c67x_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = 4 + uart; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } +} + + +static void +fdc37c67x_auxio_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[8][0x30]; + + io_removehandler(dev->auxio_base, 0x0001, + fdc37c67x_auxio_read, NULL, NULL, fdc37c67x_auxio_write, NULL, NULL, dev); + if (local_enable) { + dev->auxio_base = ld_port = make_port(dev, 8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(dev->auxio_base, 0x0001, + fdc37c67x_auxio_read, NULL, NULL, fdc37c67x_auxio_write, NULL, NULL, dev); + } +} + + +static void +fdc37c67x_sio_handler(fdc37c67x_t *dev) +{ +#if 0 + if (dev->sio_base) { + io_removehandler(dev->sio_base, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + } + dev->sio_base = (((uint16_t) dev->regs[0x27]) << 8) | dev->regs[0x26]; + if (dev->sio_base) { + io_sethandler(dev->sio_base, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + } +#endif +} + + +static void +fdc37c67x_gpio_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable; + + local_enable = !!(dev->regs[0x03] & 0x80); + + io_removehandler(dev->gpio_base, 0x0002, + fdc37c67x_gpio_read, NULL, NULL, fdc37c67x_gpio_write, NULL, NULL, dev); + if (local_enable) { + switch (dev->regs[0x03] & 0x03) { + case 0: + ld_port = 0xe0; + break; + case 1: + ld_port = 0xe2; + break; + case 2: + ld_port = 0xe4; + break; + case 3: + ld_port = 0xea; /* Default */ + break; + } + dev->gpio_base = ld_port; + if (ld_port > 0x0000) + io_sethandler(dev->gpio_base, 0x0002, + fdc37c67x_gpio_read, NULL, NULL, fdc37c67x_gpio_write, NULL, NULL, dev); + } +} + + +static void +fdc37c67x_smi_handler(fdc37c67x_t *dev) +{ + /* TODO: 8042 P1.2 SMI#. */ + pic_reset_smi_irq_mask(); + pic_set_smi_irq_mask(dev->ld_regs[3][0x70], dev->ld_regs[8][0xb4] & 0x02); + pic_set_smi_irq_mask(dev->ld_regs[5][0x70], dev->ld_regs[8][0xb4] & 0x04); + pic_set_smi_irq_mask(dev->ld_regs[4][0x70], dev->ld_regs[8][0xb4] & 0x08); + pic_set_smi_irq_mask(dev->ld_regs[0][0x70], dev->ld_regs[8][0xb4] & 0x10); + pic_set_smi_irq_mask(12, dev->ld_regs[8][0xb5] & 0x01); + pic_set_smi_irq_mask(1, dev->ld_regs[8][0xb5] & 0x02); + pic_set_smi_irq_mask(10, dev->ld_regs[8][0xb5] & 0x80); +} + + +static void +fdc37c67x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0x00, keep = 0x00; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xaa) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; + } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; + } + } + return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 0x0a) + return; + else switch (dev->regs[7]) { + case 0x01: + case 0x02: + case 0x07: + return; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val | keep; + } + } else + return; + } + + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x03: + if (valxor & 0x83) + fdc37c67x_gpio_handler(dev); + dev->regs[0x03] &= 0x83; + break; + case 0x22: + if (valxor & 0x01) + fdc37c67x_fdc_handler(dev); + if (valxor & 0x08) + fdc37c67x_lpt_handler(dev); + if (valxor & 0x10) + fdc37c67x_serial_handler(dev, 0); + if (valxor & 0x20) + fdc37c67x_serial_handler(dev, 1); + break; + case 0x26: case 0x27: + fdc37c67x_sio_handler(dev); + } + + return; + } + + switch(dev->regs[7]) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x01; + if (valxor) + fdc37c67x_fdc_handler(dev); + break; + case 0xF0: + if (valxor & 0x01) + fdc_update_enh_mode(dev->fdc, val & 0x01); + if (valxor & 0x10) + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) + fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); + if (valxor & 0x0C) + fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (val & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x08; + if (valxor) + fdc37c67x_lpt_handler(dev); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x10; + if (valxor) + fdc37c67x_serial_handler(dev, 0); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 5: + /* Serial port 2 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x20; + if (valxor) + fdc37c67x_serial_handler(dev, 1); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c67x_auxio_handler(dev); + break; + case 0xb4: + case 0xb5: + fdc37c67x_smi_handler(dev); + break; + } + break; + } +} + + +static uint8_t +fdc37c67x_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + uint16_t smi_stat = pic_get_smi_irq_status(); + int f_irq = dev->ld_regs[0][0x70]; + int p_irq = dev->ld_regs[3][0x70]; + int s1_irq = dev->ld_regs[4][0x70]; + int s2_irq = dev->ld_regs[5][0x70]; + + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + + /* TODO: 8042 P1.2 SMI#. */ + if ((dev->regs[7] == 8) && (dev->cur_reg == 0xb6)) { + ret = dev->regs[dev->cur_reg] & 0xe1; + ret |= ((!!(smi_stat & (1 << p_irq))) << 1); + ret |= ((!!(smi_stat & (1 << s2_irq))) << 2); + ret |= ((!!(smi_stat & (1 << s1_irq))) << 3); + ret |= ((!!(smi_stat & (1 << f_irq))) << 4); + } else if ((dev->regs[7] == 8) && (dev->cur_reg == 0xb7)) { + ret = dev->regs[dev->cur_reg] & 0xec; + ret |= ((!!(smi_stat & (1 << 12))) << 0); + ret |= ((!!(smi_stat & (1 << 1))) << 1); + ret |= ((!!(smi_stat & (1 << 10))) << 4); + } + } + } + } + + return ret; +} + + +static void +fdc37c67x_reset(fdc37c67x_t *dev) +{ + int i = 0; + + memset(dev->regs, 0, 48); + + dev->regs[0x03] = 0x03; + dev->regs[0x20] = dev->chip_id; + dev->regs[0x22] = 0x39; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = 0xf0; + dev->regs[0x27] = 0x03; + + for (i = 0; i < 11; i++) + memset(dev->ld_regs[i], 0, 256); + + /* Logical device 0: FDD */ + dev->ld_regs[0][0x30] = 1; + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xf0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xf0] = 0x0e; + dev->ld_regs[0][0xf2] = 0xff; + + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x30] = 1; + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 7; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xf0] = 0x3c; + + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x30] = 1; + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xf0] = 3; + serial_setup(dev->uart[0], 0x3f8, dev->ld_regs[4][0x70]); + + /* Logical device 5: Serial Port 2 */ + dev->ld_regs[5][0x30] = 1; + dev->ld_regs[5][0x60] = 2; + dev->ld_regs[5][0x61] = 0xf8; + dev->ld_regs[5][0x70] = 3; + dev->ld_regs[5][0x74] = 4; + dev->ld_regs[5][0xf1] = 2; + dev->ld_regs[5][0xf2] = 3; + serial_setup(dev->uart[1], 0x2f8, dev->ld_regs[5][0x70]); + + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; + dev->ld_regs[7][0x61] = 0x60; + dev->ld_regs[7][0x70] = 1; + dev->ld_regs[7][0x72] = 12; + + /* Logical device 8: Auxiliary I/O */ + dev->ld_regs[8][0xc0] = 6; + dev->ld_regs[8][0xc1] = 3; + + fdc37c67x_gpio_handler(dev); + fdc37c67x_lpt_handler(dev); + fdc37c67x_serial_handler(dev, 0); + fdc37c67x_serial_handler(dev, 1); + fdc37c67x_auxio_handler(dev); + fdc37c67x_sio_handler(dev); + + fdc_reset(dev->fdc); + fdc37c67x_fdc_handler(dev); + + dev->locked = 0; +} + + +static void +fdc37c67x_close(void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + free(dev); +} + + +static void * +fdc37c67x_init(const device_t *info) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) malloc(sizeof(fdc37c67x_t)); + memset(dev, 0, sizeof(fdc37c67x_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); + + dev->chip_id = info->local & 0xff; + + dev->gpio_regs[0] = 0xff; + // dev->gpio_regs[1] = (info->local == 0x0030) ? 0xff : 0xfd; + dev->gpio_regs[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; + + fdc37c67x_reset(dev); + + io_sethandler(0x370, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + io_sethandler(0x3f0, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + + return dev; +} + + +const device_t fdc37c67x_device = { + "SMC FDC37C67X Super I/O", + 0, + 0x40, + fdc37c67x_init, fdc37c67x_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c index 267de0543..c5eb40e60 100644 --- a/src/sio/sio_pc87332.c +++ b/src/sio/sio_pc87332.c @@ -366,6 +366,16 @@ const device_t pc87332_398_ide_device = { }; +const device_t pc87332_398_ide_sec_device = { + "National Semiconductor PC87332 Super I/O (Port 398h) (With Secondary IDE)", + 0, + 0x201, + pc87332_init, pc87332_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + + const device_t pc87332_398_ide_fdcon_device = { "National Semiconductor PC87332 Super I/O (Port 398h) (With IDE and FDC on)", 0, diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 8e1ea61a4..d045bc082 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1026,8 +1026,9 @@ sb_ct1745_mixer_read(uint16_t addr, void *p) /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ /* 0x02000 DSP v4.04, 0x4000 DSP v4.05, 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ + /* If QEMU is any indication, then the values are actually 0x20, 0x40, and 0x80. */ temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | - ((sb->dsp.sb_irq401) ? 4 : 0) | 0x4000; + ((sb->dsp.sb_irq401) ? 4 : 0) | 0x40; ret = temp; break; diff --git a/src/usb.c b/src/usb.c index 9692068b2..dce1a31af 100644 --- a/src/usb.c +++ b/src/usb.c @@ -146,6 +146,9 @@ ohci_mmio_read(uint32_t addr, void *p) ret = dev->ohci_mmio[addr]; + if (addr == 0x101) + ret = (ret & 0xfe) | (!!mem_a20_key); + return ret; } diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 03436ba32..7bf5933a1 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -20,8 +20,8 @@ add_library(vid OBJECT video.c vid_table.c vid_cga.c vid_cga_comp.c vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c - vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c - vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c + vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c + vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_nga.c) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 155253610..62a484891 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -1597,7 +1597,7 @@ gd54xx_recalctimings(svga_t *svga) uint8_t clocksel, rdmask; uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; - svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + svga->rowoffset = (svga->crtc[0x13]) | (((int) (uint32_t) (svga->crtc[0x1b] & 0x10)) << 4); svga->interlace = (svga->crtc[0x1a] & 0x01); @@ -1774,6 +1774,28 @@ gd54xx_recalctimings(svga_t *svga) } svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; + + pclog("svga->crtc[0x1a] = %02X\n", svga->crtc[0x1a]); + pclog("svga->crtc[0x1b] = %02X\n", svga->crtc[0x1b]); + pclog("svga->crtc[0x1c] = %02X\n", svga->crtc[0x1c]); + + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) + svga->htotal += ((svga->crtc[0x1c] >> 3) & 0x07); + + if (svga->crtc[0x1b] & ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5424) ? 0xa0 : 0x20)) { + /* Special blanking mode: the blank start and end become components of the window generator, + and the actual blanking comes from the display enable signal. */ + /* Start blanking at the first character clock after the last active one. */ + svga->hblankstart = svga->crtc[1] + 1; + svga->hblank_end_val = (svga->htotal + 6) & 0x3f; + /* In this mode, the dots per clock are always 8 or 16, never 9 or 18. */ + if (!svga->scrblank && svga->attr_palette_enable) + svga->dots_per_clock = (svga->seqregs[1] & 8) ? 16 : 8; + /* No overscan in this mode. */ + svga->hblank_overscan = 0; + /* Also make sure vertical blanking starts on display end. */ + svga->vblankstart = svga->dispend; + } } diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c new file mode 100644 index 000000000..70a383bfa --- /dev/null +++ b/src/video/vid_et3000.c @@ -0,0 +1,308 @@ +/* + * 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 Tseng Labs ET3000. + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/mca.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> + + +#define BIOS_ROM_PATH "roms/video/et3000/Tseng ET3000AX ISA VGA-VGA ULTRA.bin" + +typedef struct { + const char *name; + int type; + + svga_t svga; + + rom_t bios_rom; + + uint8_t banking; +} et3000_t; + + +static video_timings_t timing_et3000_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; + +static uint8_t et3000_in(uint16_t addr, void *priv); +static void et3000_out(uint16_t addr, uint8_t val, void *priv); + + +static uint8_t +et3000_in(uint16_t addr, void *priv) +{ + et3000_t *dev = (et3000_t *)priv; + svga_t *svga = &dev->svga; + + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3cd: /*Banking*/ + return dev->banking; + + case 0x3d4: + return svga->crtcreg; + + case 0x3d5: + return svga->crtc[svga->crtcreg]; + } + + return svga_in(addr, svga); +} + +static void +et3000_out(uint16_t addr, uint8_t val, void *priv) +{ + et3000_t *dev = (et3000_t *)priv; + svga_t *svga = &dev->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (svga->attrff && (svga->attraddr == 0x16)) { + svga->attrregs[0x16] = val; + svga->chain4 &= ~0x10; + if (svga->gdcreg[5] & 0x40) + svga->chain4 |= (svga->attrregs[0x16] & 0x10); + svga_recalctimings(svga); + } + break; + + case 0x3c5: + if (svga->seqaddr == 4) { + svga->seqregs[4] = val; + + svga->chain2_write = !(val & 4); + svga->chain4 = (svga->chain4 & ~8) | (val & 8); + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); + return; + } + break; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 5) { + svga->chain4 &= ~0x10; + if (val & 0x40) + svga->chain4 |= (svga->attrregs[0x16] & 0x10); + } + break; + + case 0x3cd: /*Banking*/ + dev->banking = val; + if (!(svga->crtc[0x23] & 0x80) && !(svga->gdcreg[6] & 0x08)) { + switch ((val >> 6) & 3) { + case 0: /*128K segments*/ + svga->write_bank = (val & 7) << 17; + svga->read_bank = ((val >> 3) & 7) << 17; + break; + case 1: /*64K segments*/ + svga->write_bank = (val & 7) << 16; + svga->read_bank = ((val >> 3) & 7) << 16; + break; + } + } + return; + + case 0x3d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + + svga_out(addr, val, svga); +} + + +static void +et3000_recalctimings(svga_t *svga) +{ + svga->ma_latch |= (svga->crtc[0x23] & 2) << 15; + if (svga->crtc[0x25] & 1) svga->vblankstart |= 0x400; + if (svga->crtc[0x25] & 2) svga->vtotal |= 0x400; + if (svga->crtc[0x25] & 4) svga->dispend |= 0x400; + if (svga->crtc[0x25] & 8) svga->vsyncstart |= 0x400; + if (svga->crtc[0x25] & 0x10) svga->split |= 0x400; + + svga->interlace = !!(svga->crtc[0x25] & 0x80); + + if (svga->attrregs[0x16] & 0x10) { + svga->ma_latch <<= (1 << 0); + svga->rowoffset <<= (1 << 0); + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + svga->render = svga_render_4bpp_highres; + svga->hdisp *= 2; + break; + case 0x20: + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: + svga->render = svga_render_8bpp_highres; + break; + } + } + + /* pclog("HDISP = %i, HTOTAL = %i, ROWOFFSET = %i, INTERLACE = %i\n", + svga->hdisp, svga->htotal, svga->rowoffset, svga->interlace); */ + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x24] << 1) & 4)) { + case 0: + case 1: + break; + case 3: + svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; + break; + case 5: + svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; + break; + default: + svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; + break; + } +} + + +static void * +et3000_init(const device_t *info) +{ + const char *fn; + et3000_t *dev; + + dev = (et3000_t *)malloc(sizeof(et3000_t)); + memset(dev, 0x00, sizeof(et3000_t)); + dev->name = info->name; + dev->type = info->local; + fn = BIOS_ROM_PATH; + + switch(dev->type) { + case 0: /* ISA ET3000AX */ + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et3000_isa); + svga_init(info, &dev->svga, dev, device_get_config_int("memory") << 10, + et3000_recalctimings, et3000_in, et3000_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et3000_in,NULL,NULL, et3000_out,NULL,NULL, dev); + break; + } + + rom_init(&dev->bios_rom, (char *) fn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + dev->svga.bpp = 8; + dev->svga.miscout = 1; + + return(dev); +} + + +static void +et3000_close(void *priv) +{ + et3000_t *dev = (et3000_t *)priv; + + svga_close(&dev->svga); + + free(dev); +} + + +static void +et3000_speed_changed(void *priv) +{ + et3000_t *dev = (et3000_t *)priv; + + svga_recalctimings(&dev->svga); +} + + +static void +et3000_force_redraw(void *priv) +{ + et3000_t *dev = (et3000_t *)priv; + + dev->svga.fullchange = changeframecount; +} + + +static int +et3000_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +static const device_config_t et3000_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, "", { 0 }, + { + { + "256 KB", 256 + }, + { + "512 KB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t et3000_isa_device = { + "Tseng Labs ET3000AX (ISA)", + DEVICE_ISA, + 0, + et3000_init, et3000_close, NULL, + { et3000_available }, + et3000_speed_changed, + et3000_force_redraw, + et3000_config +}; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index d22a6e6af..3bce65159 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -55,6 +55,7 @@ #define BIOS_ROM_PATH "roms/video/et4000/et4000.bin" +#define TC6058AF_BIOS_ROM_PATH "roms/video/et4000/Tseng_Labs_VGA-4000_BIOS_V1.1.bin" #define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" #define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" #define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" @@ -109,13 +110,14 @@ et4000_in(uint16_t addr, void *priv) { et4000_t *dev = (et4000_t *)priv; svga_t *svga = &dev->svga; + uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3c2: - if (dev->type == 1) { + if (dev->type == 2) { if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) return 0; else @@ -132,7 +134,9 @@ et4000_in(uint16_t addr, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - return sc1502x_ramdac_in(addr, svga->ramdac, svga); + if (dev->type >= 1) + return sc1502x_ramdac_in(addr, svga->ramdac, svga); + break; case 0x3cd: /*Banking*/ return dev->banking; @@ -142,6 +146,26 @@ et4000_in(uint16_t addr, void *priv) case 0x3d5: return svga->crtc[svga->crtcreg]; + + case 0x3da: + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + + ret = svga->cgastat; + + if ((svga->fcr & 0x08) && svga->dispon) + ret |= 0x08; + + if (ret & 0x08) + ret &= 0x7f; + else + ret |= 0x80; + + return ret; } return svga_in(addr, svga); @@ -223,12 +247,34 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { + case 0x3c5: + if (svga->seqaddr == 4) { + svga->seqregs[4] = val; + + svga->chain2_write = !(val & 4); + svga->chain4 = (svga->chain4 & ~8) | (val & 8); + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); + return; + } else if (svga->seqaddr == 0x0e) { + svga->seqregs[0x0e] = val; + svga->chain4 &= ~0x02; + if (svga->gdcreg[5] & 0x40) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + svga_recalctimings(svga); + return; + } + break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: - sc1502x_ramdac_out(addr, val, svga->ramdac, svga); - return; + if (dev->type >= 1) { + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; + } + break; case 0x3cd: /*Banking*/ if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { @@ -239,7 +285,11 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) return; case 0x3cf: - if ((svga->gdcaddr & 15) == 6) { + if ((svga->gdcaddr & 15) == 5) { + svga->chain4 &= ~0x02; + if (val & 0x40) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + } else if ((svga->gdcaddr & 15) == 6) { if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { svga->write_bank = (dev->banking & 0x0f) * 0x10000; svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; @@ -542,13 +592,13 @@ et4000_recalctimings(svga_t *svga) et4000_t *dev = (et4000_t *)svga->p; svga->ma_latch |= (svga->crtc[0x33] & 3) << 16; - if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; - if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; - if (svga->crtc[0x35] & 4) svga->dispend += 0x400; - if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; - if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x35] & 1) svga->vblankstart |= 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal |= 0x400; + if (svga->crtc[0x35] & 4) svga->dispend |= 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart |= 0x400; + if (svga->crtc[0x35] & 0x10) svga->split |= 0x400; if (!svga->rowoffset) svga->rowoffset = 0x100; - if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->crtc[0x3f] & 1) svga->htotal |= 0x100; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) { @@ -577,7 +627,7 @@ et4000_recalctimings(svga_t *svga) break; } - if (dev->type == 2 || dev->type == 3 || dev->type == 4) { + if (dev->type == 3 || dev->type == 4 || dev->type == 5) { if ((svga->render == svga_render_text_80) && ((svga->crtc[0x37] & 0x0A) == 0x0A)) { if (dev->port_32cb_val & 0x80) { svga->ma_latch -= 2; @@ -588,6 +638,19 @@ et4000_recalctimings(svga_t *svga) } } } + + if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { + svga->ma_latch <<= (1 << 0); + svga->rowoffset <<= (1 << 0); + svga->render = svga_render_8bpp_highres; + } + + if (dev->type == 0) { + if (svga->render == svga_render_8bpp_lowres) + svga->render = svga_render_8bpp_tseng_lowres; + else if (svga->render == svga_render_8bpp_highres) + svga->render = svga_render_8bpp_tseng_highres; + } } static void @@ -601,6 +664,7 @@ et4000_kasan_recalctimings(svga_t *svga) svga->ma_latch -= 3; svga->ca_adj = (et4000->kasan_cfg_regs[0] >> 6) - 3; svga->ksc5601_sbyte_mask = (et4000->kasan_cfg_regs[0] & 4) << 5; + /* TODO: Are we sure this doesn't use Attribute register 16h bit 6 (two-byte character code enable)? */ if((et4000->kasan_cfg_regs[0] & 0x23) == 0x20 && (et4000->kasan_cfg_regs[4] & 0x80) && ((svga->crtc[0x37] & 0x0B) == 0x0A)) svga->render = svga_render_text_80_ksc5601; } @@ -649,7 +713,8 @@ et4000_init(const device_t *info) fn = BIOS_ROM_PATH; switch(dev->type) { - case 0: /* ISA ET4000AX */ + case 0: /* ISA ET4000AX (TC6058AF) */ + case 1: /* ISA ET4000AX */ dev->vram_size = device_get_config_int("memory") << 10; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); svga_init(info, &dev->svga, dev, dev->vram_size, @@ -657,9 +722,11 @@ et4000_init(const device_t *info) NULL, NULL); io_sethandler(0x03c0, 32, et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); + if (dev->type == 0) + fn = TC6058AF_BIOS_ROM_PATH; break; - case 1: /* MCA ET4000AX */ + case 2: /* MCA ET4000AX */ dev->vram_size = 1024 << 10; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_mca); svga_init(info, &dev->svga, dev, dev->vram_size, @@ -672,8 +739,8 @@ et4000_init(const device_t *info) mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, NULL, dev); break; - case 2: /* Korean ET4000 */ - case 3: /* Trigem 286M ET4000 */ + case 3: /* Korean ET4000 */ + case 4: /* Trigem 286M ET4000 */ dev->vram_size = device_get_config_int("memory") << 10; dev->port_22cb_val = 0x60; dev->port_32cb_val = 0; @@ -697,7 +764,7 @@ et4000_init(const device_t *info) loadfont(KOREAN_FONT_ROM_PATH, 6); fn = KOREAN_BIOS_ROM_PATH; break; - case 4: /* Kasan ET4000 */ + case 5: /* Kasan ET4000 */ dev->vram_size = device_get_config_int("memory") << 10; dev->svga.ksc5601_sbyte_mask = 0; dev->svga.ksc5601_udc_area_msb[0] = 0xC9; @@ -733,7 +800,8 @@ et4000_init(const device_t *info) } - dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + if (dev->type >= 1) + dev->svga.ramdac = device_add(&sc1502x_ramdac_device); dev->vram_mask = dev->vram_size - 1; @@ -777,6 +845,13 @@ et4000_force_redraw(void *priv) } +static int +et4000_tc6058af_available(void) +{ + return rom_present(TC6058AF_BIOS_ROM_PATH); +} + + static int et4000_available(void) { @@ -798,6 +873,27 @@ et4000_kasan_available(void) rom_present(KASAN_FONT_ROM_PATH); } +static const device_config_t et4000_tc6058af_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, "", { 0 }, + { + { + "256 KB", 256 + }, + { + "512 KB", 512 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + static const device_config_t et4000_config[] = { { @@ -822,10 +918,21 @@ static const device_config_t et4000_config[] = } }; +const device_t et4000_tc6058af_isa_device = { + "Tseng Labs ET4000AX (TC6058AF) (ISA)", + DEVICE_ISA, + 0, + et4000_init, et4000_close, NULL, + { et4000_tc6058af_available }, + et4000_speed_changed, + et4000_force_redraw, + et4000_tc6058af_config +}; + const device_t et4000_isa_device = { "Tseng Labs ET4000AX (ISA)", DEVICE_ISA, - 0, + 1, et4000_init, et4000_close, NULL, { et4000_available }, et4000_speed_changed, @@ -836,7 +943,7 @@ const device_t et4000_isa_device = { const device_t et4000_mca_device = { "Tseng Labs ET4000AX (MCA)", DEVICE_MCA, - 1, + 2, et4000_init, et4000_close, NULL, { et4000_available }, et4000_speed_changed, @@ -847,7 +954,7 @@ const device_t et4000_mca_device = { const device_t et4000k_isa_device = { "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", DEVICE_ISA, - 2, + 3, et4000_init, et4000_close, NULL, { et4000k_available }, et4000_speed_changed, @@ -858,7 +965,7 @@ const device_t et4000k_isa_device = { const device_t et4000k_tg286_isa_device = { "Trigem Korean VGA (Trigem 286M)", DEVICE_ISA, - 3, + 4, et4000_init, et4000_close, NULL, { et4000k_available }, et4000_speed_changed, @@ -869,7 +976,7 @@ const device_t et4000k_tg286_isa_device = { const device_t et4000_kasan_isa_device = { "Kasan Hangulmadang-16 VGA (Tseng Labs ET4000AX Korean)", DEVICE_ISA, - 4, + 5, et4000_init, et4000_close, NULL, { et4000_kasan_available }, et4000_speed_changed, diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 1652615af..e2cbab980 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -363,6 +363,7 @@ et4000w32p_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); +#if 0 if (svga->adv_flags & FLAG_NOSKEW) { /* On the Cardex ET4000/W32p-based cards, adjust text mode clocks by 1. */ if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ @@ -379,10 +380,10 @@ et4000w32p_recalctimings(svga_t *svga) svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; else svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; - } else if ((svga->gdcreg[5] & 0x40) == 0) - svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; + } } } +#endif if (et4000->type == ET4000W32) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { @@ -421,8 +422,10 @@ et4000w32p_recalctimings(svga_t *svga) else svga->render = svga_render_text_80; } else { +#if 0 if (svga->adv_flags & FLAG_NOSKEW) svga->ma_latch--; +#endif switch (svga->gdcreg[5] & 0x60) { case 0x00: diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index cd7d4e26e..771ed1f05 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -30,9 +30,7 @@ #include <86box/vid_svga.h> #define BIOS_037C_PATH "roms/video/oti/bios.bin" -#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/oti067.bin" -#define BIOS_067_M300_08_PATH "roms/machines/olivetti_m300_08/EVC_BIOS.ROM" -#define BIOS_067_M300_15_PATH "roms/machines/olivetti_m300_15/EVC_BIOS.ROM" +#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/oti067.bin" #define BIOS_077_PATH "roms/video/oti/oti077.vbi" @@ -40,7 +38,6 @@ enum { OTI_037C, OTI_067 = 2, OTI_067_AMA932J, - OTI_067_M300 = 4, OTI_077 = 5 }; @@ -370,16 +367,6 @@ oti_init(const device_t *info) io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); break; - case OTI_067_M300: - if (rom_present(BIOS_067_M300_15_PATH)) - romfn = BIOS_067_M300_15_PATH; - else - romfn = BIOS_067_M300_08_PATH; - oti->vram_size = device_get_config_int("memory"); - oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */ - io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); - break; - case OTI_067: case OTI_077: romfn = BIOS_077_PATH; @@ -446,27 +433,20 @@ oti037c_available(void) return(rom_present(BIOS_037C_PATH)); } + static int oti067_ama932j_available(void) { return(rom_present(BIOS_067_AMA932J_PATH)); } + static int oti067_077_available(void) { return(rom_present(BIOS_077_PATH)); } -static int -oti067_m300_available(void) -{ - if (rom_present(BIOS_067_M300_15_PATH)) - return(rom_present(BIOS_067_M300_15_PATH)); - else - return(rom_present(BIOS_067_M300_08_PATH)); -} - static const device_config_t oti067_config[] = { @@ -559,18 +539,6 @@ const device_t oti067_device = oti067_config }; -const device_t oti067_m300_device = -{ - "Oak OTI-067 (Olivetti M300-08/15)", - DEVICE_ISA, - 4, - oti_init, oti_close, NULL, - { oti067_m300_available }, - oti_speed_changed, - oti_force_redraw, - oti067_config -}; - const device_t oti067_ama932j_device = { "Oak OTI-067 (AMA-932J)", diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index ed2d4b648..0822c9148 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -2531,14 +2531,14 @@ static void s3_recalctimings(svga_t *svga) s3_t *s3 = (s3_t *)svga->p; int clk_sel = (svga->miscout >> 2) & 3; + svga->hdisp = svga->hdisp_old; svga->ma_latch |= (s3->ma_ext << 16); - if (s3->chip >= S3_86C928) { - svga->hdisp = svga->hdisp_old; + if (s3->chip >= S3_86C928) { if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + svga->hdisp |= 0x100 * svga->dots_per_clock; } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; if (svga->crtc[0x5e] & 0x02) svga->dispend |= 0x400; @@ -2547,7 +2547,7 @@ static void s3_recalctimings(svga_t *svga) if (svga->crtc[0x5e] & 0x40) svga->split |= 0x400; if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; - } + } else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; if (!svga->rowoffset) svga->rowoffset = 256; if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { @@ -2649,6 +2649,28 @@ static void s3_recalctimings(svga_t *svga) svga->rowoffset <<= 1; } } + + if (s3->chip >= S3_86C801) { + if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + } + + if (svga->crtc[0x5d] & 0x04) + svga->hblankstart += 0x100; + if (s3->chip >= S3_VISION964) { + /* NOTE: The S3 Trio64V+ datasheet says this is bit 7, but then where is bit 6? + The datasheets for the pre-Trio64V+ cards say +64, which implies bit 6, + and, contrary to VGADOC, it also exists on Trio32, Trio64, Vision868, + and Vision968. */ + // pclog("svga->crtc[0x5d] = %02X\n", svga->crtc[0x5d]); + if (svga->crtc[0x5d] & 0x08) + svga->hblank_ext = 0x40; + svga->hblank_end_len = 0x00000040; + } + } + + svga->hblank_overscan = !(svga->crtc[0x33] & 0x20); } static void s3_trio64v_recalctimings(svga_t *svga) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 07f6f3823..01afc2123 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -20,11 +20,13 @@ * Copyright 2016-2019 Miran Grca. */ #include +#include #include #include -#include #include +#include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/device.h> @@ -53,6 +55,27 @@ uint8_t svga_rotate[8][256]; static svga_t *svga_pri; +// #define ENABLE_SVGA_LOG 1 +#ifdef ENABLE_SVGA_LOG +int svga_do_log = ENABLE_SVGA_LOG; + + +static void +svga_log(const char *fmt, ...) +{ + va_list ap; + + if (svga_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define svga_log(fmt, ...) +#endif + + svga_t *svga_get_pri() { @@ -176,7 +199,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) break; case 4: svga->chain2_write = !(val & 4); - svga->chain4 = val & 8; + svga->chain4 = (svga->chain4 & ~8) | (val & 8); svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); break; @@ -235,7 +258,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) break; case 6: if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { - switch (val&0xC) { + switch (val & 0xc) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; @@ -266,6 +289,9 @@ svga_out(uint16_t addr, uint8_t val, void *p) ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); break; + case 0x3da: + svga->fcr = val; + break; } } @@ -331,6 +357,9 @@ svga_in(uint16_t addr, void *p) break; } break; + case 0x3ca: + ret = svga->fcr; + break; case 0x3cc: ret = svga->miscout; break; @@ -364,7 +393,11 @@ svga_in(uint16_t addr, void *p) svga->cgastat &= ~0x30; else svga->cgastat ^= 0x30; + ret = svga->cgastat; + + if ((svga->fcr & 0x08) && svga->dispon) + ret |= 0x08; break; } @@ -396,6 +429,10 @@ void svga_recalctimings(svga_t *svga) { double crtcconst, _dispontime, _dispofftime, disptime; +#ifdef ENABLE_SVGA_LOG + int vsyncend, vblankend; + int hdispstart, hdispend, hsyncstart, hsyncend; +#endif svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; @@ -433,12 +470,9 @@ svga_recalctimings(svga_t *svga) svga->vblankstart |= 0x200; svga->vblankstart++; - svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + svga->hdisp = svga->crtc[1] - ((svga->crtc[3] & 0x60) >> 5); svga->hdisp++; - svga->htotal = svga->crtc[0]; - svga->htotal += 6; /*+6 is required for Tyrian*/ - svga->rowoffset = svga->crtc[0x13]; svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; @@ -455,20 +489,19 @@ svga_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; if (!svga->scrblank && svga->attr_palette_enable) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + else + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ { + if (svga->seqregs[1] & 8) /*40 column*/ svga->render = svga_render_text_40; - svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; - /* Character clock is off by 1 now in 40-line modes, on all cards. */ - svga->ma_latch--; - svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; - } else { + else svga->render = svga_render_text_80; - svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; - } svga->hdisp_old = svga->hdisp; } else { - svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; svga->hdisp_old = svga->hdisp; switch (svga->gdcreg[5] & 0x60) { @@ -530,7 +563,7 @@ svga_recalctimings(svga_t *svga) } svga->linedbl = svga->crtc[9] & 0x80; - svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; + svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; if (enable_overscan) { overscan_y = (svga->rowcount + 1) << 1; @@ -547,9 +580,41 @@ svga_recalctimings(svga_t *svga) } else overscan_x = 16; + svga->htotal = svga->crtc[0]; + svga->hblankstart = svga->crtc[4] + 1; + svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00); + // pclog("htotal = %i, hblankstart = %i, hblank_end_val = %02X\n", svga->htotal, svga->hblankstart, svga->hblank_end_val); + svga->hblank_end_len = 0x00000040; + svga->hblank_overscan = 1; + + if (!svga->scrblank && svga->attr_palette_enable) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + else + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); + } else + svga->dots_per_clock = 1; + + /* Do svga->recalctimings_ex() here so that the above five variables can be + updated by said function. */ if (svga->recalctimings_ex) svga->recalctimings_ex(svga); + svga->htotal += 6; /*+6 is required for Tyrian*/ + svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; + if (svga->hblankend <= svga->hblankstart) + svga->hblankend += svga->hblank_end_len; + svga->hblankend += svga->hblank_ext; + + svga->hblank_sub = 0; + if (svga->hblankend > svga->htotal) { + svga->hblankend &= (svga->hblank_end_len - 1); + svga->hblank_sub = svga->hblankend + svga->hblank_overscan; + + svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + } + svga->y_add = (overscan_y >> 1) - (svga->crtc[8] & 0x1f); svga->x_add = (overscan_x >> 1); @@ -558,6 +623,44 @@ svga_recalctimings(svga_t *svga) crtcconst = svga->clock * svga->char_width; +#ifdef ENABLE_SVGA_LOG + vsyncend = (svga->vsyncstart & 0xfffffff0) | (svga->crtc[0x11] & 0x0f); + if (vsyncend <= svga->vsyncstart) + vsyncend += 0x00000010; + vblankend = (svga->vblankstart & 0xffffff80) | (svga->crtc[0x16] & 0x7f); + if (vblankend <= svga->vblankstart) + vblankend += 0x00000080; + + hdispstart = ((svga->crtc[3] >> 5) & 3); + hdispend = svga->crtc[1] + 1; + hsyncstart = svga->crtc[4] + ((svga->crtc[5] >> 5) & 3) + 1; + hsyncend = (hsyncstart & 0xffffffe0) | (svga->crtc[5] & 0x1f); + if (hsyncend <= hsyncstart) + hsyncend += 0x00000020; +#endif + + svga_log("Last scanline in the vertical period: %i\n" + "First scanline after the last of active display: %i\n" + "First scanline with vertical retrace asserted: %i\n" + "First scanline after the last with vertical retrace asserted: %i\n" + "First scanline of blanking: %i\n" + "First scanline after the last of blanking: %i\n" + "\n" + "Last character in the horizontal period: %i\n" + "First character of active display: %i\n" + "First character after the last of active display: %i\n" + "First character with horizontal retrace asserted: %i\n" + "First character after the last with horizontal retrace asserted: %i\n" + "First character of blanking: %i\n" + "First character after the last of blanking: %i\n" + "\n" + "\n", + svga->vtotal, svga->dispend, svga->vsyncstart, vsyncend, + svga->vblankstart, vblankend, + svga->htotal, hdispstart, hdispend, hsyncstart, hsyncend, + svga->hblankstart, svga->hblankend + ); + disptime = svga->htotal; _dispontime = svga->hdisp_time; @@ -643,6 +746,8 @@ svga_poll(void *p) uint32_t x, blink_delay; int wx, wy; int ret, old_ma; + // int lines_num = (svga->vtotal > svga->vsyncstart) ? svga->vtotal : svga->vsyncstart; + // int lines_num = svga->vsyncstart + 3 + 19; if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { @@ -721,7 +826,7 @@ svga_poll(void *p) svga->displine++; if (svga->interlace) svga->displine++; - if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15))) svga->cgastat &= ~8; svga->vslines++; if (svga->displine > 1500) @@ -773,11 +878,12 @@ svga_poll(void *p) if (ret) { if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else - svga->ma = svga->maback = ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; svga->ma = (svga->ma << 2); svga->maback = (svga->maback << 2); + svga->sc = 0; if (svga->attrregs[0x10] & 0x20) { svga->scrollcache = 0; @@ -842,9 +948,9 @@ svga_poll(void *p) svga->vslines = 0; if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else - svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; svga->ca = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + ((svga->crtc[0xb] & 0x60) >> 5) + svga->ca_adj; svga->ma = (svga->ma << 2); @@ -854,6 +960,7 @@ svga_poll(void *p) if (svga->vsync_callback) svga->vsync_callback(svga); } + // if (svga->vc == lines_num) { if (svga->vc == svga->vtotal) { svga->vc = 0; svga->sc = 0; @@ -973,6 +1080,7 @@ svga_init(const device_t *info, svga_t *svga, void *p, int memsize, svga->ramdac_type = RAMDAC_6BIT; svga->map8 = svga->pallook; + svga->hblank_overscan = 1; /* Do at least 1 character of overscan after horizontal blanking. */ return 0; } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 3a929fe73..3f0095088 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -111,6 +111,8 @@ video_cards[] = { { "tvga9000b", &tvga9000b_device }, { "tgkorvga", &et4000k_isa_device }, { "et2000", &et2000_device }, + { "et3000ax", &et3000_isa_device }, + { "et4000ax_tc6058af", &et4000_tc6058af_isa_device }, { "et4000ax", &et4000_isa_device }, { "et4000w32", &et4000w32_device }, { "et4000w32i", &et4000w32i_isa_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 33686f07e..15e86c28a 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -46,10 +46,7 @@ ifeq ($(DEV_BUILD), y) HEDAKA := y endif ifndef I450KX - I450KX := y - endif - ifndef M154X - M154X := y + I450KX := y endif ifndef LASERXT LASERXT := y @@ -78,9 +75,6 @@ ifeq ($(DEV_BUILD), y) ifndef SIO_DETECT SIO_DETECT := y endif - ifndef M154X - M154X := y - endif ifndef M6117 M6117 := y endif @@ -99,6 +93,9 @@ ifeq ($(DEV_BUILD), y) ifndef OLIVETTI OLIVETTI := y endif + ifndef NEW_KBC + NEW_KBC := n + endif else ifndef DEBUG DEBUG := n @@ -124,9 +121,6 @@ else ifndef LASERXT LASERXT := n endif - ifndef M154X - M154X := n - endif ifndef MGA MGA := n endif @@ -151,9 +145,6 @@ else ifndef SIO_DETECT SIO_DETECT := n endif - ifndef M154X - M154X := n - endif ifndef M6117 M6117 := n endif @@ -172,6 +163,9 @@ else ifndef OLIVETTI OLIVETTI := n endif + ifndef NEW_KBC + NEW_KBC := n + endif endif # Defaults for several build options (possibly defined in a chained file.) @@ -557,11 +551,6 @@ OPTS += -DUSE_SIO_DETECT DEVBROBJ += sio_detect.o endif -ifeq ($(M154X), y) -OPTS += -DUSE_M154X -DEVBROBJ += ali1531.o ali1543.o -endif - ifeq ($(M6117), y) OPTS += -DUSE_M6117 DEVBROBJ += ali6117.o @@ -598,8 +587,8 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := 86box.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ +MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ usb.o device.o nvr.o nvr_at.o nvr_ps2.o \ $(VNCOBJ) @@ -610,13 +599,18 @@ CPUOBJ := cpu.o cpu_table.o fpu.o x86.o \ x86seg.o x87.o x87_timings.o \ $(DYNARECOBJ) -CHIPSETOBJ := 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 \ - sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o sis_5598.o stpc.o opti283.o opti291.o \ - umc_8886.o umc_8890.o umc_hb4.o \ - via_apollo.o via_pipc.o wd76c10.o vl82c480.o +CHIPSETOBJ := acc2168.o \ + cs4031.o cs8230.o \ + ali1217.o ali1429.o ali1489.o ali1531.o ali1543.o \ + gc100.o headland.o \ + intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ + neat.o \ + opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ + scamp.o scat.o \ + stpc.o \ + wd76c10.o vl82c480.o \ + via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ + sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ @@ -632,10 +626,21 @@ MCHOBJ := machine.o machine_table.o \ m_ps2_isa.o m_ps2_mca.o \ m_at_compaq.o \ m_at_286_386sx.o m_at_386dx_486.o \ - m_at_socket4_5.o m_at_socket7.o m_at_sockets7.o \ + m_at_socket4.o m_at_socket5.o m_at_socket7_3v.o m_at_socket7.o m_at_sockets7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o +ifeq ($(NEW_KBC), y) +DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ + lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ + i2c.o i2c_gpio.o smbus_piix4.o \ + keyboard.o \ + keyboard_xt.o kbc_at.o kbd_at.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o \ + phoenix_486_jumper.o +else DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_piix4.o \ @@ -645,10 +650,11 @@ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm mouse_bus.o \ mouse_serial.o mouse_ps2.o \ phoenix_486_jumper.o +endif SIOOBJ := sio_acc3221.o \ sio_f82c710.o sio_82091aa.o sio_fdc37c651.o \ - sio_fdc37c661.o sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ + sio_fdc37c661.o sio_fdc37c66x.o sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ sio_it8661f.o \ sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \ sio_prime3b.o sio_prime3c.o \ @@ -753,6 +759,7 @@ VIDOBJ := video.o \ vid_bt48x_ramdac.o \ vid_av9194.o vid_icd2061.o vid_ics2494.o vid_ics2595.o \ vid_cl54xx.o \ + vid_et3000.o \ vid_et4000.o vid_sc1148x_ramdac.o \ vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ diff --git a/src/win/win.c b/src/win/win.c index 0854dac64..5f8dd60f5 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -508,7 +508,8 @@ main_thread(void *param) frames = 0; } } else /* Just so we dont overload the host OS. */ - Sleep(1); + Sleep((drawits < -1) ? 1 : 0); + // Sleep(1); /* If needed, handle a screen resize. */ if (doresize && !video_fullscreen) { From a896953dd5f7590a403b8cbeb1d72878967b6be9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 18:16:35 +0200 Subject: [PATCH 002/140] Current WIP ALi work. --- src/chipset/CMakeLists.txt | 4 +- src/chipset/ali1531.c | 19 +- src/chipset/ali1541.c | 656 ++++++++++++++++ src/chipset/ali1543.c | 257 +++++-- src/chipset/ali1621.c | 757 +++++++++++++++++++ src/chipset/intel_piix.c | 2 +- src/chipset/via_pipc.c | 2 +- src/device/CMakeLists.txt | 4 +- src/device/pci_bridge.c | 157 +++- src/device/smbus_ali7101.c | 312 ++++++++ src/device/smbus_piix4.c | 2 +- src/include/86box/chipset.h | 2 + src/include/86box/machine.h | 3 + src/include/86box/pci.h | 7 +- src/include/86box/{smbus_piix4.h => smbus.h} | 18 +- src/machine/m_at_sockets7.c | 66 ++ src/machine/machine_table.c | 6 + src/win/Makefile.mingw | 4 +- 18 files changed, 2190 insertions(+), 88 deletions(-) create mode 100644 src/chipset/ali1541.c create mode 100644 src/chipset/ali1621.c create mode 100644 src/device/smbus_ali7101.c rename src/include/86box/{smbus_piix4.h => smbus.h} (66%) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index ab8f96e61..ead771da7 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,8 +13,8 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c ali1531.c ali1543.c - headland.c intel_82335.c cs4031.c intel_420ex.c intel_4x0.c intel_sio.c intel_piix.c +add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c ali1531.c ali1541.c + ali1543.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 opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index ce161ce7c..59080144f 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -253,27 +253,10 @@ ali1531_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x7f; break; - case 0x60: /* DRB's */ - case 0x62: - case 0x64: - case 0x66: - case 0x68: - case 0x6a: - case 0x6c: - case 0x6e: + case 0x60 ... 0x6f: /* DRB's */ dev->pci_conf[addr] = val; spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); break; - case 0x61: - case 0x63: - case 0x65: - case 0x67: - case 0x69: - case 0x6b: - case 0x6d: - case 0x6f: - dev->pci_conf[addr] = val; - break; case 0x70: case 0x71: dev->pci_conf[addr] = val; diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c new file mode 100644 index 000000000..16587b3fc --- /dev/null +++ b/src/chipset/ali1541.c @@ -0,0 +1,656 @@ +/* + * 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 ALi M1541/2 CPU-to-PCI Bridge. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> + +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> + +#include <86box/chipset.h> + + +typedef struct ali1541_t +{ + uint8_t pci_conf[256]; + + smram_t * smram; + void * agp_bridge; +} ali1541_t; + + +#ifdef ENABLE_ALI1541_LOG +int ali1541_do_log = ENABLE_ALI1541_LOG; +static void +ali1541_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1541_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1541_log(fmt, ...) +#endif + + +static void +ali1541_smram_recalc(uint8_t val, ali1541_t *dev) +{ + smram_disable_all(); + + if (val & 1) { + switch (val & 0x0c) { + case 0x00: + ali1541_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); + break; + case 0x04: + ali1541_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + break; + case 0x08: + ali1541_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + break; + } + } + + flushmmucache_nopc(); +} + + +static void +ali1541_shadow_recalc(int cur_reg, ali1541_t *dev) +{ + int i, bit, r_reg, w_reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 16; i++) { + base = 0x000c0000 + (i << 14); + bit = i & 7; + r_reg = 0x56 + (i >> 3); + w_reg = 0x58 + (i >> 3); + + flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[r_reg] & (1 << bit)) + shadowbios |= 1; + if (dev->pci_conf[w_reg] & (1 << bit)) + shadowbios_write |= 1; + } + + ali1541_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + flushmmucache_nopc(); +} + + +static void +ali1541_mask_bar(ali1541_t *dev) +{ + uint32_t bar, mask; + + switch (dev->pci_conf[0xbc] & 0x0f) { + case 0x00: + default: + mask = 0x00000000; + break; + case 0x01: + mask = 0xfff00000; + break; + case 0x02: + mask = 0xffe00000; + break; + case 0x03: + mask = 0xffc00000; + break; + case 0x04: + mask = 0xff800000; + break; + case 0x06: + mask = 0xff000000; + break; + case 0x07: + mask = 0xfe000000; + break; + case 0x08: + mask = 0xfc000000; + break; + case 0x09: + mask = 0xf8000000; + break; + case 0x0a: + mask = 0xf0000000; + break; + } + + bar = ((dev->pci_conf[0x13] << 24) | (dev->pci_conf[0x12] << 16)) & mask; + dev->pci_conf[0x12] = (bar >> 16) & 0xff; + dev->pci_conf[0x13] = (bar >> 24) & 0xff; +} + + +static void +ali1541_write(int func, int addr, uint8_t val, void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf8); + break; + + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x12: + dev->pci_conf[0x12] = (val & 0xc0); + ali1541_mask_bar(dev); + break; + case 0x13: + dev->pci_conf[0x13] = val; + ali1541_mask_bar(dev); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val; + break; + + case 0x34: + if (dev->pci_conf[0x90] & 0x02) + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x41: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x42: /* L2 Cache */ + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = !!(val & 1); + cpu_update_waitstates(); + break; + + case 0x43: /* PLCTL-Pipe Line Control */ + dev->pci_conf[addr] = val & 0xf7; + break; + + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; + case 0x46: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0x47: + dev->pci_conf[addr] = val; + break; + + case 0x48: + dev->pci_conf[addr] = val; + break; + case 0x49: + dev->pci_conf[addr] = val; + break; + + case 0x4a: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x4b: + dev->pci_conf[addr] = val; + break; + + case 0x4c: + dev->pci_conf[addr] = val; + break; + case 0x4d: + dev->pci_conf[addr] = val; + break; + + case 0x4e: + dev->pci_conf[addr] = val; + break; + case 0x4f: + dev->pci_conf[addr] = val; + break; + + case 0x50: + dev->pci_conf[addr] = val & 0x71; + break; + + case 0x51: + dev->pci_conf[addr] = val; + break; + + case 0x52: + dev->pci_conf[addr] = val; + break; + + case 0x53: + dev->pci_conf[addr] = val; + break; + + case 0x54: + dev->pci_conf[addr] = val & 0x3c; + + if (mem_size > 0xe00000) + mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + if (mem_size > 0xf00000) + mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + flushmmucache_nopc(); + break; + + case 0x55: /* SMRAM */ + dev->pci_conf[addr] = val & 0x1f; + ali1541_smram_recalc(val, dev); + break; + + case 0x56 ... 0x59: /* Shadow RAM */ + dev->pci_conf[addr] = val; + ali1541_shadow_recalc(val, dev); + break; + + case 0x5a: case 0x5b: + dev->pci_conf[addr] = val; + break; + + case 0x5c: + dev->pci_conf[addr] = val; + break; + + case 0x5d: + dev->pci_conf[addr] = val & 0x17; + break; + + case 0x5e: + dev->pci_conf[addr] = val; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0xc1; + break; + + case 0x60 ... 0x6f: /* DRB's */ + dev->pci_conf[addr] = val; + spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); + break; + + case 0x70: + dev->pci_conf[addr] = val; + break; + + case 0x71: + dev->pci_conf[addr] = val; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xc7; + break; + + case 0x73: + dev->pci_conf[addr] = val & 0x1f; + break; + + case 0x84: case 0x85: + dev->pci_conf[addr] = val; + break; + + case 0x86: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x87: /* H2PO */ + dev->pci_conf[addr] = val; + /* Find where the Shut-down Special cycle is initiated. */ + // if (!(val & 0x20)) + // outb(0x92, 0x01); + break; + + case 0x88: + dev->pci_conf[addr] = val; + break; + + case 0x89: + dev->pci_conf[addr] = val; + break; + + case 0x8a: + dev->pci_conf[addr] = val; + break; + + case 0x8b: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x8c: + dev->pci_conf[addr] = val; + break; + + case 0x8d: + dev->pci_conf[addr] = val; + break; + + case 0x8e: + dev->pci_conf[addr] = val; + break; + + case 0x8f: + dev->pci_conf[addr] = val; + break; + + case 0x90: + dev->pci_conf[addr] = val; + pci_bridge_set_ctl(dev->agp_bridge, val); + break; + + case 0x91: + dev->pci_conf[addr] = val; + break; + + case 0xb4: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb5: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x02; + break; + case 0xb7: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val; + break; + + case 0xb8: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb9: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xbb: + dev->pci_conf[addr] = val; + break; + + case 0xbc: + dev->pci_conf[addr] = val & 0x0f; + ali1541_mask_bar(dev); + break; + case 0xbd: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0xbe: case 0xbf: + dev->pci_conf[addr] = val; + break; + + case 0xc0: + dev->pci_conf[addr] = val & 0x90; + break; + case 0xc1: case 0xc2: + case 0xc3: + dev->pci_conf[addr] = val; + break; + + case 0xc8: case 0xc9: + dev->pci_conf[addr] = val; + break; + + case 0xd1: + dev->pci_conf[addr] = val & 0xf1; + break; + case 0xd2: case 0xd3: + dev->pci_conf[addr] = val; + break; + + case 0xe0: case 0xe1: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + case 0xe2: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x3f; + break; + case 0xe3: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0xe4: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xe5: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe6: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xc0; + break; + + case 0xe7: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe8: case 0xe9: + if (dev->pci_conf[0x90] & 0x04) + dev->pci_conf[addr] = val; + break; + + case 0xea: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xeb: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xec: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0xed: + dev->pci_conf[addr] = val; + break; + + case 0xee: + dev->pci_conf[addr] = val & 0x3e; + break; + case 0xef: + dev->pci_conf[addr] = val; + break; + + case 0xf3: + dev->pci_conf[addr] = val & 0x08; + break; + + case 0xf5: + dev->pci_conf[addr] = val; + break; + + case 0xf6: + dev->pci_conf[addr] = val; + break; + + case 0xf7: + dev->pci_conf[addr] = val & 0x43; + break; + } +} + + +static uint8_t +ali1541_read(int func, int addr, void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ali1541_reset(void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + int i; + + /* Default Registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x41; + dev->pci_conf[0x03] = 0x15; + dev->pci_conf[0x04] = 0x06; + dev->pci_conf[0x05] = 0x00; + dev->pci_conf[0x06] = 0x10; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x08] = 0x00; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x0c] = 0x00; + dev->pci_conf[0x0d] = 0x20; + dev->pci_conf[0x0e] = 0x00; + dev->pci_conf[0x0f] = 0x00; + dev->pci_conf[0x2c] = 0xb9; + dev->pci_conf[0x2d] = 0x10; + dev->pci_conf[0x2e] = 0x41; + dev->pci_conf[0x2f] = 0x15; + dev->pci_conf[0x34] = 0xb0; + dev->pci_conf[0x89] = 0x20; + dev->pci_conf[0x8a] = 0x20; + dev->pci_conf[0x91] = 0x13; + dev->pci_conf[0xb0] = 0x02; + dev->pci_conf[0xb1] = 0xe0; + dev->pci_conf[0xb2] = 0x10; + dev->pci_conf[0xb4] = 0x03; + dev->pci_conf[0xb5] = 0x02; + dev->pci_conf[0xb7] = 0x1c; + dev->pci_conf[0xc8] = 0xbf; + dev->pci_conf[0xc9] = 0x0a; + dev->pci_conf[0xe0] = 0x01; + + cpu_cache_int_enabled = 1; + ali1541_write(0, 0x42, 0x00, dev); + + ali1541_write(0, 0x54, 0x00, dev); + ali1541_write(0, 0x55, 0x00, dev); + + for (i = 0; i < 4; i++) + ali1541_write(0, 0x56 + i, 0x00, dev); + + ali1541_write(0, 0x60 + i, 0x07, dev); + ali1541_write(0, 0x61 + i, 0x40, dev); + for (i = 0; i < 14; i += 2) { + ali1541_write(0, 0x62 + i, 0x00, dev); + ali1541_write(0, 0x63 + i, 0x00, dev); + } +} + + +static void +ali1541_close(void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + + smram_del(dev->smram); + free(dev); +} + + +static void * +ali1541_init(const device_t *info) +{ + ali1541_t *dev = (ali1541_t *)malloc(sizeof(ali1541_t)); + memset(dev, 0, sizeof(ali1541_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, ali1541_read, ali1541_write, dev); + + dev->smram = smram_add(); + + ali1541_reset(dev); + + dev->agp_bridge = device_add(&ali5243_agp_device); + + return dev; +} + + +const device_t ali1541_device = { + "ALi M1541 CPU-to-PCI Bridge", + DEVICE_PCI, + 0, + ali1541_init, + ali1541_close, + ali1541_reset, + {NULL}, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 4f0d3cbff..e15c77b77 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -34,15 +34,13 @@ #include <86box/fdc.h> #include <86box/hdc_ide.h> #include <86box/hdc_ide_sff8038i.h> -#include <86box/keyboard.h> #include <86box/lpt.h> #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> -#include <86box/pic.h> #include <86box/port_92.h> #include <86box/serial.h> -#include <86box/smbus_piix4.h> +#include <86box/smbus.h> #include <86box/usb.h> #include <86box/acpi.h> @@ -55,7 +53,7 @@ typedef struct ali1543_t uint8_t pci_conf[256], pmu_conf[256], usb_conf[256], ide_conf[256], sio_regs[256], device_regs[8][256], sio_index, in_configuration_mode, pci_slot, ide_slot, usb_slot, pmu_slot, usb_dev_enable, ide_dev_enable, - pmu_dev_enable; + pmu_dev_enable, type; apm_t * apm; acpi_t * acpi; @@ -65,7 +63,7 @@ typedef struct ali1543_t port_92_t * port_92; serial_t * uart[2]; sff8038i_t * ide_controller[2]; - smbus_piix4_t * smbus; + smbus_ali7101_t * smbus; usb_t * usb; } ali1543_t; @@ -120,8 +118,6 @@ static void ali1533_write(int func, int addr, uint8_t val, void *priv) { ali1543_t *dev = (ali1543_t *)priv; - int irq; - ali1543_log("M1533: dev->pci_conf[%02x] = %02x\n", addr, val); if (func > 0) @@ -129,8 +125,15 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) switch (addr) { case 0x04: /* Command Register */ - if (!(dev->pci_conf[0x5f] & 0x08)) - dev->pci_conf[0x04] = val; + if (dev->type == 1) { + if (dev->pci_conf[0x5f] & 0x08) + dev->pci_conf[0x04] = val & 0x0f; + else + dev->pci_conf[0x04] = val; + } else { + if (!(dev->pci_conf[0x5f] & 0x08)) + dev->pci_conf[0x04] = val; + } break; case 0x05: /* Command Register */ if (!(dev->pci_conf[0x5f] & 0x08)) @@ -222,11 +225,13 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; case 0x4d: /* MBIRQ0(SIRQI#), MBIRQ1(SIRQII#) Interrupt to ISA IRQ routing table */ - dev->pci_conf[addr] = val; + if (dev->type == 0) { + dev->pci_conf[addr] = val; - ali1543_log("SIRQI = IRQ %i; SIRQII = IRQ %i\n", ali1533_irq_routing[(val >> 4) & 0x0f], ali1533_irq_routing[val & 0x0f]); - // pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[(val >> 4) & 0x0f]); - // pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + ali1543_log("SIRQI = IRQ %i; SIRQII = IRQ %i\n", ali1533_irq_routing[(val >> 4) & 0x0f], ali1533_irq_routing[val & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[(val >> 4) & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + } break; /* I/O cycle posted-write first port definition */ @@ -242,7 +247,10 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val; break; case 0x53: - dev->pci_conf[addr] = val & 0xcf; + if (dev->type == 1) + dev->pci_conf[addr] = val; + else + dev->pci_conf[addr] = val & 0xcf; /* This actually enables/disables the USB *device* rather than the interface itself. */ dev->usb_dev_enable = !(val & 0x40); break; @@ -254,7 +262,10 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val; break; case 0x57: - dev->pci_conf[addr] = val & 0xc7; + if (dev->type == 1) + dev->pci_conf[addr] = val & 0xf0; + else + dev->pci_conf[addr] = val & 0xe0; break; /* IDE interface control @@ -277,7 +288,8 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->ide_slot = 0x0d; /* A24 = slot 13 */ break; } - ali1543_log("IDE slot = %02X (A%0i)\n", dev->ide_slot, dev->ide_slot + 11 - 5); + ali1543_log("IDE slot = %02X (A%0i)\n", dev->ide_slot - 5, dev->ide_slot + 11); + pclog("IDE slot = %02X (A%0i)\n", dev->ide_slot - 5, dev->ide_slot + 11); ali5229_ide_irq_handler(dev); break; @@ -303,7 +315,10 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; case 0x5e: - dev->pci_conf[addr] = val & 0xe0; + if (dev->type == 1) + dev->pci_conf[addr] = val & 0xe1; + else + dev->pci_conf[addr] = val & 0xe0; break; case 0x5f: @@ -343,7 +358,8 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->pmu_slot = 0x04; /* A15 = slot 04 */ break; } - ali1543_log("PMU slot = %02X (A%0i)\n", dev->pmu_slot, dev->pmu_slot + 11 - 5); + ali1543_log("PMU slot = %02X (A%0i)\n", dev->pmu_slot - 5, dev->pmu_slot + 11); + pclog("PMU slot = %02X (A%0i)\n", dev->pmu_slot - 5, dev->pmu_slot + 11); switch (val & 0x03) { case 0x00: dev->usb_slot = 0x14; /* A31 = slot 20 */ @@ -358,7 +374,8 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->usb_slot = 0x01; /* A12 = slot 01 */ break; } - ali1543_log("USB slot = %02X (A%0i)\n", dev->usb_slot, dev->usb_slot + 11 - 5); + ali1543_log("USB slot = %02X (A%0i)\n", dev->usb_slot - 5, dev->usb_slot + 11); + pclog("USB slot = %02X (A%0i)\n", dev->usb_slot - 5, dev->usb_slot + 11); break; case 0x73: /* DDMA Base Address */ @@ -382,9 +399,15 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; case 0x76: /* PMU IRQ Routing - we cheat and use MIRQ5 */ - dev->pci_conf[addr] = val & 0x1f; + if (dev->type == 1) + dev->pci_conf[addr] = val & 0x9f; + else + dev->pci_conf[addr] = val & 0x1f; acpi_set_mirq_is_level(dev->acpi, !!(val & 0x10)); - pci_set_mirq_routing(PCI_MIRQ5, ali1533_irq_routing[val & 0x0f]); + if ((dev->type == 1) && (val & 0x80)) + pci_set_mirq_routing(PCI_MIRQ5, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ5, ali1533_irq_routing[val & 0x0f]); /* TODO: Tell ACPI to use MIRQ5 */ break; @@ -392,10 +415,24 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x1f; pci_set_mirq_routing(PCI_MIRQ6, ali1533_irq_routing[val & 0x0f]); break; + + case 0x78: + if (dev->type == 1) { + pclog("PCI78 = %02X\n", val); + dev->pci_conf[addr] = val & 0x33; + } + break; + + case 0x7c ... 0xff: + if ((dev->type == 1) && !dev->pmu_dev_enable) { + dev->pmu_dev_enable = 1; + ali7101_write(func, addr, val, priv); + dev->pmu_dev_enable = 0; + } + break; } } - static uint8_t ali1533_read(int func, int addr, void *priv) { @@ -411,6 +448,11 @@ ali1533_read(int func, int addr, void *priv) ret |= (keyboard_at_get_mouse_scan() << 2); else if (addr == 0x58) ret = (ret & 0xbf) | (dev->ide_dev_enable ? 0x40 : 0x00); + else if ((dev->type == 1) && ((addr >= 0x7c) && (addr <= 0xff)) && !dev->pmu_dev_enable) { + dev->pmu_dev_enable = 1; + ret = ali7101_read(func, addr, priv); + dev->pmu_dev_enable = 0; + } } } @@ -506,6 +548,7 @@ ali5229_ide_irq_handler(ali1543_t *dev) static void ali5229_ide_handler(ali1543_t *dev) +ali5229_ide_handler(ali1543_t *dev) { uint32_t ch = 0; @@ -617,7 +660,14 @@ ali5229_chip_reset(ali1543_t *dev) dev->ide_conf[0x67] = 0x01; dev->ide_conf[0x78] = 0x21; - ali5229_write(0, 0x04, 0x01, dev); + if (dev->type == 1) { + dev->ide_conf[0x08] = 0xc1; + dev->ide_conf[0x4b] = 0x4a; + dev->ide_conf[0x4e] = 0xba; + dev->ide_conf[0x4f] = 0x1a; + } + + ali5229_write(0, 0x04, 0x00 /*0x01*/, dev); ali5229_write(0, 0x10, 0xf1, dev); ali5229_write(0, 0x11, 0x01, dev); ali5229_write(0, 0x14, 0xf5, dev); @@ -672,10 +722,12 @@ ali5229_write(int func, int addr, uint8_t val, void *priv) case 0x09: /* Control */ ali1543_log("IDE09: %02X\n", val); -#ifdef M1543_C - val &= ~(dev->ide_conf[0x43]); - val |= (dev->ide_conf[addr] & dev->ide_conf[0x43]); -#endif + + if (dev->type == 1) { + val &= ~(dev->ide_conf[0x43]); + val |= (dev->ide_conf[addr] & dev->ide_conf[0x43]); + } + if (dev->ide_conf[0x4d] & 0x80) dev->ide_conf[addr] = (dev->ide_conf[addr] & 0xfa) | (val & 0x05); else @@ -710,18 +762,23 @@ ali5229_write(int func, int addr, uint8_t val, void *priv) break; /* The machines don't touch anything beyond that point so we avoid any programming */ -#ifdef M1543_C case 0x43: - dev->ide_conf[addr] = val & 0x7f; + if (dev->type == 1) + dev->ide_conf[addr] = val & 0x7f; + break; + + case 0x4b: + if (dev->type == 1) + dev->ide_conf[addr] = val; break; -#endif case 0x4d: dev->ide_conf[addr] = val & 0x80; break; case 0x4f: - dev->ide_conf[addr] = val & 0x3f; + if (dev->type == 0) + dev->ide_conf[addr] = val & 0x3f; break; case 0x50: /* Configuration */ @@ -830,8 +887,13 @@ ali5237_write(int func, int addr, uint8_t val, void *priv) case 0x0c: /* Cache Line Size */ case 0x0d: /* Latency Timer */ case 0x3c: /* Interrupt Line Register */ - case 0x40 ... 0x43: /* Test Mode Register */ - dev->usb_conf[addr] = val; + + case 0x42: /* Test Mode Register */ + dev->usb_conf[addr] = val & 0x10; + break; + case 0x43: + if (dev->type == 1) + dev->usb_conf[addr] = val & 0x04; break; /* USB Base I/O */ @@ -888,7 +950,10 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) ali1543_log("PMU04: %02X\n", val); dev->pmu_conf[addr] = val & 0x01; acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + if (dev->type == 1) + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + else + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); break; /* PMU Base I/O */ @@ -899,6 +964,7 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) else if (addr == 0x11) dev->pmu_conf[addr] = val; + pclog("New ACPI base address: %08X\n", (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0)); acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); } break; @@ -906,12 +972,21 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) /* SMBus Base I/O */ case 0x14: case 0x15: if (!(dev->pmu_conf[0x5b] & 0x04)) { - if (addr == 0x14) - dev->pmu_conf[addr] = (val & 0xe0) | 1; - else if (addr == 0x15) + if (addr == 0x14) { + if (dev->type == 1) + dev->pmu_conf[addr] = (val & 0xc0) | 1; + else + dev->pmu_conf[addr] = (val & 0xe0) | 1; + } else if (addr == 0x15) dev->pmu_conf[addr] = val; - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + if (dev->type == 1) { + pclog("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0)); + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } else { + pclog("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0)); + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } } break; @@ -977,6 +1052,16 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] &= ~(val & 1); break; + case 0x50: case 0x51: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + + case 0x52: case 0x53: + if (dev->type == 1) + dev->pmu_conf[addr] &= ~val; + break; + case 0x54: /* Standby timer */ dev->pmu_conf[addr] = val; break; @@ -988,7 +1073,10 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) break; case 0x5b: /* ACPI/SMB Base I/O Control */ - dev->pmu_conf[addr] = val & 0x7f; + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x87; + else + dev->pmu_conf[addr] = val & 0x7f; break; case 0x60: @@ -1022,7 +1110,10 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val & 0xbf; break; case 0x6f: - dev->pmu_conf[addr] = val & 0x1f; + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x1e; + else + dev->pmu_conf[addr] = val & 0x1f; break; case 0x70: @@ -1065,11 +1156,17 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) break; case 0x7a: - dev->pmu_conf[addr] = val & 0x02; + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x07; + else + dev->pmu_conf[addr] = val & 0x02; break; case 0x7b: - dev->pmu_conf[addr] = val & 0x7f; + if (dev->type == 1) + dev->pmu_conf[addr] = val; + else + dev->pmu_conf[addr] = val & 0x7f; break; case 0x7c ... 0x7f: @@ -1080,12 +1177,34 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val & 0xf0; break; + case 0x82: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0x84 ... 0x87: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + case 0x88 ... 0x8b: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + case 0x8c: case 0x8d: dev->pmu_conf[addr] = val & 0x0f; break; case 0x90: - dev->pmu_conf[addr] = val & 0x01; + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x0f; + else + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0x91: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x02; break; case 0x94: @@ -1095,6 +1214,11 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val; break; + case 0x98: case 0x99: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + case 0xa4: case 0xa5: dev->pmu_conf[addr] = val; break; @@ -1115,6 +1239,11 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val & 0x0f; break; + case 0xb8: case 0xb9: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + case 0xbc: outb(0x70, val); break; @@ -1160,6 +1289,15 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val; break; + case 0xcc: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x1f; + break; + case 0xcd: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x33; + break; + case 0xd4: dev->pmu_conf[addr] = val & 0x01; break; @@ -1167,10 +1305,17 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) case 0xd8: dev->pmu_conf[addr] = val & 0xfd; break; + case 0xd9: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x3f; + break; case 0xe0: dev->pmu_conf[addr] = val & 0x03; - smbus_piix4_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); + if (dev->type == 1) + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); + else + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); break; case 0xe1: @@ -1382,7 +1527,7 @@ ali1543_reset(void *priv) ali5229_chip_reset(dev); /* M5237 */ - memset(dev->usb_conf, 0x00, sizeof(dev->pmu_conf)); + memset(dev->usb_conf, 0x00, sizeof(dev->usb_conf)); dev->usb_conf[0x00] = 0xb9; dev->usb_conf[0x01] = 0x10; dev->usb_conf[0x02] = 0x37; @@ -1444,6 +1589,8 @@ ali1543_reset(void *priv) dev->pci_conf[0x03] = 0x15; dev->pci_conf[0x04] = 0x0f; dev->pci_conf[0x07] = 0x02; + if (dev->type == 1) + dev->pci_conf[0x08] = 0xc0; dev->pci_conf[0x0a] = 0x01; dev->pci_conf[0x0b] = 0x06; @@ -1534,9 +1681,6 @@ ali1543_init(const device_t *info) dev->acpi = device_add(&acpi_ali_device); dev->nvr = device_add(&piix4_nvr_device); - /* APM */ - // dev->apm = device_add(&apm_pci_device); - /* DMA */ dma_alias_set(); @@ -1563,7 +1707,7 @@ ali1543_init(const device_t *info) dev->uart[1] = device_add_inst(&ns16550_device, 2); /* Standard SMBus */ - dev->smbus = device_add(&piix4_smbus_device); + dev->smbus = device_add(&ali7101_smbus_device); /* Super I/O Configuration Mechanism */ dev->in_configuration_mode = 0; @@ -1571,6 +1715,8 @@ ali1543_init(const device_t *info) /* USB */ dev->usb = device_add(&usb_device); + dev->type = info->local; + pci_enable_mirq(0); pci_enable_mirq(1); pci_enable_mirq(2); @@ -1597,3 +1743,16 @@ const device_t ali1543_device = { NULL, NULL }; + +const device_t ali1543c_device = { + "ALi M1543C Desktop South Bridge", + DEVICE_PCI, + 1, + ali1543_init, + ali1543_close, + ali1543_reset, + { NULL }, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c new file mode 100644 index 000000000..97fbeb522 --- /dev/null +++ b/src/chipset/ali1621.c @@ -0,0 +1,757 @@ +/* + * 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 ALi M1621/2 CPU-to-PCI Bridge. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> + +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> + +#include <86box/chipset.h> + + +typedef struct ali1621_t +{ + uint8_t pci_conf[256]; + + smram_t * smram; + void * agp_bridge; +} ali1621_t; + + +#ifdef ENABLE_ALI1621_LOG +int ali1621_do_log = ENABLE_ALI1621_LOG; +static void +ali1621_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1621_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1621_log(fmt, ...) +#endif + + +static void +ali1621_smram_recalc(uint8_t val, ali1621_t *dev) +{ + smram_disable_all(); + + if (val & 1) { + switch (val & 0x0c) { + case 0x00: + ali1621_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); + break; + case 0x04: + ali1621_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + break; + case 0x08: + ali1621_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + break; + } + } + + flushmmucache_nopc(); +} + + +static void +ali1621_shadow_recalc(int cur_reg, ali1621_t *dev) +{ + int i, bit, r_reg, w_reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 16; i++) { + base = 0x000c0000 + (i << 14); + bit = i & 7; + r_reg = 0x56 + (i >> 3); + w_reg = 0x58 + (i >> 3); + + flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[r_reg] & (1 << bit)) + shadowbios |= 1; + if (dev->pci_conf[w_reg] & (1 << bit)) + shadowbios_write |= 1; + } + + ali1621_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + flushmmucache_nopc(); +} + + +static void +ali1621_mask_bar(ali1621_t *dev) +{ + uint32_t bar, mask; + + switch (dev->pci_conf[0xbc] & 0x0f) { + case 0x00: + default: + mask = 0x00000000; + break; + case 0x01: + mask = 0xfff00000; + break; + case 0x02: + mask = 0xffe00000; + break; + case 0x03: + mask = 0xffc00000; + break; + case 0x04: + mask = 0xff800000; + break; + case 0x06: + mask = 0xff000000; + break; + case 0x07: + mask = 0xfe000000; + break; + case 0x08: + mask = 0xfc000000; + break; + case 0x09: + mask = 0xf8000000; + break; + case 0x0a: + mask = 0xf0000000; + break; + } + + bar = ((dev->pci_conf[0x13] << 24) | (dev->pci_conf[0x12] << 16)) & mask; + dev->pci_conf[0x12] = (bar >> 16) & 0xff; + dev->pci_conf[0x13] = (bar >> 24) & 0xff; +} + + +static void +ali1621_write(int func, int addr, uint8_t val, void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val & 0x01; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf0); + break; + + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x12: + dev->pci_conf[0x12] = (val & 0xc0); + ali1621_mask_bar(dev); + break; + case 0x13: + dev->pci_conf[0x13] = val; + ali1621_mask_bar(dev); + break; + + case 0x34: + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val; + break; + case 0x41: + dev->pci_conf[addr] = val; + break; + + case 0x42: + dev->pci_conf[addr] = val; + break; + case 0x43: + dev->pci_conf[addr] = val; + break; + + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; + + case 0x46: + dev->pci_conf[addr] = val; + break; + case 0x47: + dev->pci_conf[addr] = val; + break; + + case 0x48: + dev->pci_conf[addr] = val; + break; + case 0x49: + dev->pci_conf[addr] = val; + break; + + case 0x4a: + dev->pci_conf[addr] = val; + break; + + case 0x4b: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x4c: + dev->pci_conf[addr] = val; + break; + + case 0x4d: + dev->pci_conf[addr] = val; + break; + + case 0x4e: + dev->pci_conf[addr] = val; + break; + case 0x4f: + dev->pci_conf[addr] = val; + break; + + case 0x50: + dev->pci_conf[addr] = val & 0xef; + break; + + case 0x51: + dev->pci_conf[addr] = val; + break; + + case 0x52: + dev->pci_conf[addr] = val & 0x9f; + break; + + case 0x53: + dev->pci_conf[addr] = val; + break; + + case 0x54: + dev->pci_conf[addr] = val & 0xb4; + break; + case 0x55: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x56: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x57: + dev->pci_conf[addr] = val & 0x08; + break; + + case 0x58: + dev->pci_conf[addr] = val; + break; + + case 0x59: + dev->pci_conf[addr] = val; + break; + + case 0x5a: + dev->pci_conf[addr] = val; + break; + + case 0x5c: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x60: + dev->pci_conf[addr] = val; + break; + + case 0x61: + dev->pci_conf[addr] = val; + break; + + case 0x62: + dev->pci_conf[addr] = val; + break; + + case 0x63: + dev->pci_conf[addr] = val; + break; + + case 0x64: + dev->pci_conf[addr] = val & 0xb7; + break; + case 0x65: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x66: + dev->pci_conf[addr] &= ~(val & 0x33); + break; + + case 0x67: + dev->pci_conf[addr] = val; + break; + + case 0x68: + dev->pci_conf[addr] = val; + break; + + case 0x69: + dev->pci_conf[addr] = val; + break; + + case 0x6c ... case 0x7b: + /* Bits 22:20 = DRAM Row size: + - 000: 4 MB; + - 001: 8 MB; + - 010: 16 MB; + - 011: 32 MB; + - 100: 64 MB; + - 101: 128 MB; + - 110: 256 MB; + - 111: Reserved. */ + dev->pci_conf[addr] = val; + break; + + case 0x7c ... 0x7f: + dev->pci_conf[addr] = val; + break; + + case 0x80: + dev->pci_conf[addr] = val; + break; + case 0x81: + dev->pci_conf[addr] = val & 0xdf; + break; + + case 0x82: + dev->pci_conf[addr] = val & 0xf7; + break; + + case 0x54: + dev->pci_conf[addr] = val & 0x3c; + + if (mem_size > 0xe00000) + mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + if (mem_size > 0xf00000) + mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + flushmmucache_nopc(); + break; + + case 0x55: /* SMRAM */ + dev->pci_conf[addr] = val & 0x1f; + ali1621_smram_recalc(val, dev); + break; + + case 0x56 ... 0x59: /* Shadow RAM */ + dev->pci_conf[addr] = val; + ali1621_shadow_recalc(val, dev); + break; + + case 0x5a: case 0x5b: + dev->pci_conf[addr] = val; + break; + + case 0x5c: + dev->pci_conf[addr] = val; + break; + + case 0x5d: + dev->pci_conf[addr] = val & 0x17; + break; + + case 0x5e: + dev->pci_conf[addr] = val; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0xc1; + break; + + case 0x60 ... 0x6f: /* DRB's */ + dev->pci_conf[addr] = val; + spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); + break; + + case 0x70: + dev->pci_conf[addr] = val; + break; + + case 0x71: + dev->pci_conf[addr] = val; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xc7; + break; + + case 0x73: + dev->pci_conf[addr] = val & 0x1f; + break; + + case 0x84: case 0x85: + dev->pci_conf[addr] = val; + break; + + case 0x86: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x87: /* H2PO */ + dev->pci_conf[addr] = val; + /* Find where the Shut-down Special cycle is initiated. */ + // if (!(val & 0x20)) + // outb(0x92, 0x01); + break; + + case 0x88: + dev->pci_conf[addr] = val; + break; + + case 0x89: + dev->pci_conf[addr] = val; + break; + + case 0x8a: + dev->pci_conf[addr] = val; + break; + + case 0x8b: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x8c: + dev->pci_conf[addr] = val; + break; + + case 0x8d: + dev->pci_conf[addr] = val; + break; + + case 0x8e: + dev->pci_conf[addr] = val; + break; + + case 0x8f: + dev->pci_conf[addr] = val; + break; + + case 0x90: + dev->pci_conf[addr] = val; + pci_bridge_set_ctl(dev->agp_bridge, val); + break; + + case 0x91: + dev->pci_conf[addr] = val; + break; + + case 0xb4: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb5: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x02; + break; + case 0xb7: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val; + break; + + case 0xb8: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb9: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xbb: + dev->pci_conf[addr] = val; + break; + + case 0xbc: + dev->pci_conf[addr] = val & 0x0f; + ali1621_mask_bar(dev); + break; + case 0xbd: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0xbe: case 0xbf: + dev->pci_conf[addr] = val; + break; + + case 0xc0: + dev->pci_conf[addr] = val & 0x90; + break; + case 0xc1: case 0xc2: + case 0xc3: + dev->pci_conf[addr] = val; + break; + + case 0xc8: case 0xc9: + dev->pci_conf[addr] = val; + break; + + case 0xd1: + dev->pci_conf[addr] = val & 0xf1; + break; + case 0xd2: case 0xd3: + dev->pci_conf[addr] = val; + break; + + case 0xe0: case 0xe1: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + case 0xe2: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x3f; + break; + case 0xe3: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0xe4: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xe5: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe6: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xc0; + break; + + case 0xe7: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe8: case 0xe9: + if (dev->pci_conf[0x90] & 0x04) + dev->pci_conf[addr] = val; + break; + + case 0xea: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xeb: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xec: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0xed: + dev->pci_conf[addr] = val; + break; + + case 0xee: + dev->pci_conf[addr] = val & 0x3e; + break; + case 0xef: + dev->pci_conf[addr] = val; + break; + + case 0xf3: + dev->pci_conf[addr] = val & 0x08; + break; + + case 0xf5: + dev->pci_conf[addr] = val; + break; + + case 0xf6: + dev->pci_conf[addr] = val; + break; + + case 0xf7: + dev->pci_conf[addr] = val & 0x43; + break; + } +} + + +static uint8_t +ali1621_read(int func, int addr, void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ali1621_reset(void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + int i; + + /* Default Registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x21; + dev->pci_conf[0x03] = 0x16; + dev->pci_conf[0x04] = 0x06; + dev->pci_conf[0x05] = 0x00; + dev->pci_conf[0x06] = 0x10; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x08] = 0x01; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x10] = 0x08; + dev->pci_conf[0x34] = 0xb0; + dev->pci_conf[0x40] = 0x0c; + dev->pci_conf[0x41] = 0x0c; + dev->pci_conf[0x4c] = 0x04; + dev->pci_conf[0x4d] = 0x04; + dev->pci_conf[0x4e] = 0x7f; + dev->pci_conf[0x4f] = 0x7f; + dev->pci_conf[0x50] = 0x0c; + dev->pci_conf[0x53] = 0x02; + dev->pci_conf[0x5a] = 0x02; + dev->pci_conf[0x63] = 0x02; + dev->pci_conf[0x6c] = dev->pci_conf[0x70] = dev->pci_conf[0x74] = dev->pci_conf[0x78] = 0xff; + dev->pci_conf[0x6d] = dev->pci_conf[0x71] = dev->pci_conf[0x75] = dev->pci_conf[0x79] = 0xff; + dev->pci_conf[0x6e] = dev->pci_conf[0x72] = dev->pci_conf[0x76] = dev->pci_conf[0x7a] = 0x00; + dev->pci_conf[0x6f] = dev->pci_conf[0x73] = dev->pci_conf[0x77] = dev->pci_conf[0x7b] = 0xe0; + dev->pci_conf[0x6f] |= 0x06; + dev->pci_conf[0x7c] = 0x11; + dev->pci_conf[0x7d] = 0xc4; + dev->pci_conf[0x7e] = 0xc7; + dev->pci_conf[0x80] = 0x01; + dev->pci_conf[0x81] = 0xc0; + + dev->pci_conf[0x89] = 0x20; + dev->pci_conf[0x8a] = 0x20; + dev->pci_conf[0x91] = 0x13; + dev->pci_conf[0xb0] = 0x02; + dev->pci_conf[0xb1] = 0xe0; + dev->pci_conf[0xb2] = 0x10; + dev->pci_conf[0xb4] = 0x03; + dev->pci_conf[0xb5] = 0x02; + dev->pci_conf[0xb7] = 0x1c; + dev->pci_conf[0xc8] = 0xbf; + dev->pci_conf[0xc9] = 0x0a; + dev->pci_conf[0xe0] = 0x01; + + cpu_cache_int_enabled = 1; + ali1621_write(0, 0x42, 0x00, dev); + + ali1621_write(0, 0x54, 0x00, dev); + ali1621_write(0, 0x55, 0x00, dev); + + for (i = 0; i < 4; i++) + ali1621_write(0, 0x56 + i, 0x00, dev); + + ali1621_write(0, 0x60 + i, 0x07, dev); + ali1621_write(0, 0x61 + i, 0x40, dev); + for (i = 0; i < 14; i += 2) { + ali1621_write(0, 0x62 + i, 0x00, dev); + ali1621_write(0, 0x63 + i, 0x00, dev); + } +} + + +static void +ali1621_close(void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + + smram_del(dev->smram); + free(dev); +} + + +static void * +ali1621_init(const device_t *info) +{ + ali1621_t *dev = (ali1621_t *)malloc(sizeof(ali1621_t)); + memset(dev, 0, sizeof(ali1621_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, ali1621_read, ali1621_write, dev); + + dev->smram = smram_add(); + + ali1621_reset(dev); + + dev->agp_bridge = device_add(&ali5243_agp_device); + + return dev; +} + + +const device_t ali1621_device = { + "ALi M1621 CPU-to-PCI Bridge", + DEVICE_PCI, + 0, + ali1621_init, + ali1621_close, + ali1621_reset, + {NULL}, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 2c3e0fa89..d31f0f835 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -45,7 +45,7 @@ #include <86box/hdc_ide_sff8038i.h> #include <86box/usb.h> #include <86box/machine.h> -#include <86box/smbus_piix4.h> +#include <86box/smbus.h> #include <86box/chipset.h> diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index d488035ee..bae8e59fc 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -45,7 +45,7 @@ #include <86box/hdc_ide_sff8038i.h> #include <86box/usb.h> #include <86box/machine.h> -#include <86box/smbus_piix4.h> +#include <86box/smbus.h> #include <86box/chipset.h> #include <86box/sio.h> #include <86box/hwm.h> diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index f09051ac9..41f6228fa 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -16,8 +16,8 @@ add_library(dev OBJECT bugger.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c - smbus_piix4.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c - mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) + smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c + mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) if(LASERXT) target_compile_definitions(dev PRIVATE USE_LASERXT) diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index ab2d010ac..6a175d302 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -33,6 +33,7 @@ #define PCI_BRIDGE_DEC_21150 0x10110022 +#define AGP_BRIDGE_ALI_M5243 0x10b95243 #define AGP_BRIDGE_INTEL_440LX 0x80867181 #define AGP_BRIDGE_INTEL_440BX 0x80867191 #define AGP_BRIDGE_INTEL_440GX 0x808671a1 @@ -41,15 +42,16 @@ #define AGP_BRIDGE_VIA_691 0x11068691 #define AGP_BRIDGE_VIA_8601 0x11068601 +#define AGP_BRIDGE_ALI(x) (((x) >> 16) == 0x10b9) #define AGP_BRIDGE_INTEL(x) (((x) >> 16) == 0x8086) #define AGP_BRIDGE_VIA(x) (((x) >> 16) == 0x1106) -#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_VIA_597) +#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_ALI_M5243) typedef struct { uint32_t local; - uint8_t type; + uint8_t type, ctl; uint8_t regs[256]; uint8_t bus_index; @@ -77,6 +79,15 @@ pci_bridge_log(const char *fmt, ...) #endif +void +pci_bridge_set_ctl(void *priv, uint8_t ctl) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + dev->ctl = ctl; +} + + static void pci_bridge_write(int func, int addr, uint8_t val, void *priv) { @@ -94,21 +105,24 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x1e: case 0x34: case 0x3d: case 0x67: case 0xdc: - case 0xdd: case 0xde: case 0xdf: case 0xe0: - case 0xe1: case 0xe2: case 0xe3: + case 0xdd: case 0xde: case 0xdf: return; case 0x04: if (AGP_BRIDGE_INTEL(dev->local)) { if (dev->local == AGP_BRIDGE_INTEL_440BX) val &= 0x1f; - } else + } else if (AGP_BRIDGE_ALI(dev->local)) + val |= 0x02; + else val &= 0x67; break; case 0x05: if (AGP_BRIDGE_INTEL(dev->local)) val &= 0x01; + else if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x01; else val &= 0x03; break; @@ -116,6 +130,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x07: if (dev->local == AGP_BRIDGE_INTEL_440LX) dev->regs[addr] &= ~(val & 0x40); + else if (AGP_BRIDGE_ALI(dev->local)) + dev->regs[addr] &= ~(val & 0xf8); return; case 0x0c: case 0x18: @@ -129,6 +145,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) return; else if (AGP_BRIDGE_INTEL(dev->local)) val &= 0xf8; + else if (AGP_BRIDGE_ALI(dev->local)) + val &= 0xf8; break; case 0x19: @@ -144,7 +162,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) else if ((dev->local == AGP_BRIDGE_INTEL_440BX) || (dev->local == AGP_BRIDGE_INTEL_440GX)) dev->regs[addr] &= ~(val & 0xf0); - } + } else if (AGP_BRIDGE_ALI(dev->local)) + dev->regs[addr] &= ~(val & 0xf0); return; case 0x1c: case 0x1d: case 0x20: case 0x22: @@ -152,6 +171,11 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) val &= 0xf0; break; + case 0x3c: + if (!(dev->ctl & 0x80)) + return; + break; + case 0x3e: if (AGP_BRIDGE_VIA(dev->local)) val &= 0x0c; @@ -170,7 +194,9 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (dev->local == AGP_BRIDGE_INTEL_440LX) { dev->regs[addr] = ((dev->regs[addr] & 0x04) | (val & 0x02)) & ~(val & 0x04); return; - } else if (AGP_BRIDGE(dev->local)) + } else if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x06; + else if (AGP_BRIDGE(dev->local)) return; else if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x0f; @@ -207,6 +233,94 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x3f; break; + + case 0x86: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x3f; + break; + + case 0x87: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x60; + break; + + case 0x88: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x8c; + break; + + case 0x8b: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x0f; + break; + + case 0x8c: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x83; + break; + + case 0x8d: + if (AGP_BRIDGE_ALI(dev->local)) + return; + break; + + case 0xe0: case 0xe1: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } else + return; + break; + + case 0xe2: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0x3f; + else + return; + } else + return; + break; + case 0xe3: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0xfe; + else + return; + } else + return; + break; + + case 0xe4: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0x03; + else + return; + } + break; + case 0xe5: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } + break; + + case 0xe6: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0xc0; + else + return; + } + break; + + case 0xe7: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } + break; } dev->regs[addr] = val; @@ -251,6 +365,21 @@ pci_bridge_reset(void *priv) dev->regs[0x07] = 0x02; break; + case AGP_BRIDGE_ALI_M5243: + dev->regs[0x04] = 0x06; + dev->regs[0x07] = 0x04; + dev->regs[0x0d] = 0x20; + dev->regs[0x19] = 0x01; + dev->regs[0x1b] = 0x20; + dev->regs[0x34] = 0xe0; + dev->regs[0x89] = 0x20; + dev->regs[0x8a] = 0xa0; + dev->regs[0x8e] = 0x20; + dev->regs[0x8f] = 0x20; + dev->regs[0xe0] = 0x01; + pci_remap_bus(dev->bus_index, 0x01); + break; + case AGP_BRIDGE_INTEL_440LX: dev->regs[0x06] = 0xa0; dev->regs[0x07] = 0x02; @@ -362,6 +491,20 @@ const device_t dec21150_device = }; /* AGP bridges */ +const device_t ali5243_agp_device = +{ + "ALi M5243 AGP Bridge", + DEVICE_PCI, + AGP_BRIDGE_ALI_M5243, + pci_bridge_init, + NULL, + pci_bridge_reset, + { NULL }, + NULL, + NULL, + NULL +}; + const device_t i440lx_agp_device = { "Intel 82443LX/EX AGP Bridge", diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c new file mode 100644 index 000000000..1a3f49c03 --- /dev/null +++ b/src/device/smbus_ali7101.c @@ -0,0 +1,312 @@ +/* + * 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 a generic ALi M7101-compatible SMBus host + * controller. + * + * Authors: RichardG, + * Miran Grca, + * + * Copyright 2020,2021 RichardG. + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/i2c.h> +#include <86box/smbus.h> + + +#ifdef ENABLE_SMBUS_ALI7101_LOG +int smbus_ali7101_do_log = ENABLE_SMBUS_ALI7101_LOG; + + +static void +smbus_ali7101_log(const char *fmt, ...) +{ + va_list ap; + + if (smbus_ali7101_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define smbus_ali7101_log(fmt, ...) +#endif + + +static uint8_t +smbus_ali7101_read(uint16_t addr, void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + uint8_t ret = 0x00; + + switch (addr - dev->io_base) { + case 0x00: + ret = dev->stat; + break; + + case 0x02: + dev->index = 0; /* reading from this resets the block data index */ + ret = dev->ctl; + break; + + case 0x03: + ret = dev->addr; + break; + + case 0x04: + ret = dev->data0; + break; + + case 0x05: + ret = dev->data1; + break; + + case 0x06: + ret = dev->data[dev->index++]; + if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE) + dev->index = 0; + break; + + case 0x07: + ret = dev->cmd; + break; + } + + smbus_ali7101_log("SMBus ALI7101: read(%02X) = %02x\n", addr, ret); + + return ret; +} + + +static void +smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + uint8_t smbus_addr, cmd, read, prev_stat; + uint16_t timer_bytes = 0; + + smbus_ali7101_log("SMBus ALI7101: write(%02X, %02X)\n", addr, val); + + prev_stat = dev->next_stat; + dev->next_stat = 0x04; + switch (addr - dev->io_base) { + case 0x00: + dev->stat &= ~(val & 0xe2); + /* Make sure IDLE is set if we're not busy or errored. */ + if (dev->stat == 0x00) + dev->stat = 0x04; + break; + + case 0x01: + dev->ctl = val & 0xfc; + if (val & 0x04) { /* cancel an in-progress command if KILL is set */ + if (prev_stat) { /* cancel only if a command is in progress */ + timer_disable(&dev->response_timer); + dev->stat = 0x80; /* raise FAILED */ + } + } else if (val & 0x08) { /* T_OUT_CMD */ + if (prev_stat) { /* cancel only if a command is in progress */ + timer_disable(&dev->response_timer); + dev->stat = 0x20; /* raise DEVICE_ERR */ + } + } + break; + + case 0x02: + /* dispatch command if START is set */ + timer_bytes++; /* address */ + + smbus_addr = (dev->addr >> 1); + read = dev->addr & 0x01; + + cmd = (dev->ctl >> 4) & 0x7; + smbus_ali7101_log("SMBus ALI7101: addr=%02X read=%d protocol=%X cmd=%02X data0=%02X data1=%02X\n", smbus_addr, read, cmd, dev->cmd, dev->data0, dev->data1); + + /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */ + if (!i2c_start(i2c_smbus, smbus_addr, read)) { + dev->next_stat = 0x20; + break; + } + + dev->next_stat = 0x10; /* raise INTER (command completed) by default */ + + /* Decode the command protocol. */ + switch (cmd) { + case 0x0: /* quick R/W */ + break; + + case 0x1: /* byte R/W */ + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x2: /* byte data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x3: /* word data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) { /* word read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); + } else { /* word write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + } + timer_bytes += 2; + + break; + + case 0x4: /* block R/W */ + timer_bytes++; /* count the SMBus length byte now */ + + /* fall-through */ + + default: /* unknown */ + dev->next_stat = 0x20; /* raise DEV_ERR */ + timer_bytes = 0; + break; + } + + /* Finish transfer. */ + i2c_stop(i2c_smbus, smbus_addr); + break; + + case 0x03: + dev->addr = val; + break; + + case 0x04: + dev->data0 = val; + break; + + case 0x05: + dev->data1 = val; + break; + + case 0x06: + dev->data[dev->index++] = val; + if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE) + dev->index = 0; + break; + + case 0x07: + dev->cmd = val; + break; + } + + if (dev->next_stat != 0x04) { /* schedule dispatch of any pending status register update */ + dev->stat = 0x08; /* raise HOST_BUSY while waiting */ + timer_disable(&dev->response_timer); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC); + } +} + + +static void +smbus_ali7101_response(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + /* Dispatch the status register update. */ + dev->stat = dev->next_stat; +} + + +void +smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable) +{ + if (dev->io_base) + io_removehandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev); + + dev->io_base = new_io_base; + smbus_ali7101_log("SMBus ALI7101: remap to %04Xh (%sabled)\n", dev->io_base, enable ? "en" : "dis"); + + if (enable && dev->io_base) + io_sethandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev); +} + + +static void +smbus_ali7101_reset(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + timer_disable(&dev->response_timer); + dev->stat = 0x04; +} + + +static void * +smbus_ali7101_init(const device_t *info) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) malloc(sizeof(smbus_ali7101_t)); + memset(dev, 0, sizeof(smbus_ali7101_t)); + + dev->local = info->local; + dev->stat = 0x04; + /* We save the I2C bus handle on dev but use i2c_smbus for all operations because + dev and therefore dev->i2c will be invalidated if a device triggers a hard reset. */ + i2c_smbus = dev->i2c = i2c_addbus("smbus_ali7101"); + + timer_add(&dev->response_timer, smbus_ali7101_response, dev, 0); + + return dev; +} + + +static void +smbus_ali7101_close(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + if (i2c_smbus == dev->i2c) + i2c_smbus = NULL; + i2c_removebus(dev->i2c); + + free(dev); +} + + +const device_t ali7101_smbus_device = { + "ALi M7101-compatible SMBus Host Controller", + DEVICE_AT, + 0, + smbus_ali7101_init, smbus_ali7101_close, smbus_ali7101_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index f3b14eda0..09d46999d 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -26,7 +26,7 @@ #include <86box/device.h> #include <86box/timer.h> #include <86box/i2c.h> -#include <86box/smbus_piix4.h> +#include <86box/smbus.h> #ifdef ENABLE_SMBUS_PIIX4_LOG diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index b0a3cb71f..d20618051 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -26,7 +26,9 @@ extern const device_t ali1217_device; extern const device_t ali1429_device; extern const device_t ali1489_device; extern const device_t ali1531_device; +extern const device_t ali1541_device; extern const device_t ali1543_device; +extern const device_t ali1543c_device; #if defined(DEV_BRANCH) && defined(USE_M6117) extern const device_t ali6117d_device; #endif diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c63a3b991..b3e9b66d5 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -497,6 +497,9 @@ extern int machine_at_m560_init(const machine_t *); extern int machine_at_ms5164_init(const machine_t *); /* m_at_sockets7.c */ +extern int machine_at_m579_init(const machine_t *); +extern int machine_at_ga_5aa_init(const machine_t *); + extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); extern int machine_at_ficva503a_init(const machine_t *); diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 8e28fbbdf..18c19dd55 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -45,10 +45,6 @@ #define PCI_MIRQ1 1 #define PCI_MIRQ2 2 #define PCI_MIRQ3 3 -#define PCI_MIRQ4 4 -#define PCI_MIRQ5 5 -#define PCI_MIRQ6 6 -#define PCI_MIRQ7 7 #define PCI_IRQ_DISABLED -1 @@ -123,10 +119,13 @@ extern void trc_init(void); extern uint8_t trc_read(uint16_t port, void *priv); extern void trc_write(uint16_t port, uint8_t val, void *priv); +extern void pci_bridge_set_ctl(void *priv, uint8_t ctl); + #ifdef EMU_DEVICE_H extern const device_t dec21150_device; +extern const device_t ali5243_agp_device; extern const device_t i440lx_agp_device; extern const device_t i440bx_agp_device; extern const device_t i440gx_agp_device; diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus.h similarity index 66% rename from src/include/86box/smbus_piix4.h rename to src/include/86box/smbus.h index 3173ead4e..514ef4bde 100644 --- a/src/include/86box/smbus_piix4.h +++ b/src/include/86box/smbus.h @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Definitions for the generic PIIX4-compatible SMBus host controller. + * Definitions for the SMBus host controllers. * * * @@ -21,6 +21,9 @@ #define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 #define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1) +#define SMBUS_ALI7101_BLOCK_DATA_SIZE 32 +#define SMBUS_ALI7101_BLOCK_DATA_MASK (SMBUS_ALI7101_BLOCK_DATA_SIZE - 1) + enum { SMBUS_PIIX4 = 0, @@ -37,13 +40,26 @@ typedef struct { void *i2c; } smbus_piix4_t; +typedef struct { + uint32_t local; + uint16_t io_base; + uint8_t stat, next_stat, ctl, cmd, addr, + data0, data1, + index, data[SMBUS_ALI7101_BLOCK_DATA_SIZE]; + pc_timer_t response_timer; + void *i2c; +} smbus_ali7101_t; + extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); +extern void smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable); #ifdef EMU_DEVICE_H extern const device_t piix4_smbus_device; extern const device_t via_smbus_device; + +extern const device_t ali7101_smbus_device; #endif diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index f15ddf01b..e51fda097 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -42,6 +42,72 @@ #include <86box/machine.h> +int +machine_at_m579_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m579/MS6260S_Socket7_ALi_M1542_AMI.BIN", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + +int +machine_at_ga_5aa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ga-5aa/GA-5AA.F7b", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + int machine_at_ax59pro_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 75dad8e60..f80d66334 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -667,6 +667,12 @@ const machine_t machines[] = { { "[ALi ALADDiN IV] MSI MS-5164", "ms5164", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ms5164_init, NULL }, /* Super Socket 7 machines */ + /* ALi ALADDiN V */ + /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge + with on-chip KBC. */ + { "[ALi ALADDiN V] PC Chips M579", "m579", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m579_init, NULL }, + { "[ALi ALADDiN V] Gigabyte GA-5AA", "ga-5aa", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5aa_init, NULL }, + /* Apollo MVP3 */ /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA VT82C42N. */ diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 15e86c28a..beed254e0 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -601,7 +601,7 @@ CPUOBJ := cpu.o cpu_table.o fpu.o x86.o \ CHIPSETOBJ := acc2168.o \ cs4031.o cs8230.o \ - ali1217.o ali1429.o ali1489.o ali1531.o ali1543.o \ + ali1217.o ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o \ gc100.o headland.o \ intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o \ @@ -633,7 +633,7 @@ MCHOBJ := machine.o machine_table.o \ ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ - i2c.o i2c_gpio.o smbus_piix4.o \ + i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o kbc_at.o kbd_at.o \ mouse.o \ From 2f24523802c92c766c2da7e96c388160f888759f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 18:22:00 +0200 Subject: [PATCH 003/140] And more fixes. --- src/chipset/ali1543.c | 7 ++++++- src/include/86box/pci.h | 4 ++++ src/win/Makefile.mingw | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index e15c77b77..bec3663cc 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -34,10 +34,12 @@ #include <86box/fdc.h> #include <86box/hdc_ide.h> #include <86box/hdc_ide_sff8038i.h> +#include <86box/keyboard.h> #include <86box/lpt.h> #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> +#include <86box/pic.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/smbus.h> @@ -113,11 +115,15 @@ static void ali5229_ide_irq_handler(ali1543_t *dev); static void ali5229_write(int func, int addr, uint8_t val, void *priv); +static void ali7101_write(int func, int addr, uint8_t val, void *priv); +static uint8_t ali7101_read(int func, int addr, void *priv); + static void ali1533_write(int func, int addr, uint8_t val, void *priv) { ali1543_t *dev = (ali1543_t *)priv; + int irq; ali1543_log("M1533: dev->pci_conf[%02x] = %02x\n", addr, val); if (func > 0) @@ -548,7 +554,6 @@ ali5229_ide_irq_handler(ali1543_t *dev) static void ali5229_ide_handler(ali1543_t *dev) -ali5229_ide_handler(ali1543_t *dev) { uint32_t ch = 0; diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 18c19dd55..0041855e4 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -45,6 +45,10 @@ #define PCI_MIRQ1 1 #define PCI_MIRQ2 2 #define PCI_MIRQ3 3 +#define PCI_MIRQ4 4 +#define PCI_MIRQ5 5 +#define PCI_MIRQ6 6 +#define PCI_MIRQ7 7 #define PCI_IRQ_DISABLED -1 diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index beed254e0..9c515eaa8 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -643,7 +643,7 @@ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm else DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ - i2c.o i2c_gpio.o smbus_piix4.o \ + i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ mouse.o \ From 9d62da4548f6592a6e2b9fa1654be2e64f7b417e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 18:24:23 +0200 Subject: [PATCH 004/140] And SPD. --- src/mem/spd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/mem/spd.c b/src/mem/spd.c index 821f88e71..74346417b 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -388,7 +388,8 @@ void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) { uint8_t row, dimm, drb, apollo = 0; - uint16_t size, rows[SPD_MAX_SLOTS]; + uint16_t size, size_acc; + uint16_t rows[SPD_MAX_SLOTS]; /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ if (reg_max < reg_min) { @@ -426,15 +427,16 @@ spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint if (apollo && ((drb & 0xf) < 0xa)) drb = apollo + (drb & 0xf); - /* Write DRB register, adding the previous DRB's value. */ + /* Calculate previous and new size. */ if (row == 0) - regs[drb] = 0; - else if ((apollo) && (drb == apollo)) - regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */ + size_acc = 0; else - regs[drb] = regs[drb - 1]; - if (size) - regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + size_acc += (size / drb_unit); + + /* Write DRB register, adding the previous DRB's value. */ + regs[drb] = size_acc & 0xff; + regs[drb + 1] = (regs[drb + 1] & 0xf0) | ((size_acc >> 8) & 0x0f); + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row >> 1, size, regs[drb]); } } From 29c8e36e6ef2344e27392eb732168be58fca3682 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 20:50:03 +0200 Subject: [PATCH 005/140] Fixed miscellaneous bugs reported by Coverity. --- src/chipset/ali1489.c | 16 ++++++++-------- src/chipset/intel_4x0.c | 6 +++--- src/chipset/opti895.c | 4 ++-- src/chipset/via_apollo.c | 13 ++++++------- src/chipset/via_vt82c49x.c | 4 ++-- src/device/hwm_lm75.c | 5 +++-- src/device/pci_bridge.c | 6 ++++-- src/include/86box/hwm.h | 1 + src/mem/sst_flash.c | 6 ++++-- src/sio/sio_fdc37c93x.c | 2 +- src/video/vid_et4000.c | 9 ++++++--- src/win/win_joystick_rawinput.c | 2 +- src/win/win_settings.c | 2 ++ 13 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index 47e7cbd9b..03c1f4519 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -199,10 +199,10 @@ ali1489_defaults(ali1489_t *dev) smi_line = 0; in_smm = 0; - pci_set_irq(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTD, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); } @@ -570,10 +570,10 @@ ali1489_reset(void *priv) { ali1489_t *dev = (ali1489_t *)priv; - pci_set_irq(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq(PCI_INTD, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); ali1489_defaults(dev); } diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 0b157f4dd..6da41c24f 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -1303,11 +1303,11 @@ static void regs[0x0d] = 0x20; /* According to information from FreeBSD 3.x source code: 0x00 = 486DX, 0x20 = 486SX, 0x40 = 486DX2 or 486DX4, 0x80 = Pentium OverDrive. */ - if (!(hasfpu) && (cpu_multi = 1)) + if (!(hasfpu) && (cpu_multi == 1)) regs[0x50] = 0x20; - else if (!(hasfpu) && (cpu_multi = 2)) + else if (!(hasfpu) && (cpu_multi == 2)) regs[0x50] = 0x60; /* Guess based on the SX, DX, and DX2 values. */ - else if (hasfpu && (cpu_multi = 1)) + else if (hasfpu && (cpu_multi == 1)) regs[0x50] = 0x00; else if (hasfpu && (cpu_multi >= 2) && !(cpu_s->cpu_type == CPU_P24T)) regs[0x50] = 0x40; diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 447d64fa3..289388391 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -187,7 +187,7 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) case 0xe1: case 0xe2: - dev->scratch[addr] = val; + dev->scratch[addr - 0xe1] = val; break; } } @@ -214,7 +214,7 @@ opti895_read(uint16_t addr, void *priv) break; case 0xe1: case 0xe2: - ret = dev->scratch[addr]; + ret = dev->scratch[addr - 0xe1]; break; } diff --git a/src/chipset/via_apollo.c b/src/chipset/via_apollo.c index 22de563c8..bf593c487 100644 --- a/src/chipset/via_apollo.c +++ b/src/chipset/via_apollo.c @@ -213,13 +213,12 @@ via_apollo_host_bridge_write(int func, int addr, uint8_t val, void *priv) return; /*Read-only addresses*/ - if ((addr < 4) || ((addr >= 5) && (addr < 7)) || ((addr >= 8) && (addr < 0xd)) || - ((addr >= 0xe) && (addr < 0x12)) || ((addr >= 0x14) && (addr < 0x50)) || - (addr == 0x69) || ((addr >= 0x79) && (addr < 0x7e)) || - ((addr >= 0x81) && (addr < 0x84)) || ((addr >= 0x85) && (addr < 0x88)) || - ((addr >= 0x8c) && (addr < 0xa8)) || ((addr >= 0xaa) && (addr < 0xac)) || - ((addr >= 0xad) && (addr < 0xf0)) || ((addr >= 0xf8) && (addr < 0xfc)) || - (addr == 0xfd)) + if ((addr < 4) || ((addr > 5) && (addr < 7)) || ((addr >= 8) && (addr < 0xd)) || + ((addr >= 0xe) && (addr != 0x0f) && (addr < 0x12)) || ((addr >= 0x14) && (addr < 0x50)) || + ((addr > 0x7a) && (addr < 0x7e)) || ((addr >= 0x81) && (addr < 0x84)) || + ((addr >= 0x85) && (addr < 0x88)) || ((addr >= 0x8c) && (addr < 0xa8)) || + ((addr >= 0xaa) && (addr < 0xac)) || ((addr > 0xad) && (addr < 0xf0)) || + ((addr >= 0xf8) && (addr < 0xfc))) return; if (((addr == 0x78) || (addr >= 0xad)) && (dev->id == VIA_597)) return; diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index 712ad8f5a..20824b006 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -133,9 +133,9 @@ vt82c49x_recalc(vt82c49x_t *dev) state = (dev->regs[0x33] & 0x10) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL; if ((dev->regs[0x32]) & (1 << (bit + 1))) - state = MEM_READ_INTERNAL; + state |= MEM_READ_INTERNAL; else - state = (dev->regs[0x33] & 0x10) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; + state |= (dev->regs[0x33] & 0x10) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; } else if ((base >= 0xe8000) && (base <= 0xeffff)) { if (dev->regs[0x40] & 0x20) state = MEM_WRITE_DISABLED; diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 9faf73326..30615d912 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -187,13 +187,14 @@ lm75_remap(lm75_t *dev, uint8_t addr) { lm75_log("LM75: remapping to SMBus %02Xh\n", addr); - if (dev->i2c_addr < 0x80) + if (dev->i2c_enabled) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); - dev->i2c_addr = addr; + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !!(addr & 0x80); } diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 6a175d302..8e1353cc1 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -452,8 +452,10 @@ pci_bridge_init(const device_t *info) dev->slot = pci_add_card(AGP_BRIDGE(dev->local) ? PCI_ADD_AGPBRIDGE : PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev); interrupt_count = sizeof(interrupts); interrupt_mask = interrupt_count - 1; - for (i = 0; i < interrupt_count; i++) - interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i); + if (dev->slot < 32) { + for (i = 0; i < interrupt_count; i++) + interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i); + } pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]); if (info->local == PCI_BRIDGE_DEC_21150) diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 6172ec693..28e6c031c 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -36,6 +36,7 @@ typedef struct { uint8_t regs[8]; uint8_t addr_register; uint8_t i2c_addr: 7, i2c_state: 2; + uint8_t i2c_enabled; } lm75_t; diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 2b8c4a54d..9358d554c 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -402,8 +402,10 @@ sst_close(void *p) if (dev->dirty) { f = nvr_fopen(flash_path, "wb"); - fwrite(&(dev->array[0x00000]), dev->size, 1, f); - fclose(f); + if (f != NULL) { + fwrite(&(dev->array[0x00000]), dev->size, 1, f); + fclose(f); + } } free(dev->array); diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 35cfe862b..a20349aff 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -206,7 +206,7 @@ fdc37c93x_nvr_sec_handler(fdc37c93x_t *dev) dev->nvr_sec_base = ld_port = make_port_sec(dev, 6) & 0xFFFE; /* Datasheet erratum: First it says minimum address is 0x0100, but later implies that it's 0x0000 and that default is 0x0070, same as (unrelocatable) primary NVR. */ - if ((ld_port >= 0x0000) && (ld_port <= 0x0FFE)) + if (ld_port <= 0x0FFE) nvr_at_sec_handler(1, dev->nvr_sec_base, dev->nvr); } } diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 3bce65159..f1dedf4a2 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -464,7 +464,8 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) break; case 1: case 2: - et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + if ((et4000->kasan_cfg_index - 0xF0) <= 16) + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; io_removehandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); et4000->kasan_access_addr = (et4000->kasan_cfg_regs[2] << 8) | et4000->kasan_cfg_regs[1]; io_sethandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); @@ -507,8 +508,10 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) case 3: case 4: case 5: - if (et4000->kasan_cfg_regs[0] & 1) - et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; + if (et4000->kasan_cfg_regs[0] & 1) { + if ((addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)) <= 4) + et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; + } break; case 6: if ((et4000->kasan_cfg_regs[0] & 1) && (et4000->kasan_font_data[3] & !(val & 0x80)) && (et4000->get_korean_font_base & 0x7F) >= 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) { diff --git a/src/win/win_joystick_rawinput.c b/src/win/win_joystick_rawinput.c index c4f947bac..be808fc47 100644 --- a/src/win/win_joystick_rawinput.c +++ b/src/win/win_joystick_rawinput.c @@ -56,7 +56,7 @@ typedef struct { HANDLE hdevice; PHIDP_PREPARSED_DATA data; - USAGE usage_button[128]; + USAGE usage_button[256]; struct raw_axis_t { USAGE usage; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 067f7c9f9..a5f426ded 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -949,6 +949,8 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) win_settings_machine_recalc_machine(hdlg); } + + free(lptsTemp); } break; case IDC_COMBO_MACHINE: From 8e14514660b200b8bdffe6b7c4706854419d08e3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Jul 2021 21:03:28 +0200 Subject: [PATCH 006/140] More HWM fixes. --- src/device/hwm_gl518sm.c | 10 +++++++--- src/device/hwm_lm75.c | 4 ++-- src/device/hwm_lm78.c | 10 ++++++---- src/include/86box/hwm.h | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index c340ce59c..9c8eae920 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -41,7 +41,7 @@ typedef struct { uint16_t regs[32]; uint8_t addr_register: 5; - uint8_t i2c_addr: 7, i2c_state: 2; + uint8_t i2c_addr: 7, i2c_state: 2, i2c_enabled: 1; } gl518sm_t; @@ -78,12 +78,14 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr) { gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr); - i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); + if (dev->i2c_enabled) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); - dev->i2c_addr = addr; + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !(addr & 0x80); } @@ -244,6 +246,8 @@ gl518sm_reset(gl518sm_t *dev) dev->regs[0x0b] = 0xdac5; dev->regs[0x0c] = 0xdac5; dev->regs[0x0f] = 0xf8; + + gl518sm_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); } diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 30615d912..3a28e2a1f 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -194,7 +194,7 @@ lm75_remap(lm75_t *dev, uint8_t addr) i2c_sethandler(i2c_smbus, addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); dev->i2c_addr = addr & 0x7f; - dev->i2c_enabled = !!(addr & 0x80); + dev->i2c_enabled = !(addr & 0x80); } @@ -204,7 +204,7 @@ lm75_reset(lm75_t *dev) dev->regs[0x3] = 0x4b; dev->regs[0x5] = 0x50; - lm75_remap(dev, dev->local & 0x7f); + lm75_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); } diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index e849190cf..e93989afe 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -72,7 +72,7 @@ typedef struct { }; uint8_t addr_register, data_register; - uint8_t i2c_addr: 7, i2c_state: 1; + uint8_t i2c_addr: 7, i2c_state: 1, i2c_enabled: 1; } lm78_t; @@ -315,7 +315,7 @@ lm78_reset(void *priv) dev->regs[0x49] = 0x40; } - lm78_remap(dev, dev->i2c_addr); + lm78_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); } @@ -665,12 +665,14 @@ lm78_remap(lm78_t *dev, uint8_t addr) lm78_log("LM78: remapping to SMBus %02Xh\n", addr); - i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); + if (dev->i2c_enabled) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); - dev->i2c_addr = addr; + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !(addr & 0x80); if (dev->local & LM78_AS99127F) { /* Store our handle on the primary LM75 device to ensure reads/writes diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 28e6c031c..e4613f05b 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -36,7 +36,7 @@ typedef struct { uint8_t regs[8]; uint8_t addr_register; uint8_t i2c_addr: 7, i2c_state: 2; - uint8_t i2c_enabled; + uint8_t i2c_enabled: 1; } lm75_t; From 2bf2489f5051d7b2e03a7590fd181084583cd92d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 00:15:39 +0200 Subject: [PATCH 007/140] ALi SMBUS fixes. --- src/device/smbus_ali7101.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index 1a3f49c03..f5a3d4d70 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -61,11 +61,6 @@ smbus_ali7101_read(uint16_t addr, void *priv) ret = dev->stat; break; - case 0x02: - dev->index = 0; /* reading from this resets the block data index */ - ret = dev->ctl; - break; - case 0x03: ret = dev->addr; break; From ab86ee8f4a074d7409f53112005776dc17de5bdb Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 00:17:02 +0200 Subject: [PATCH 008/140] And another fix. --- src/device/smbus_ali7101.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index f5a3d4d70..32cc0a22e 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -122,6 +122,9 @@ smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv) dev->stat = 0x20; /* raise DEVICE_ERR */ } } + + if (val & 0x80) + dev->index = 0; break; case 0x02: From 903a54c0f1ebd0104b6f8bc3eeb83c290db638b5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:33:59 +0200 Subject: [PATCH 009/140] SMBus header fixes. --- src/include/86box/smbus.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/86box/smbus.h b/src/include/86box/smbus.h index 514ef4bde..6661a25c6 100644 --- a/src/include/86box/smbus.h +++ b/src/include/86box/smbus.h @@ -33,6 +33,8 @@ enum { typedef struct { uint32_t local; uint16_t io_base; + int clock; + double bit_period; uint8_t stat, next_stat, ctl, cmd, addr, data0, data1, index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; @@ -52,6 +54,8 @@ typedef struct { extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); +extern void smbus_piix4_setclock(smbus_piix4_t *dev, int clock); + extern void smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable); From a7bda63022068e69d6837698a94678c49cdf8fa9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:35:48 +0200 Subject: [PATCH 010/140] An unused smbus_piix4.h just to make merges easier. --- src/include/86box/smbus_piix4.h | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/include/86box/smbus_piix4.h diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h new file mode 100644 index 000000000..3173ead4e --- /dev/null +++ b/src/include/86box/smbus_piix4.h @@ -0,0 +1,50 @@ +/* + * 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. + * + * Definitions for the generic PIIX4-compatible SMBus host controller. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#ifndef EMU_SMBUS_PIIX4_H +# define EMU_SMBUS_PIIX4_H + + +#define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 +#define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1) + + +enum { + SMBUS_PIIX4 = 0, + SMBUS_VIA +}; + +typedef struct { + uint32_t local; + uint16_t io_base; + uint8_t stat, next_stat, ctl, cmd, addr, + data0, data1, + index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; + pc_timer_t response_timer; + void *i2c; +} smbus_piix4_t; + + +extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); + + +#ifdef EMU_DEVICE_H +extern const device_t piix4_smbus_device; +extern const device_t via_smbus_device; +#endif + + +#endif /*EMU_SMBUS_PIIX4_H*/ From f3213527dcceb76f91c417411015322546915a50 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:38:29 +0200 Subject: [PATCH 011/140] Makefile change. --- src/win/Makefile.mingw | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9c515eaa8..c67fa66f6 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -631,8 +631,9 @@ MCHOBJ := machine.o machine_table.o \ m_at_misc.o ifeq ($(NEW_KBC), y) -DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ - lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ +DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ + ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ + vpc2007.o clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o kbc_at.o kbd_at.o \ @@ -641,8 +642,9 @@ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm mouse_serial.o mouse_ps2.o \ phoenix_486_jumper.o else -DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ - lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ +DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ + ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ + vpc2007.o clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ From 950fef202ea5ef2406b6f3f4cc5ac63e390286f5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:39:43 +0200 Subject: [PATCH 012/140] And another. --- src/win/Makefile.mingw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index c67fa66f6..e4e961306 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -634,7 +634,8 @@ ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ vpc2007.o clock_ics9xxx.o isapnp.o \ - i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ + i2c.o i2c_gpio.o smbus_piix4.o \ + smbus_ali7101.o \ keyboard.o \ keyboard_xt.o kbc_at.o kbd_at.o \ mouse.o \ From 38fc26403cebf78a893e8d64d3bb9e571340cae7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:40:42 +0200 Subject: [PATCH 013/140] And another. --- src/win/Makefile.mingw | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index e4e961306..0ca531268 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -631,6 +631,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_misc.o ifeq ($(NEW_KBC), y) + DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ vpc2007.o clock_ics9xxx.o isapnp.o \ From 638dff832fffe9b53b03a6a80b334e537870b2f2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:41:43 +0200 Subject: [PATCH 014/140] I have to do this. --- src/win/Makefile.mingw | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 0ca531268..9524aa123 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -630,8 +630,6 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o -ifeq ($(NEW_KBC), y) - DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ vpc2007.o clock_ics9xxx.o isapnp.o \ @@ -643,6 +641,8 @@ DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c68 mouse_bus.o \ mouse_serial.o mouse_ps2.o \ phoenix_486_jumper.o +ifeq ($(NEW_KBC), y) + else DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ From 99b9174e02e7b97bcd6599c5dfa04c4c291bdd07 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:43:12 +0200 Subject: [PATCH 015/140] Back to normal. --- src/win/Makefile.mingw | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9524aa123..c67fa66f6 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -630,19 +630,17 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o +ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ vpc2007.o clock_ics9xxx.o isapnp.o \ - i2c.o i2c_gpio.o smbus_piix4.o \ - smbus_ali7101.o \ + i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o kbc_at.o kbd_at.o \ mouse.o \ mouse_bus.o \ mouse_serial.o mouse_ps2.o \ phoenix_486_jumper.o -ifeq ($(NEW_KBC), y) - else DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ From 9cba2a91dc98c8c1dc6b5ea32508cad105b74811 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:46:08 +0200 Subject: [PATCH 016/140] Reverted the PIT and Soyo 4SA2 changes. --- src/acpi.c | 1 + src/include/86box/pit.h | 35 ++- src/machine/m_at_386dx_486.c | 9 +- src/pit.c | 469 ++++++++++------------------------- 4 files changed, 152 insertions(+), 362 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index d8e6a12aa..d83b087bc 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -642,6 +642,7 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) break; case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ + pclog("addr = %02X, val = %02X\n", addr, val); if ((addr == 0x05) && (val & 0x20)) { sus_typ = (val >> 2) & 7; switch (sus_typ) { diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index 93f6c594e..bf8d71048 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -18,34 +18,33 @@ # define EMU_PIT_H -typedef struct ctr_s { +typedef struct { uint8_t m, ctrl, read_status, latch, s1_det, l_det, - bcd, flag_64k; + bcd, pad; - uint16_t l, rl; - - union { - uint16_t count; - struct { - uint16_t units :4; - uint16_t tens :4; - uint16_t hundreds :4; - uint16_t thousands :4; - uint16_t myriads :4; - }; - }; + uint16_t rl; int rm, wm, gate, out, newcount, clock, using_timer, latched, - state, null_count, do_read_status, do_load; + state, null_count, do_read_status; + + union { + int count; + struct { + int units :4; + int tens :4; + int hundreds :4; + int thousands :4; + int myriads :4; + }; + }; + + uint32_t l; - void (*tick_func)(struct ctr_s *ctr); void (*load_func)(uint8_t new_m, int new_count); void (*out_func)(int new_out, int old_out); - - struct PIT *pit; } ctr_t; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index eb6efeb96..93d5d9499 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -990,13 +990,10 @@ machine_at_4sa2_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - // device_add(&w83787f_device); - device_add(&prime3b_device); - // device_add(&keyboard_ps2_pci_device); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83787f_device); + device_add(&keyboard_ps2_pci_device); - // device_add(&intel_flash_bxt_device); - device_add(&sst_flash_29ee010_device); + device_add(&intel_flash_bxt_device); return ret; } diff --git a/src/pit.c b/src/pit.c index fc1e91927..9db4c45dd 100644 --- a/src/pit.c +++ b/src/pit.c @@ -64,7 +64,6 @@ int64_t firsttime = 1; #define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ #define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ #define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */ -#define PIT_OLIVETTI 256 /* The PIT is that of the Olivetti 486 (has slight timing differences). */ enum { @@ -93,214 +92,67 @@ pit_log(const char *fmt, ...) #endif -#define NEW_PIT_CODE 1 - - -#ifdef NEW_PIT_CODE -typedef void (*tf_t)(ctr_t *ctr); - - -static void ctr_tick_mode_0(ctr_t *ctr); -static void ctr_tick_mode_1(ctr_t *ctr); -static void ctr_tick_mode_2_and_6(ctr_t *ctr); -static void ctr_tick_mode_3_and_7(ctr_t *ctr); -static void ctr_tick_mode_4_and_5(ctr_t *ctr); - - -static tf_t ctr_tick_funcs[8] = { ctr_tick_mode_0, ctr_tick_mode_1, ctr_tick_mode_2_and_6, - ctr_tick_mode_3_and_7, ctr_tick_mode_4_and_5, ctr_tick_mode_4_and_5, - ctr_tick_mode_2_and_6, ctr_tick_mode_3_and_7 }; - - -/* MODE 0: Interrupt on Terminal Count. */ static void -ctr_tick_mode_0(ctr_t *ctr) +ctr_set_out(ctr_t *ctr, int out) { - uint8_t state = ctr->state; + if (ctr == NULL) + return; - switch (state) { - case 1: - /* Load count. */ - ctr->count = ctr->l; - ctr->null_count = 0; - /* Switch to next state. */ - ctr->state++; - case 2: case 3: - if (ctr->gate) { - /* Decrease counter. */ - if ((state == 3) || ctr->gate) - ctr->count--; - if ((state == 2) && ctr->gate && (ctr->count == 0)) { - /* Terminal count reached, switch to next state. */ - ctr->state++; - /* Set output high. */ - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - } - } - break; - } -} - - -/* MODE 1: Programmale One-Shoft. */ -static void -ctr_tick_mode_1(ctr_t *ctr) -{ - uint8_t state = ctr->state; - - switch (state) { - case 1: - /* Load count. */ - ctr->count = ctr->l; - ctr->null_count = 0; - /* Switch to next state. */ - ctr->state++; - /* Set output low. */ - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; - break; - case 2: case 3: - /* Decrease counter. */ - ctr->count--; - if ((state == 2) && (ctr->count == 0)) { - /* Terminal count reached, switch to next state. */ - ctr->state++; - /* Set output high. */ - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - } - break; - } + if (ctr->out_func != NULL) + ctr->out_func(out, ctr->out); + ctr->out = out; } static void -ctr_tick_mode_2_and_6(ctr_t *ctr) +ctr_decrease_count(ctr_t *ctr) { - uint8_t state = ctr->state; - - switch (state) { - case 1: case 3: - /* Load count. */ - ctr->count = ctr->l; - ctr->null_count = 0; - if (ctr->state == 3) { - /* Set output high. */ - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - } - /* Switch to next state. */ - ctr->state = 2; - break; - case 2: - /* Decrease counter. */ - if (ctr->gate) { - ctr->count--; - if (ctr->count == 1) { - /* Terminal count reached, switch to previous state. */ - ctr->state = 3; - /* Set output low. */ - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; + if (ctr->bcd) { + ctr->units--; + if (ctr->units == 0xff) { + ctr->units = 9; + ctr->tens--; + if (ctr->tens == 0xff) { + ctr->tens = 9; + ctr->hundreds--; + if (ctr->hundreds == 0xff) { + ctr->hundreds = 9; + ctr->thousands--; + if (ctr->thousands == 0xff) { + ctr->thousands = 9; + ctr->myriads--; + if (ctr->myriads == 0xff) + ctr->myriads = 0; /* 0 - 1 should wrap around to 9999. */ + } } } - break; - } -} - - -static void -ctr_tick_mode_3_and_7(ctr_t *ctr) -{ - uint8_t state = ctr->state; - uint16_t old_count = ctr->count; - - switch (state) { - case 1: - /* Load count. */ - ctr->count = ctr->l; - ctr->flag_64k = !ctr->count; - ctr->null_count = 0; - ctr->newcount = ctr->count & 1; - /* Switch to next state. */ - ctr->state = 2; - case 2: case 3: - if (ctr->gate) { - ctr->count -= (ctr->newcount ? ((ctr->state == 3) ? 3 : 1) : 2); - if (!ctr->flag_64k && (ctr->count > old_count)) { - /* Load count. */ - ctr->count = ctr->l; - ctr->flag_64k = !ctr->count; - ctr->null_count = 0; - ctr->newcount = ctr->count & 1; - /* Switch to next state. */ - ctr->state ^= 1; - /* Set output low. */ - if (ctr->out_func != NULL) - ctr->out_func(state & 1, ctr->out); - ctr->out = state & 1; - } else { - if (ctr->newcount) - ctr->newcount = 0; - ctr->flag_64k = 0; - } - } - break; - } -} - - -static void -ctr_tick_mode_4_and_5(ctr_t *ctr) -{ - uint8_t state = ctr->state; - - /* Software triggered strobe */ - /* Hardware triggered strobe */ - if (ctr->gate || (ctr->m != 4)) { - switch(state) { - case 0: case 2: - ctr->count--; - if ((state == 2) && (ctr->count < 1)) { - ctr->state++; - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; - } - break; - case 3: - ctr->state = 0; - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - break; } - } + } else + ctr->count = (ctr->count - 1) & 0xffff; } -#else + + +static void +ctr_load_count(ctr_t *ctr) +{ + int l = ctr->l ? ctr->l : 0x10000; + + ctr->count = l; + pit_log("ctr->count = %i\n", l); + ctr->null_count = 0; + ctr->newcount = !!(l & 1); +} + + static void ctr_tick(ctr_t *ctr) { uint8_t state = ctr->state; - uint16_t old_count = ctr->count; if (state == 1) { /* This is true for all modes */ - ctr->count = ctr->l; - ctr->null_count = 0; - ctr->newcount = !!(ctr->count & 1); - ctr->state++; - if ((ctr->m & 0x07) == 1) { - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; - } + ctr_load_count(ctr); + ctr->state = 2; return; } @@ -309,35 +161,38 @@ ctr_tick(ctr_t *ctr) /* Interrupt on terminal count */ switch (state) { case 2: - if (ctr->gate) { - ctr->count--; + if (ctr->gate && (ctr->count >= 1)) { + ctr_decrease_count(ctr); if (ctr->count < 1) { - ctr->state++; - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; + ctr->state = 3; + ctr_set_out(ctr, 1); } } break; case 3: - ctr->count--; + ctr_decrease_count(ctr); break; } break; case 1: /* Hardware retriggerable one-shot */ switch (state) { + case 1: + ctr_load_count(ctr); + ctr->state = 2; + ctr_set_out(ctr, 0); + break; case 2: - ctr->count--; - if (ctr->count < 1) { - ctr->state++; - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; + if (ctr->count >= 1) { + ctr_decrease_count(ctr); + if (ctr->count < 1) { + ctr->state = 3; + ctr_set_out(ctr, 1); + } } break; case 3: - ctr->count--; + ctr_decrease_count(ctr); break; } break; @@ -345,40 +200,59 @@ ctr_tick(ctr_t *ctr) /* Rate generator */ switch (state) { case 3: - ctr->count = ctr->l; - ctr->null_count = 0; - ctr->state ^= 1; - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; + ctr_load_count(ctr); + ctr->state = 2; + ctr_set_out(ctr, 1); break; case 2: - // if (ctr->gate) { - ctr->count--; + if (ctr->gate == 0) + break; + else if (ctr->count >= 2) { + ctr_decrease_count(ctr); if (ctr->count < 2) { - ctr->state ^= 1; - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; + ctr->state = 3; + ctr_set_out(ctr, 0); } - // } + } break; } break; case 3: case 7: /* Square wave mode */ switch (state) { - case 2: case 3: - if (ctr->gate != 0) { - ctr->count -= (ctr->newcount ? ((state & 1) ? 3 : 1) : 2); - if (ctr->count > old_count) { - ctr->count = ctr->l; - ctr->null_count = 0; - ctr->newcount = !!(ctr->count & 1); - ctr->state ^= 1; - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; + case 2: + if (ctr->gate == 0) + break; + else if (ctr->count >= 0) { + if (ctr->bcd) { + ctr_decrease_count(ctr); + if (!ctr->newcount) + ctr_decrease_count(ctr); + } else + ctr->count -= (ctr->newcount ? 1 : 2); + if (ctr->count < 0) { + ctr_load_count(ctr); + ctr->state = 3; + ctr_set_out(ctr, 0); + } else if (ctr->newcount) + ctr->newcount = 0; + } + break; + case 3: + if (ctr->gate == 0) + break; + else if (ctr->count >= 0) { + if (ctr->bcd) { + ctr_decrease_count(ctr); + ctr_decrease_count(ctr); + if (ctr->newcount) + ctr_decrease_count(ctr); + } else + ctr->count -= (ctr->newcount ? 3 : 2); + if (ctr->count < 0) { + ctr_load_count(ctr); + ctr->state = 2; + ctr_set_out(ctr, 1); } else if (ctr->newcount) ctr->newcount = 0; } @@ -390,20 +264,21 @@ ctr_tick(ctr_t *ctr) /* Hardware triggered strobe */ if ((ctr->gate != 0) || (ctr->m != 4)) { switch(state) { - case 0: case 2: - ctr->count--; - if ((state == 2) && (ctr->count < 1)) { - ctr->state++; - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; + case 0: + ctr_decrease_count(ctr); + break; + case 2: + if (ctr->count >= 1) { + ctr_decrease_count(ctr); + if (ctr->count < 1) { + ctr->state = 3; + ctr_set_out(ctr, 0); + } } break; case 3: ctr->state = 0; - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; + ctr_set_out(ctr, 1); break; } } @@ -412,24 +287,19 @@ ctr_tick(ctr_t *ctr) break; } } -#endif static void ctr_clock(ctr_t *ctr) { - /* FIXME: Is this even needed? */ + /* FIXME: Is this even needed? */ if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3)) return; if (ctr->using_timer) return; -#ifdef NEW_PIT_CODE - ctr->tick_func(ctr); -#else ctr_tick(ctr); -#endif } @@ -480,11 +350,6 @@ ctr_latch_count(ctr_t *ctr) { int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count; - // if ((ctr->pit->flags & PIT_OLIVETTI) && (ctr->state == 0)) - // count--; - - pit_log("PIT latch count with state %i (%i)\n", ctr->state, ctr->latch); - switch (ctr->rm & 0x03) { case 0x00: /* This should never happen. */ @@ -550,21 +415,15 @@ pit_ctr_set_gate(ctr_t *ctr, int gate) if (!old && gate) { /* Here we handle the rising edges. */ if (mode & 1) { - if (mode != 1) { - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - } + if (mode != 1) + ctr_set_out(ctr, 1); ctr->state = 1; } else if (mode == 2) ctr->state = 3; } else if (old && !gate) { /* Here we handle the lowering edges. */ - if (mode & 2) { - if (ctr->out_func != NULL) - ctr->out_func(1, ctr->out); - ctr->out = 1; - } + if (mode & 2) + ctr_set_out(ctr, 1); } break; } @@ -578,27 +437,12 @@ pit_ctr_set_clock_common(ctr_t *ctr, int clock) ctr->clock = clock; - if (!ctr->using_timer) - return; - -#if 0 - if ((ctr->pit->flags & PIT_OLIVETTI) && !old && ctr->clock) { - if (ctr->do_load) { - if (ctr->do_load == 3) - ctr_load(ctr); - ctr->do_load++; - if (ctr->do_load == 4) - ctr->do_load = 0; - } - } -#endif - - if (ctr->latch) { + if (ctr->using_timer && ctr->latch) { if (old && !ctr->clock) { ctr_set_state_1(ctr); ctr->latch = 0; } - } else if (!ctr->latch) { + } else if (ctr->using_timer && !ctr->latch) { if (ctr->state == 1) { if (!old && ctr->clock) ctr->s1_det = 1; /* Rising edge. */ @@ -606,19 +450,11 @@ pit_ctr_set_clock_common(ctr_t *ctr, int clock) ctr->s1_det++; /* Falling edge. */ if (ctr->s1_det >= 2) { ctr->s1_det = 0; -#ifdef NEW_PIT_CODE - ctr->tick_func(ctr); -#else ctr_tick(ctr); -#endif } } } else if (old && !ctr->clock) -#ifdef NEW_PIT_CODE - ctr->tick_func(ctr); -#else ctr_tick(ctr); -#endif } } @@ -702,14 +538,9 @@ pit_write(uint16_t addr, uint8_t val, void *priv) ctr->m = (val >> 1) & 7; if (ctr->m > 5) ctr->m &= 3; -#ifdef NEW_PIT_CODE - ctr->tick_func = ctr_tick_funcs[ctr->m]; -#endif ctr->null_count = 1; ctr->bcd = (ctr->ctrl & 0x01); - if (ctr->out_func != NULL) - ctr->out_func(!!ctr->m, ctr->out); - ctr->out = !!ctr->m; + ctr_set_out(ctr, !!ctr->m); ctr->state = 0; if (ctr->latched) { pit_log("PIT %i: Reload while counter is latched\n", t); @@ -732,44 +563,27 @@ pit_write(uint16_t addr, uint8_t val, void *priv) break; case 1: ctr->l = val; - if (ctr->m == 0) { - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; - } - if (dev->flags & PIT_OLIVETTI) - ctr->do_load = 1; - else - ctr_load(ctr); + if (ctr->m == 0) + ctr_set_out(ctr, 0); + ctr_load(ctr); break; case 2: ctr->l = (val << 8); - if (ctr->m == 0) { - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; - } - if (dev->flags & PIT_OLIVETTI) - ctr->do_load = 1; - else - ctr_load(ctr); + if (ctr->m == 0) + ctr_set_out(ctr, 0); + ctr_load(ctr); break; case 3: case 0x83: if (ctr->wm & 0x80) { ctr->l = (ctr->l & 0x00ff) | (val << 8); pit_log("PIT %i: Written high byte %02X, latch now %04X\n", t, val, ctr->l); - if (dev->flags & PIT_OLIVETTI) - ctr->do_load = 1; - else - ctr_load(ctr); + ctr_load(ctr); } else { ctr->l = (ctr->l & 0xff00) | val; pit_log("PIT %i: Written low byte %02X, latch now %04X\n", t, val, ctr->l); if (ctr->m == 0) { ctr->state = 0; - if (ctr->out_func != NULL) - ctr->out_func(0, ctr->out); - ctr->out = 0; + ctr_set_out(ctr, 0); } } @@ -943,7 +757,7 @@ pit_nmi_timer_ps2(int new_out, int old_out) static void -ctr_reset(pit_t *dev, ctr_t *ctr) +ctr_reset(ctr_t *ctr) { ctr->ctrl = 0; ctr->m = 0; @@ -957,8 +771,6 @@ ctr_reset(pit_t *dev, ctr_t *ctr) ctr->s1_det = 0; ctr->l_det = 0; - - ctr->pit = dev; } @@ -972,15 +784,10 @@ pit_reset(pit_t *dev) dev->clock = 0; for (i = 0; i < 3; i++) - ctr_reset(dev, &dev->counters[i]); + ctr_reset(&dev->counters[i]); /* Disable speaker gate. */ dev->counters[2].gate = 0; - -#ifdef NEW_PIT_CODE - dev->counters[0].tick_func = dev->counters[1].tick_func = - dev->counters[2].tick_func = ctr_tick_funcs[0]; -#endif } @@ -1051,17 +858,6 @@ const device_t i8254_device = }; -const device_t i8254_olivetti_device = -{ - "Intel 8254 Programmable Interval Timer (Olivetti)", - DEVICE_ISA, - PIT_8254 | PIT_OLIVETTI, - pit_init, pit_close, NULL, - { NULL }, NULL, NULL, - NULL -}; - - const device_t i8254_sec_device = { "Intel 8254 Programmable Interval Timer (Secondary)", @@ -1108,9 +904,6 @@ pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(i case PIT_8254: pit = device_add(&i8254_device); break; - case (PIT_8254 | PIT_OLIVETTI): - pit = device_add(&i8254_olivetti_device); - break; } for (i = 0; i < 3; i++) { From 3fa7579d66228db1d21c7a875f7fa5ca49fa2ad8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 Jul 2021 04:47:02 +0200 Subject: [PATCH 017/140] Reverted excess ACPI logging. --- src/acpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/acpi.c b/src/acpi.c index d83b087bc..d8e6a12aa 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -642,7 +642,6 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) break; case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ - pclog("addr = %02X, val = %02X\n", addr, val); if ((addr == 0x05) && (val & 0x20)) { sus_typ = (val >> 2) & 7; switch (sus_typ) { From dbddb3e30979cc8cedaae08b80fa39615ba1c264 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 12 Jul 2021 05:56:06 +0200 Subject: [PATCH 018/140] Finished the ALADDiN-PRO II, implemented the Contaq/Cypress 82C596(A) and 82C597 chipsets, added the ASUS P5A, Gigabyte GA-5AX, PC CHIPS M729, and Green-B, removed the "Virtual PC 2007" device as it turns out it was actually SMBus all along, did some fixes to the ALi SMBUS, fixed start LM75 SMBus address and enabled it by default, and added a ASUS P5A-specific version of the Winbond W83781D hardware monitor. --- src/chipset/CMakeLists.txt | 12 +- src/chipset/ali1543.c | 37 +-- src/chipset/ali1621.c | 436 ++++++++++++++------------------ src/chipset/contaq_82c59x.c | 476 +++++++++++++++++++++++++++++++++++ src/device/CMakeLists.txt | 2 +- src/device/hwm_lm75.c | 3 + src/device/hwm_lm78.c | 21 +- src/device/pci_bridge.c | 46 +++- src/device/smbus_ali7101.c | 4 +- src/device/vpc2007.c | 186 -------------- src/include/86box/chipset.h | 5 + src/include/86box/hwm.h | 1 + src/include/86box/machine.h | 5 + src/include/86box/mem.h | 11 + src/include/86box/pci.h | 1 + src/include/86box/spd.h | 1 + src/machine/m_at_386dx_486.c | 26 +- src/machine/m_at_misc.c | 1 - src/machine/m_at_slot1.c | 33 +++ src/machine/m_at_sockets7.c | 73 ++++++ src/machine/machine_table.c | 11 + src/mem/mem.c | 11 +- src/mem/spd.c | 87 ++++++- src/win/Makefile.mingw | 7 +- 24 files changed, 1007 insertions(+), 489 deletions(-) create mode 100644 src/chipset/contaq_82c59x.c delete mode 100644 src/device/vpc2007.c diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index ead771da7..14ca76962 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -14,12 +14,12 @@ # add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c ali1531.c ali1541.c - ali1543.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 opti391.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 - via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c - gc100.c stpc.c - via_apollo.c via_pipc.c vl82c480.c wd76c10.c) + ali1543.c ali1621.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c + intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c + sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c via_apollo.c via_pipc.c vl82c480.c + wd76c10.c) if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index bec3663cc..5e43ec9fd 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -295,7 +295,6 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; } ali1543_log("IDE slot = %02X (A%0i)\n", dev->ide_slot - 5, dev->ide_slot + 11); - pclog("IDE slot = %02X (A%0i)\n", dev->ide_slot - 5, dev->ide_slot + 11); ali5229_ide_irq_handler(dev); break; @@ -365,7 +364,6 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; } ali1543_log("PMU slot = %02X (A%0i)\n", dev->pmu_slot - 5, dev->pmu_slot + 11); - pclog("PMU slot = %02X (A%0i)\n", dev->pmu_slot - 5, dev->pmu_slot + 11); switch (val & 0x03) { case 0x00: dev->usb_slot = 0x14; /* A31 = slot 20 */ @@ -381,7 +379,6 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; } ali1543_log("USB slot = %02X (A%0i)\n", dev->usb_slot - 5, dev->usb_slot + 11); - pclog("USB slot = %02X (A%0i)\n", dev->usb_slot - 5, dev->usb_slot + 11); break; case 0x73: /* DDMA Base Address */ @@ -424,7 +421,7 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) case 0x78: if (dev->type == 1) { - pclog("PCI78 = %02X\n", val); + ali1543_log("PCI78 = %02X\n", val); dev->pci_conf[addr] = val & 0x33; } break; @@ -557,10 +554,10 @@ ali5229_ide_handler(ali1543_t *dev) { uint32_t ch = 0; - uint16_t native_base_pri_addr = (dev->ide_conf[0x11] | dev->ide_conf[0x10] << 8); - uint16_t native_side_pri_addr = (dev->ide_conf[0x15] | dev->ide_conf[0x14] << 8); - uint16_t native_base_sec_addr = (dev->ide_conf[0x19] | dev->ide_conf[0x18] << 8); - uint16_t native_side_sec_addr = (dev->ide_conf[0x1c] | dev->ide_conf[0x1b] << 8); + uint16_t native_base_pri_addr = ((dev->ide_conf[0x11] | dev->ide_conf[0x10] << 8)) & 0xfffe; + uint16_t native_side_pri_addr = ((dev->ide_conf[0x15] | dev->ide_conf[0x14] << 8)) & 0xfffe; + uint16_t native_base_sec_addr = ((dev->ide_conf[0x19] | dev->ide_conf[0x18] << 8)) & 0xfffe; + uint16_t native_side_sec_addr = ((dev->ide_conf[0x1c] | dev->ide_conf[0x1b] << 8)) & 0xfffe; uint16_t comp_base_pri_addr = 0x01f0; uint16_t comp_side_pri_addr = 0x03f6; @@ -597,7 +594,7 @@ ali5229_ide_handler(ali1543_t *dev) if (dev->ide_conf[0x04] & 0x01) { /* Primary Channel Setup */ - if (dev->ide_conf[0x09] & 0x20) { + if ((dev->ide_conf[0x09] & 0x20) || (dev->ide_conf[0x4d] & 0x80)) { ali1543_log("ali5229_ide_handler(): Primary IDE base now %04X...\n", current_pri_base); ide_set_base(0, current_pri_base); ali1543_log("ali5229_ide_handler(): Primary IDE side now %04X...\n", current_pri_side); @@ -611,7 +608,7 @@ ali5229_ide_handler(ali1543_t *dev) } /* Secondary Channel Setup */ - if (dev->ide_conf[0x09] & 0x10) { + if ((dev->ide_conf[0x09] & 0x10) || (dev->ide_conf[0x4d] & 0x80)) { ali1543_log("ali5229_ide_handler(): Secondary IDE base now %04X...\n", current_sec_base); ide_set_base(1, current_sec_base); ali1543_log("ali5229_ide_handler(): Secondary IDE side now %04X...\n", current_sec_side); @@ -650,8 +647,8 @@ ali5229_chip_reset(ali1543_t *dev) dev->ide_conf[0x15] = 0x03; dev->ide_conf[0x18] = 0x71; dev->ide_conf[0x19] = 0x01; - dev->ide_conf[0x1a] = 0x75; - dev->ide_conf[0x1b] = 0x03; + dev->ide_conf[0x1c] = 0x75; + dev->ide_conf[0x1d] = 0x03; dev->ide_conf[0x20] = 0x01; dev->ide_conf[0x21] = 0xf0; dev->ide_conf[0x3d] = 0x01; @@ -667,12 +664,13 @@ ali5229_chip_reset(ali1543_t *dev) if (dev->type == 1) { dev->ide_conf[0x08] = 0xc1; + dev->ide_conf[0x43] = 0x00; dev->ide_conf[0x4b] = 0x4a; dev->ide_conf[0x4e] = 0xba; dev->ide_conf[0x4f] = 0x1a; } - ali5229_write(0, 0x04, 0x00 /*0x01*/, dev); + ali5229_write(0, 0x04, 0x05, dev); ali5229_write(0, 0x10, 0xf1, dev); ali5229_write(0, 0x11, 0x01, dev); ali5229_write(0, 0x14, 0xf5, dev); @@ -742,10 +740,12 @@ ali5229_write(int func, int addr, uint8_t val, void *priv) break; /* Primary Base Address */ - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: + case 0x10: case 0x11: case 0x14: case 0x15: + /* FALLTHROUGH */ /* Secondary Base Address */ - case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: + case 0x18: case 0x19: case 0x1c: case 0x1d: + /* FALLTHROUGH */ /* Bus Mastering Base Address */ case 0x20: case 0x21: case 0x22: case 0x23: @@ -779,6 +779,7 @@ ali5229_write(int func, int addr, uint8_t val, void *priv) case 0x4d: dev->ide_conf[addr] = val & 0x80; + ali5229_ide_handler(dev); break; case 0x4f: @@ -969,7 +970,7 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) else if (addr == 0x11) dev->pmu_conf[addr] = val; - pclog("New ACPI base address: %08X\n", (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0)); + ali1543_log("New ACPI base address: %08X\n", (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0)); acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); } break; @@ -986,10 +987,10 @@ ali7101_write(int func, int addr, uint8_t val, void *priv) dev->pmu_conf[addr] = val; if (dev->type == 1) { - pclog("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0)); + ali1543_log("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0)); smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); } else { - pclog("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0)); + ali1543_log("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0)); smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); } } diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c index 97fbeb522..cc83899e8 100644 --- a/src/chipset/ali1621.c +++ b/src/chipset/ali1621.c @@ -36,8 +36,7 @@ typedef struct ali1621_t { uint8_t pci_conf[256]; - smram_t * smram; - void * agp_bridge; + smram_t * smram[2]; } ali1621_t; @@ -60,34 +59,80 @@ ali1621_log(const char *fmt, ...) #endif +/* Table translated to a more sensible format: + Read cycles: + SMREN SMM Mode Code Data + 0 X X PCI PCI + 1 0 Close PCI PCI + 1 0 Lock PCI PCI + 1 0 Protect PCI PCI + 1 0 Open DRAM DRAM + 1 1 Open DRAM DRAM + 1 1 Protect DRAM DRAM + 1 1 Close DRAM PCI + 1 1 Lock DRAM PCI + + Write cycles: + SMWEN SMM Mode Data + 0 X X PCI + 1 0 Close PCI + 1 0 Lock PCI + 1 0 Protect PCI + 1 0 Open DRAM + 1 1 Open DRAM + 1 1 Protect DRAM + 1 1 Close PCI + 1 1 Lock PCI + + Explanation of the modes based above: + If SM*EN = 0, SMRAM is entirely disabled, otherwise: + If mode is Close or Lock, then SMRAM always goes to PCI outside SMM, + and data to PCI, code to DRAM in SMM; + If mode is Protect, then SMRAM always goes to PCI outside SMM and + DRAM in SMM; + If mode is Open, then SMRAM always goes to DRAM. + Read and write are enabled separately. + */ static void ali1621_smram_recalc(uint8_t val, ali1621_t *dev) { + uint16_t access_smm = 0x0000, access_normal = 0x0000; + smram_disable_all(); - if (val & 1) { - switch (val & 0x0c) { - case 0x00: - ali1621_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); - smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); - if (val & 0x10) - mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); - break; - case 0x04: - ali1621_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); - smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); - if (val & 0x10) - mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); - break; - case 0x08: - ali1621_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); - smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); - if (val & 0x10) - mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + if (val & 0xc0) { + /* SMRAM 0: A0000-BFFFF */ + if (val & 0x80) { + access_smm = ACCESS_SMRAM_X; + + switch (val & 0x30) { + case 0x10: /* Open. */ + access_normal = ACCESS_SMRAM_RX; + /* FALLTHROUGH */ + case 0x30: /* Protect. */ + access_smm |= ACCESS_SMRAM_R; + break; + } + } + + if (val & 0x40) switch (val & 0x30) { + case 0x10: /* Open. */ + access_normal |= ACCESS_SMRAM_W; + /* FALLTHROUGH */ + case 0x30: /* Protect. */ + access_smm |= ACCESS_SMRAM_W; break; } + + smram_enable(dev->smram[0], 0xa0000, 0xa0000, 0x20000, ((val & 0x30) == 0x10), (val & 0x30)); + + mem_set_access(ACCESS_NORMAL, 3, 0xa0000, 0x20000, access_normal); + mem_set_access(ACCESS_SMM, 3, 0xa0000, 0x20000, access_smm); } + if (val & 0x08) + smram_enable(dev->smram[1], 0x38000, 0xa8000, 0x08000, 0, 1); + flushmmucache_nopc(); } @@ -95,32 +140,61 @@ ali1621_smram_recalc(uint8_t val, ali1621_t *dev) static void ali1621_shadow_recalc(int cur_reg, ali1621_t *dev) { - int i, bit, r_reg, w_reg; + int i, r_bit, w_bit, reg; uint32_t base, flags = 0; shadowbios = shadowbios_write = 0; - for (i = 0; i < 16; i++) { + /* C0000-EFFFF */ + for (i = 0; i < 12; i++) { base = 0x000c0000 + (i << 14); - bit = i & 7; - r_reg = 0x56 + (i >> 3); - w_reg = 0x58 + (i >> 3); + r_bit = (i << 1) + 4; + reg = 0x84; + if (r_bit > 23) { + r_bit &= 7; + reg += 3; + } else if (r_bit > 15) { + r_bit &= 7; + reg += 2; + } else if (r_bit > 7) { + r_bit &= 7; + reg++; + } + w_bit = r_bit + 1; - flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + flags = (dev->pci_conf[reg] & (1 << r_bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[reg] & (1 << w_bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); if (base >= 0x000e0000) { - if (dev->pci_conf[r_reg] & (1 << bit)) + if (dev->pci_conf[reg] & (1 << r_bit)) shadowbios |= 1; - if (dev->pci_conf[w_reg] & (1 << bit)) + if (dev->pci_conf[reg] & (1 << r_bit)) shadowbios_write |= 1; } ali1621_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, - (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + (dev->pci_conf[reg] & (1 << r_bit)) ? 'I' : 'E', (dev->pci_conf[reg] & (1 << w_bit)) ? 'I' : 'E'); mem_set_mem_state_both(base, 0x00004000, flags); } + /* F0000-FFFFF */ + base = 0x000f0000; + r_bit = 4; + w_bit = 5; + reg = 0x87; + + flags = (dev->pci_conf[reg] & (1 << r_bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[reg] & (1 << w_bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios |= 1; + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios_write |= 1; + + ali1621_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x0000ffff, + (dev->pci_conf[reg] & (1 << r_bit)) ? 'I' : 'E', (dev->pci_conf[reg] & (1 << w_bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00010000, flags); + flushmmucache_nopc(); } @@ -348,7 +422,7 @@ ali1621_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val; break; - case 0x6c ... case 0x7b: + case 0x6c ... 0x7b: /* Bits 22:20 = DRAM Row size: - 000: 4 MB; - 001: 8 MB; @@ -359,6 +433,7 @@ ali1621_write(int func, int addr, uint8_t val, void *priv) - 110: 256 MB; - 111: Reserved. */ dev->pci_conf[addr] = val; + spd_write_drbs_ali1621(dev->pci_conf, 0x6c, 0x7b); break; case 0x7c ... 0x7f: @@ -376,148 +451,53 @@ ali1621_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0xf7; break; - case 0x54: - dev->pci_conf[addr] = val & 0x3c; - - if (mem_size > 0xe00000) - mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - - if (mem_size > 0xf00000) - mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - - mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); - - flushmmucache_nopc(); + case 0x83: + dev->pci_conf[addr] = val & 0xfc; + ali1621_smram_recalc(val & 0xfc, dev); break; - case 0x55: /* SMRAM */ - dev->pci_conf[addr] = val & 0x1f; - ali1621_smram_recalc(val, dev); - break; - - case 0x56 ... 0x59: /* Shadow RAM */ - dev->pci_conf[addr] = val; + case 0x84 ... 0x87: + if (addr == 0x87) + dev->pci_conf[addr] = val & 0x3f; + else + dev->pci_conf[addr] = val; ali1621_shadow_recalc(val, dev); break; - case 0x5a: case 0x5b: + case 0x88: case 0x89: dev->pci_conf[addr] = val; break; - - case 0x5c: - dev->pci_conf[addr] = val; - break; - - case 0x5d: - dev->pci_conf[addr] = val & 0x17; - break; - - case 0x5e: - dev->pci_conf[addr] = val; - break; - - case 0x5f: - dev->pci_conf[addr] = val & 0xc1; - break; - - case 0x60 ... 0x6f: /* DRB's */ - dev->pci_conf[addr] = val; - spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); - break; - - case 0x70: - dev->pci_conf[addr] = val; - break; - - case 0x71: - dev->pci_conf[addr] = val; - break; - - case 0x72: - dev->pci_conf[addr] = val & 0xc7; - break; - - case 0x73: - dev->pci_conf[addr] = val & 0x1f; - break; - - case 0x84: case 0x85: - dev->pci_conf[addr] = val; - break; - - case 0x86: - dev->pci_conf[addr] = val & 0x0f; - break; - - case 0x87: /* H2PO */ - dev->pci_conf[addr] = val; - /* Find where the Shut-down Special cycle is initiated. */ - // if (!(val & 0x20)) - // outb(0x92, 0x01); - break; - - case 0x88: - dev->pci_conf[addr] = val; - break; - - case 0x89: - dev->pci_conf[addr] = val; - break; - case 0x8a: - dev->pci_conf[addr] = val; + dev->pci_conf[addr] = val & 0xc5; break; - case 0x8b: - dev->pci_conf[addr] = val & 0x3f; + dev->pci_conf[addr] = val & 0xbf; break; - case 0x8c: - dev->pci_conf[addr] = val; - break; - - case 0x8d: - dev->pci_conf[addr] = val; - break; - - case 0x8e: - dev->pci_conf[addr] = val; - break; - - case 0x8f: + case 0x8c ... 0x8f: dev->pci_conf[addr] = val; break; case 0x90: dev->pci_conf[addr] = val; - pci_bridge_set_ctl(dev->agp_bridge, val); + break; + case 0x91: + dev->pci_conf[addr] = val & 0x07; break; - case 0x91: + case 0x94 ... 0x97: dev->pci_conf[addr] = val; break; - case 0xb4: - if (dev->pci_conf[0x90] & 0x01) - dev->pci_conf[addr] = val & 0x03; - break; - case 0xb5: - if (dev->pci_conf[0x90] & 0x01) - dev->pci_conf[addr] = val & 0x02; - break; - case 0xb7: - if (dev->pci_conf[0x90] & 0x01) - dev->pci_conf[addr] = val; + case 0x98 ... 0x9b: + dev->pci_conf[addr] = val; break; - case 0xb8: - dev->pci_conf[addr] = val & 0x03; + case 0x9c ... 0x9f: + dev->pci_conf[addr] = val; break; - case 0xb9: - dev->pci_conf[addr] = val & 0x03; - break; - case 0xbb: + + case 0xa0: case 0xa1: dev->pci_conf[addr] = val; break; @@ -533,99 +513,53 @@ ali1621_write(int func, int addr, uint8_t val, void *priv) break; case 0xc0: - dev->pci_conf[addr] = val & 0x90; + dev->pci_conf[addr] = val & 0xb1; break; - case 0xc1: case 0xc2: - case 0xc3: + + case 0xc4 ... 0xc7: dev->pci_conf[addr] = val; break; - case 0xc8: case 0xc9: + case 0xc8: + dev->pci_conf[addr] = val & 0x8c; + break; + case 0xc9: + dev->pci_conf[addr] = val; + break; + case 0xca: + dev->pci_conf[addr] = val & 0x7f; + break; + case 0xcb: + dev->pci_conf[addr] = val & 0x87; + break; + + case 0xcc ... 0xcf: dev->pci_conf[addr] = val; break; - case 0xd1: - dev->pci_conf[addr] = val & 0xf1; + case 0xd0: + dev->pci_conf[addr] = val & 0x80; break; - case 0xd2: case 0xd3: + case 0xd2: + dev->pci_conf[addr] = val & 0x40; + break; + case 0xd3: + dev->pci_conf[addr] = val & 0xb0; + break; + + case 0xd4: + dev->pci_conf[addr] = val; + break; + case 0xd5: + dev->pci_conf[addr] = val & 0xef; + break; + case 0xd6: case 0xd7: dev->pci_conf[addr] = val; break; - case 0xe0: case 0xe1: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val; - break; - case 0xe2: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val & 0x3f; - break; - case 0xe3: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val & 0xfe; - break; - - case 0xe4: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val & 0x03; - break; - case 0xe5: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val; - break; - - case 0xe6: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val & 0xc0; - break; - - case 0xe7: - if (dev->pci_conf[0x90] & 0x20) - dev->pci_conf[addr] = val; - break; - - case 0xe8: case 0xe9: - if (dev->pci_conf[0x90] & 0x04) - dev->pci_conf[addr] = val; - break; - - case 0xea: - dev->pci_conf[addr] = val & 0xcf; - break; - - case 0xeb: - dev->pci_conf[addr] = val & 0xcf; - break; - - case 0xec: - dev->pci_conf[addr] = val & 0x3f; - break; - - case 0xed: + case 0xf0 ... 0xff: dev->pci_conf[addr] = val; break; - - case 0xee: - dev->pci_conf[addr] = val & 0x3e; - break; - case 0xef: - dev->pci_conf[addr] = val; - break; - - case 0xf3: - dev->pci_conf[addr] = val & 0x08; - break; - - case 0xf5: - dev->pci_conf[addr] = val; - break; - - case 0xf6: - dev->pci_conf[addr] = val; - break; - - case 0xf7: - dev->pci_conf[addr] = val & 0x43; - break; } } @@ -683,35 +617,26 @@ ali1621_reset(void *priv) dev->pci_conf[0x7e] = 0xc7; dev->pci_conf[0x80] = 0x01; dev->pci_conf[0x81] = 0xc0; - - dev->pci_conf[0x89] = 0x20; - dev->pci_conf[0x8a] = 0x20; - dev->pci_conf[0x91] = 0x13; + dev->pci_conf[0x8e] = 0x01; + dev->pci_conf[0xa0] = 0x20; dev->pci_conf[0xb0] = 0x02; - dev->pci_conf[0xb1] = 0xe0; dev->pci_conf[0xb2] = 0x10; dev->pci_conf[0xb4] = 0x03; dev->pci_conf[0xb5] = 0x02; - dev->pci_conf[0xb7] = 0x1c; - dev->pci_conf[0xc8] = 0xbf; - dev->pci_conf[0xc9] = 0x0a; - dev->pci_conf[0xe0] = 0x01; + dev->pci_conf[0xb7] = 0x20; + dev->pci_conf[0xc0] = 0x80; + dev->pci_conf[0xc9] = 0x28; + dev->pci_conf[0xd4] = 0x10; + dev->pci_conf[0xd5] = 0x01; + dev->pci_conf[0xf0] = dev->pci_conf[0xf4] = dev->pci_conf[0xf8] = dev->pci_conf[0xfc] = 0x20; + dev->pci_conf[0xf1] = dev->pci_conf[0xf5] = dev->pci_conf[0xf9] = dev->pci_conf[0xfd] = 0x43; + dev->pci_conf[0xf2] = dev->pci_conf[0xf6] = dev->pci_conf[0xfa] = dev->pci_conf[0xfe] = 0x21; + dev->pci_conf[0xf3] = dev->pci_conf[0xf7] = dev->pci_conf[0xfb] = dev->pci_conf[0xff] = 0x43; - cpu_cache_int_enabled = 1; - ali1621_write(0, 0x42, 0x00, dev); - - ali1621_write(0, 0x54, 0x00, dev); - ali1621_write(0, 0x55, 0x00, dev); + ali1621_write(0, 0x83, 0x08, dev); for (i = 0; i < 4; i++) - ali1621_write(0, 0x56 + i, 0x00, dev); - - ali1621_write(0, 0x60 + i, 0x07, dev); - ali1621_write(0, 0x61 + i, 0x40, dev); - for (i = 0; i < 14; i += 2) { - ali1621_write(0, 0x62 + i, 0x00, dev); - ali1621_write(0, 0x63 + i, 0x00, dev); - } + ali1621_write(0, 0x84 + i, 0x00, dev); } @@ -720,7 +645,9 @@ ali1621_close(void *priv) { ali1621_t *dev = (ali1621_t *)priv; - smram_del(dev->smram); + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); + free(dev); } @@ -733,11 +660,12 @@ ali1621_init(const device_t *info) pci_add_card(PCI_ADD_NORTHBRIDGE, ali1621_read, ali1621_write, dev); - dev->smram = smram_add(); + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); ali1621_reset(dev); - dev->agp_bridge = device_add(&ali5243_agp_device); + device_add(&ali5247_agp_device); return dev; } diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c new file mode 100644 index 000000000..48c84dd87 --- /dev/null +++ b/src/chipset/contaq_82c59x.c @@ -0,0 +1,476 @@ +/* + * 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 Contaq/Cypress 82C596(A) and 597 chipsets. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/smram.h> +#include <86box/chipset.h> + + +#ifdef ENABLE_CONTAQ_82C59X_LOG +int contaq_82c59x_do_log = ENABLE_CONTAQ_82C59X_LOG; + +static void +contaq_82c59x_log(const char *fmt, ...) +{ + va_list ap; + + if (contaq_82c59x_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define contaq_82c59x_log(fmt, ...) +#endif + + +typedef struct +{ + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, green, + smi_status_set, + regs[256], smi_status[2]; + + smram_t *smram[2]; +} contaq_82c59x_t; + + +static void +contaq_82c59x_isa_speed_recalc(contaq_82c59x_t *dev) +{ + if (dev->regs[0x1c] & 0x02) + cpu_set_isa_speed(7159091); + else { + /* TODO: ISA clock dividers for 386 and alt. 486. */ + switch (dev->regs[0x10] & 0x03) { + case 0x00: + cpu_set_isa_pci_div(4); + break; + case 0x01: + cpu_set_isa_pci_div(6); + break; + case 0x02: + cpu_set_isa_pci_div(8); + break; + case 0x04: + cpu_set_isa_pci_div(5); + break; + } + } +} + + +static void +contaq_82c59x_shadow_recalc(contaq_82c59x_t *dev) +{ + uint32_t i, base; + uint8_t bit; + + shadowbios = shadowbios_write = 0; + + /* F0000-FFFFF */ + if (dev->regs[0x15] & 0x80) { + shadowbios |= 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + } else { + shadowbios_write |= 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + /* C0000-CFFFF */ + if (dev->regs[0x15] & 0x01) + mem_set_mem_state_both(0xc0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x15] & bit) { + if (dev->regs[0x15] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + if (dev->green) { + /* D0000-DFFFF */ + if (dev->regs[0x6e] & 0x01) + mem_set_mem_state_both(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xd0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x6e] & bit) { + if (dev->regs[0x6e] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + /* E0000-EFFFF */ + if (dev->regs[0x6f] & 0x01) + mem_set_mem_state_both(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xe0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x6f] & bit) { + shadowbios |= 1; + if (dev->regs[0x6f] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else { + shadowbios_write |= 1; + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + } +} + + +static void +contaq_82c59x_smram_recalc(contaq_82c59x_t *dev) +{ + smram_disable(dev->smram[1]); + + if (dev->regs[0x70] & 0x04) + smram_enable(dev->smram[1], 0x00040000, 0x000a0000, 0x00020000, 1, 1); +} + + +static void +contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; + break; + + case 0x23: + contaq_82c59x_log("Contaq 82C59x: dev->regs[%02x] = %02x\n", dev->index, val); + + if ((dev->index >= 0x60) && !dev->green) + return; + + switch (dev->index) { + /* Registers common to 82C596(A) and 82C597. */ + case 0x10: + dev->regs[dev->index] = val; + contaq_82c59x_isa_speed_recalc(dev); + break; + + case 0x11: + dev->regs[dev->index] = val; + cpu_cache_int_enabled = !!(val & 0x01); + cpu_update_waitstates(); + break; + + case 0x12: + dev->regs[dev->index] = val; + break; + + case 0x13: + dev->regs[dev->index] = val; + break; + + case 0x14: + dev->regs[dev->index] = val; + reset_on_hlt = !!(val & 0x80); + break; + + case 0x15: + dev->regs[dev->index] = val; + contaq_82c59x_shadow_recalc(dev); + break; + + case 0x16: + dev->regs[dev->index] = val; + break; + + case 0x17: + dev->regs[dev->index] = val; + break; + + case 0x18: + dev->regs[dev->index] = val; + break; + + case 0x19: + dev->regs[dev->index] = val; + break; + + case 0x1a: + dev->regs[dev->index] = val; + break; + + case 0x1b: + dev->regs[dev->index] = val; + break; + + case 0x1c: + /* TODO: What's NPRST (generated if bit 3 is set)? */ + dev->regs[dev->index] = val; + contaq_82c59x_isa_speed_recalc(dev); + break; + + case 0x1d: + dev->regs[dev->index] = val; + break; + + case 0x1e: + dev->regs[dev->index] = val; + break; + + case 0x1f: + dev->regs[dev->index] = val; + break; + + /* Green (82C597-specific) registers. */ + case 0x60: + dev->regs[dev->index] = val; + break; + + case 0x61: + dev->regs[dev->index] = val; + break; + + case 0x62: + dev->regs[dev->index] = val; + break; + + case 0x63: + dev->regs[dev->index] = val; + break; + + case 0x64: + dev->regs[dev->index] = val; + if (val & 0x80) { + if (dev->regs[0x65] & 0x80) + smi_line = 1; + dev->smi_status[0] |= 0x10; + } + break; + + case 0x65: + dev->regs[dev->index] = val; + break; + + case 0x66: + dev->regs[dev->index] = val; + break; + + case 0x67: + dev->regs[dev->index] = val; + break; + + case 0x68: + dev->regs[dev->index] = val; + break; + + case 0x69: + dev->regs[dev->index] = val; + break; + + case 0x6a: + dev->regs[dev->index] = val; + dev->smi_status_set = !!(val & 0x80); + break; + + case 0x6b: + dev->regs[dev->index] = val; + break; + + case 0x6c: + dev->regs[dev->index] = val; + break; + + case 0x6d: + dev->regs[dev->index] = val; + break; + + case 0x6e: case 0x6f: + dev->regs[dev->index] = val; + contaq_82c59x_shadow_recalc(dev); + break; + + case 0x70: + dev->regs[dev->index] = val; + contaq_82c59x_smram_recalc(dev); + break; + + case 0x71: + dev->regs[dev->index] = val; + break; + + case 0x72: + dev->regs[dev->index] = val; + break; + + case 0x73: + dev->regs[dev->index] = val; + break; + + case 0x74: + dev->regs[dev->index] = val; + break; + + case 0x75: + dev->regs[dev->index] = val; + break; + + case 0x76: + dev->regs[dev->index] = val; + break; + + case 0x77: + dev->regs[dev->index] = val; + break; + + case 0x78: + dev->regs[dev->index] = val; + break; + + case 0x79: + dev->regs[dev->index] = val; + break; + + case 0x7b: + dev->regs[dev->index] = val; + break; + + case 0x7c: + dev->regs[dev->index] = val; + break; + } + break; + } +} + + +static uint8_t +contaq_82c59x_read(uint16_t addr, void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x23) { + if (dev->index == 0x6a) { + ret = dev->smi_status[dev->smi_status_set]; + /* I assume it's cleared on read. */ + dev->smi_status[dev->smi_status_set] = 0x00; + } else + ret = dev->regs[dev->index]; + } + + return ret; +} + + +static void +contaq_82c59x_close(void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + + free(dev); +} + + +static void * +contaq_82c59x_init(const device_t *info) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)malloc(sizeof(contaq_82c59x_t)); + memset(dev, 0x00, sizeof(contaq_82c59x_t)); + + dev->green = info->local; + + io_sethandler(0x0022, 0x0002, contaq_82c59x_read, NULL, NULL, contaq_82c59x_write, NULL, NULL, dev); + + contaq_82c59x_isa_speed_recalc(dev); + + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + + reset_on_hlt = 0; + + contaq_82c59x_shadow_recalc(dev); + + if (dev->green) { + /* SMRAM 0: Fixed A0000-BFFFF to A0000-BFFFF DRAM. */ + dev->smram[0] = smram_add(); + smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x00020000, 0, 1); + + /* SMRAM 1: Optional. */ + dev->smram[1] = smram_add(); + contaq_82c59x_smram_recalc(dev); + } + + return dev; +} + + +const device_t contaq_82c596a_device = { + "Contaq 82C596A", + 0, + 0, + contaq_82c59x_init, + contaq_82c59x_close, + NULL, + { NULL }, + NULL, + NULL, + NULL +}; + + +const device_t contaq_82c597_device = { + "Contaq 82C597", + 0, + 1, + contaq_82c59x_init, + contaq_82c59x_close, + NULL, + { NULL }, + NULL, + NULL, + NULL +}; diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 86ebeabb2..6140e8e2d 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(dev OBJECT bugger.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c - postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c + postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 3a28e2a1f..b6988232b 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -232,6 +232,9 @@ lm75_init(const device_t *info) hwm_values.temperatures[dev->local >> 8] = 30; dev->values = &hwm_values; + dev->i2c_addr = dev->local & 0x7f; + dev->i2c_enabled = 1; + lm75_reset(dev); return dev; diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index e93989afe..9df3c4b6d 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -37,6 +37,7 @@ #define LM78_AS99127F_REV1 0x040000 #define LM78_AS99127F_REV2 0x080000 #define LM78_W83782D 0x100000 +#define LM78_P5A 0x200000 #define LM78_AS99127F (LM78_AS99127F_REV1 | LM78_AS99127F_REV2) /* special mask covering both _REV1 and _REV2 */ #define LM78_WINBOND (LM78_W83781D | LM78_AS99127F | LM78_W83782D) /* special mask covering all Winbond variants */ #define LM78_WINBOND_VENDOR_ID ((dev->local & LM78_AS99127F_REV1) ? 0x12c3 : 0x5ca3) @@ -258,8 +259,13 @@ lm78_reset(void *priv) dev->regs[0x46] = 0x40; dev->regs[0x47] = 0x50; if (dev->local & LM78_I2C) { - if (!initialization) /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */ - dev->i2c_addr = 0x2d; + if (!initialization) { /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */ + if (dev->local & LM78_P5A) + dev->i2c_addr = 0x77; + else + dev->i2c_addr = 0x2d; + dev->i2c_enabled = 1; + } dev->regs[0x48] = dev->i2c_addr; if (dev->local & LM78_WINBOND) dev->regs[0x4a] = 0x01; @@ -797,6 +803,17 @@ const device_t w83781d_device = { }; +/* Winbond W83781D on ISA and SMBus. */ +const device_t w83781d_p5a_device = { + "Winbond W83781D Hardware Monitor (ASUS P5A)", + DEVICE_ISA, + 0x290 | LM78_I2C | LM78_W83781D | LM78_P5A, + lm78_init, lm78_close, lm78_reset, + { NULL }, NULL, NULL, + NULL +}; + + /* The AS99127F is an ASIC manufactured by Holtek for ASUS, containing an I2C-only W83781D clone with additional voltages, GPIOs and fan control. */ const device_t as99127f_device = { diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 8e1353cc1..3980f8df6 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -34,6 +34,7 @@ #define PCI_BRIDGE_DEC_21150 0x10110022 #define AGP_BRIDGE_ALI_M5243 0x10b95243 +#define AGP_BRIDGE_ALI_M5247 0x10b95247 #define AGP_BRIDGE_INTEL_440LX 0x80867181 #define AGP_BRIDGE_INTEL_440BX 0x80867191 #define AGP_BRIDGE_INTEL_440GX 0x808671a1 @@ -98,6 +99,9 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (func > 0) return; + if ((dev->local == AGP_BRIDGE_ALI_M5247) && (addr >= 0x40)) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x09: case 0x0a: @@ -112,8 +116,10 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (AGP_BRIDGE_INTEL(dev->local)) { if (dev->local == AGP_BRIDGE_INTEL_440BX) val &= 0x1f; - } else if (AGP_BRIDGE_ALI(dev->local)) + } else if (dev->local == AGP_BRIDGE_ALI_M5243) val |= 0x02; + else if (dev->local == AGP_BRIDGE_ALI_M5247) + val &= 0xc3; else val &= 0x67; break; @@ -130,8 +136,10 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x07: if (dev->local == AGP_BRIDGE_INTEL_440LX) dev->regs[addr] &= ~(val & 0x40); - else if (AGP_BRIDGE_ALI(dev->local)) + else if (dev->local == AGP_BRIDGE_ALI_M5243) dev->regs[addr] &= ~(val & 0xf8); + else if (dev->local == AGP_BRIDGE_ALI_M5247) + dev->regs[addr] &= ~(val & 0xc0); return; case 0x0c: case 0x18: @@ -179,6 +187,10 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x3e: if (AGP_BRIDGE_VIA(dev->local)) val &= 0x0c; + else if (dev->local == AGP_BRIDGE_ALI_M5247) + val &= 0x0f; + else if (dev->local == AGP_BRIDGE_ALI_M5243) + return; else if (AGP_BRIDGE(dev->local)) { if ((dev->local == AGP_BRIDGE_INTEL_440BX) || (dev->local == AGP_BRIDGE_INTEL_440GX)) @@ -194,7 +206,9 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (dev->local == AGP_BRIDGE_INTEL_440LX) { dev->regs[addr] = ((dev->regs[addr] & 0x04) | (val & 0x02)) & ~(val & 0x04); return; - } else if (AGP_BRIDGE_ALI(dev->local)) + } else if (dev->local == AGP_BRIDGE_ALI_M5247) + return; + else if (dev->local == AGP_BRIDGE_ALI_M5243) val &= 0x06; else if (AGP_BRIDGE(dev->local)) return; @@ -380,6 +394,11 @@ pci_bridge_reset(void *priv) pci_remap_bus(dev->bus_index, 0x01); break; + case AGP_BRIDGE_ALI_M5247: + dev->regs[0x04] = 0x03; + dev->regs[0x08] = 0x01; + break; + case AGP_BRIDGE_INTEL_440LX: dev->regs[0x06] = 0xa0; dev->regs[0x07] = 0x02; @@ -395,7 +414,7 @@ pci_bridge_reset(void *priv) case AGP_BRIDGE_VIA_597: case AGP_BRIDGE_VIA_598: case AGP_BRIDGE_VIA_691: - case AGP_BRIDGE_VIA_8601: + case AGP_BRIDGE_VIA_8601: dev->regs[0x04] = 0x07; dev->regs[0x06] = 0x20; dev->regs[0x07] = 0x02; @@ -413,7 +432,9 @@ pci_bridge_reset(void *priv) else dev->regs[0x1c] = dev->regs[0x1d] = 0x01; - if (!AGP_BRIDGE_VIA(dev->local)) { + if (dev->local == AGP_BRIDGE_ALI_M5247) + dev->regs[0x1e] = 0x20; + else if (!AGP_BRIDGE_VIA(dev->local)) { dev->regs[0x1e] = AGP_BRIDGE(dev->local) ? 0xa0 : 0x80; dev->regs[0x1f] = 0x02; } @@ -507,6 +528,21 @@ const device_t ali5243_agp_device = NULL }; +/* AGP bridges */ +const device_t ali5247_agp_device = +{ + "ALi M5247 AGP Bridge", + DEVICE_PCI, + AGP_BRIDGE_ALI_M5247, + pci_bridge_init, + NULL, + pci_bridge_reset, + { NULL }, + NULL, + NULL, + NULL +}; + const device_t i440lx_agp_device = { "Intel 82443LX/EX AGP Bridge", diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index 32cc0a22e..5b112a1a5 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -103,7 +103,7 @@ smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv) dev->next_stat = 0x04; switch (addr - dev->io_base) { case 0x00: - dev->stat &= ~(val & 0xe2); + dev->stat &= ~(val & 0xf2); /* Make sure IDLE is set if we're not busy or errored. */ if (dev->stat == 0x00) dev->stat = 0x04; @@ -139,7 +139,7 @@ smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv) /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */ if (!i2c_start(i2c_smbus, smbus_addr, read)) { - dev->next_stat = 0x20; + dev->next_stat = 0x40; break; } diff --git a/src/device/vpc2007.c b/src/device/vpc2007.c deleted file mode 100644 index 4caf77fbb..000000000 --- a/src/device/vpc2007.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 f52168777..c94205277 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -29,6 +29,7 @@ extern const device_t ali1531_device; extern const device_t ali1541_device; extern const device_t ali1543_device; extern const device_t ali1543c_device; +extern const device_t ali1621_device; #if defined(DEV_BRANCH) && defined(USE_M6117) extern const device_t ali6117d_device; #endif @@ -36,6 +37,10 @@ extern const device_t ali6117d_device; /* AMD */ extern const device_t amd640_device; +/* Contaq/Cypress */ +extern const device_t contaq_82c596a_device; +extern const device_t contaq_82c597_device; + /* C&T */ extern const device_t neat_device; extern const device_t scat_device; diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index e4613f05b..ef5621da6 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -64,6 +64,7 @@ extern const device_t lm75_w83781d_device; extern const device_t lm78_device; extern const device_t w83781d_device; +extern const device_t w83781d_p5a_device; extern const device_t as99127f_device; extern const device_t as99127f_rev2_device; extern const device_t w83782d_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b3e9b66d5..b4b7b6037 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -340,6 +340,7 @@ extern int machine_at_dtk486_init(const machine_t *); extern int machine_at_px471_init(const machine_t *); extern int machine_at_win471_init(const machine_t *); extern int machine_at_vi15g_init(const machine_t *); +extern int machine_at_green_b_init(const machine_t *); extern int machine_at_r418_init(const machine_t *); extern int machine_at_ls486e_init(const machine_t *); @@ -497,8 +498,10 @@ extern int machine_at_m560_init(const machine_t *); extern int machine_at_ms5164_init(const machine_t *); /* m_at_sockets7.c */ +extern int machine_at_p5a_init(const machine_t *); extern int machine_at_m579_init(const machine_t *); extern int machine_at_ga_5aa_init(const machine_t *); +extern int machine_at_ga_5ax_init(const machine_t *); extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); @@ -522,6 +525,8 @@ extern void machine_at_p65up5_common_init(const machine_t *, const device_t *nor extern int machine_at_p65up5_cp6nd_init(const machine_t *); /* m_at_slot1.c */ +extern int machine_at_m729_init(const machine_t *); + extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 700c92981..2bd76eb30 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -64,6 +64,15 @@ #define ACCESS_READ 1 #define ACCESS_WRITE 2 +#define ACCESS_SMRAM_OFF 0 +#define ACCESS_SMRAM_X 1 +#define ACCESS_SMRAM_W 2 +#define ACCESS_SMRAM_WX 3 +#define ACCESS_SMRAM_R 4 +#define ACCESS_SMRAM_RX 5 +#define ACCESS_SMRAM_RW 6 +#define ACCESS_SMRAM_RWX 7 + /* Conversion #define's - we need these to seamlessly convert the old mem_set_mem_state() calls to the new stuff in order to make this a drop in replacement. @@ -81,6 +90,8 @@ #define MEM_READ_EXTERNAL_EX 0 #define MEM_READ_SMRAM (ACCESS_X_SMRAM | ACCESS_R_SMRAM) #define MEM_READ_SMRAM_EX (ACCESS_X_SMRAM) +#define MEM_EXEC_SMRAM MEM_READ_SMRAM_EX +#define MEM_READ_SMRAM_2 (ACCESS_R_SMRAM) /* Theese two are going to be identical. */ #define MEM_READ_DISABLED_EX MEM_READ_DISABLED #define MEM_READ_MASK 0x7c1f diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 0041855e4..4ca5d94c4 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -130,6 +130,7 @@ extern void pci_bridge_set_ctl(void *priv, uint8_t ctl); extern const device_t dec21150_device; extern const device_t ali5243_agp_device; +extern const device_t ali5247_agp_device; extern const device_t i440lx_agp_device; extern const device_t i440bx_agp_device; extern const device_t i440gx_agp_device; diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index db283cc87..81216a6f6 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -107,6 +107,7 @@ typedef struct { extern void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size); extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max); #endif /*EMU_SPD_H*/ diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 93d5d9499..4497b1b97 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -697,7 +697,7 @@ machine_at_sis_85c471_common_init(const machine_t *model) machine_at_common_init(model); if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); device_add(&sis_85c471_device); } @@ -817,6 +817,30 @@ machine_at_vi15g_init(const machine_t *model) } +int +machine_at_green_b_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/green-b/4gpv31-ami-1993-8273517.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&contaq_82c597_device); + + device_add(&keyboard_at_ami_device); + + return ret; +} + + static void machine_at_sis_85c496_common_init(const machine_t *model) { diff --git a/src/machine/m_at_misc.c b/src/machine/m_at_misc.c index aff270d95..e8e6c96b5 100644 --- a/src/machine/m_at_misc.c +++ b/src/machine/m_at_misc.c @@ -68,7 +68,6 @@ machine_at_vpc2007_init(const machine_t *model) device_add(&w83977f_370_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; diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index e57e315dd..9ed1f3ccb 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -690,3 +690,36 @@ machine_at_ms6168_init(const machine_t *model) return ret; } + + +int +machine_at_m729_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m729/M729NEW.BIN", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1621_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index e51fda097..47ee28a29 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -40,6 +40,44 @@ #include <86box/video.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/clock.h> + + +int +machine_at_p5a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5a/1011.005", + 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&w83781d_p5a_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + + return ret; +} int @@ -108,6 +146,41 @@ machine_at_ga_5aa_init(const machine_t *model) } +int +machine_at_ga_5ax_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ga-5ax/5AX.F4", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + int machine_at_ax59pro_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f80d66334..f44ca808f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -370,6 +370,8 @@ const machine_t machines[] = { /* 486 machines - Socket 3 */ /* 486 machines with just the ISA slot */ + /* Has AMI MegaKey KBC firmware. */ + { "[Contaq 82C597] Green-B", "green-b", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_green_b_init, NULL }, /* Has a VIA VT82C42N KBC. */ { "[OPTi 895] Jetway J-403TG", "403tg", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_init, NULL }, /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ @@ -668,10 +670,15 @@ const machine_t machines[] = { /* Super Socket 7 machines */ /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN V] ASUS P5A", "p5a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_p5a_init, NULL }, /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge with on-chip KBC. */ { "[ALi ALADDiN V] PC Chips M579", "m579", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m579_init, NULL }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ { "[ALi ALADDiN V] Gigabyte GA-5AA", "ga-5aa", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5aa_init, NULL }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN V] Gigabyte GA-5AX", "ga-5ax", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5ax_init, NULL }, /* Apollo MVP3 */ /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA @@ -716,6 +723,10 @@ const machine_t machines[] = { { "[i440FX] PC Partner MB600N", "mb600n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_mb600n_init, NULL }, /* Slot 1 machines */ + /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN-PRO II] PC Chips M729", "m729", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m729_init, NULL }, + /* 440FX */ /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-PKND)", "p65up5_cpknd", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cpknd_init, NULL }, diff --git a/src/mem/mem.c b/src/mem/mem.c index 79e27f011..225fafcbd 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2493,6 +2493,7 @@ mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t uint16_t mask, smstate = 0x0000; const uint16_t smstates[4] = { 0x0000, (MEM_READ_SMRAM | MEM_WRITE_SMRAM), MEM_READ_SMRAM_EX, (MEM_READ_DISABLED_EX | MEM_WRITE_DISABLED_EX) }; + int i; if (mode) @@ -2504,7 +2505,15 @@ mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t if (mode == 1) access = !!access; - smstate = smstates[access & 0x03]; + if (mode == 3) { + if (access & ACCESS_SMRAM_X) + smstate |= MEM_EXEC_SMRAM; + if (access & ACCESS_SMRAM_R) + smstate |= MEM_READ_SMRAM_2; + if (access & ACCESS_SMRAM_W) + smstate |= MEM_WRITE_SMRAM; + } else + smstate = smstates[access & 0x07]; } else smstate = access & 0x6f7b; diff --git a/src/mem/spd.c b/src/mem/spd.c index 74346417b..8e79833ad 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -384,19 +384,15 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit } +/* Used by ALi M1531 and M1541/2. */ void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) { - uint8_t row, dimm, drb, apollo = 0; + uint8_t row, dimm; + uint8_t drb; uint16_t size, size_acc; uint16_t rows[SPD_MAX_SLOTS]; - /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ - if (reg_max < reg_min) { - apollo = reg_max; - reg_max = reg_min + 7; - } - /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ if (!spd_present) { dimm = ((reg_max - reg_min) + 1) >> 2; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ @@ -424,8 +420,6 @@ spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint /* Determine the DRB register to write. */ drb = reg_min + row; - if (apollo && ((drb & 0xf) < 0xa)) - drb = apollo + (drb & 0xf); /* Calculate previous and new size. */ if (row == 0) @@ -442,6 +436,81 @@ spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint } +/* This is needed because the ALi M1621 does this stuff completely differently, + as it has DRAM bank registers instead of DRAM row boundary registers. */ +void +spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max) +{ + uint8_t dimm, drb; + uint16_t size; + uint16_t rows[SPD_MAX_SLOTS]; + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 2; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, 4, 1 << (log2i((machines[machine].max_ram >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (dimm = 0; dimm <= ((reg_max - reg_min) >> 2); dimm++) { + size = 0; + drb = reg_min + (dimm << 2); + + regs[drb] = 0xff; + regs[drb + 1] = 0xff; + regs[drb + 2] = 0x00; + regs[drb + 3] = 0xf0; + + if (spd_modules[dimm] == NULL) + continue; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + size = (spd_modules[dimm]->row1 + spd_modules[dimm]->row2) >> 1; + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + if (spd_modules[dimm]->row1) + regs[drb + 3] |= 0x06; + + switch (size) { + case 4: + default: + regs[drb + 2] = 0x00; + break; + case 8: + regs[drb + 2] = 0x10; + break; + case 16: + regs[drb + 2] = 0x20; + break; + case 32: + regs[drb + 2] = 0x30; + break; + case 64: + regs[drb + 2] = 0x40; + break; + case 128: + regs[drb + 2] = 0x50; + break; + case 256: + regs[drb + 2] = 0x60; + break; + } + + if (spd_modules[dimm]->row2) { + regs[drb + 3] |= 0x01; + regs[drb + 2] |= 0x80; + } + + spd_log("SPD: DIMM %i: %02X %02X %02X %02X\n", regs[drb], regs[drb + 1], regs[drb + 2], regs[drb + 3]); + } +} + + static const device_t spd_device = { "Serial Presence Detect ROMs", DEVICE_ISA, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index c67fa66f6..10fde74f7 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -600,8 +600,9 @@ CPUOBJ := cpu.o cpu_table.o fpu.o x86.o \ $(DYNARECOBJ) CHIPSETOBJ := acc2168.o \ + contaq_82c59x.o \ cs4031.o cs8230.o \ - ali1217.o ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o \ + ali1217.o ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o \ gc100.o headland.o \ intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o \ @@ -633,7 +634,7 @@ MCHOBJ := machine.o machine_table.o \ ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ - vpc2007.o clock_ics9xxx.o isapnp.o \ + clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o kbc_at.o kbd_at.o \ @@ -644,7 +645,7 @@ DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c68 else DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ - vpc2007.o clock_ics9xxx.o isapnp.o \ + clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ From 6aeeba135173b19033c01b1ab9813a19b4fecd81 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 13 Jul 2021 05:24:52 +0200 Subject: [PATCH 019/140] The Contaq chipsets now close SMRAM on close. --- src/chipset/contaq_82c59x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 48c84dd87..19a3d5b44 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -411,6 +411,9 @@ contaq_82c59x_close(void *priv) { contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); + free(dev); } From 36bb5847630c448c1b1c5e5fd4f8ec3f5f6f0d32 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 06:55:35 +0200 Subject: [PATCH 020/140] Preparation for bringing it up to par with master. --- src/win/Makefile.mingw | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 10fde74f7..42b3fbbbc 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -632,7 +632,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_misc.o ifeq ($(NEW_KBC), y) -DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ @@ -643,7 +643,7 @@ DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c68 mouse_serial.o mouse_ps2.o \ phoenix_486_jumper.o else -DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ From 15cc6cc12cf9ec7a2b312c3df6ee52455797ee0b Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 06:56:36 +0200 Subject: [PATCH 021/140] And one more. --- src/win/Makefile.mingw | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 42b3fbbbc..4390235a9 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -631,7 +631,6 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o -ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ From 4a6c064d0f59491cd2ca336e4d9ebcae8ae8c2c7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 06:57:51 +0200 Subject: [PATCH 022/140] Temporary revert of keyboard_at.c. --- src/device/keyboard_at.c | 2785 ++++++++++++++------------------------ 1 file changed, 1039 insertions(+), 1746 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 92690db1f..581f55f30 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,7 +57,9 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define RESET_DELAY_TIME 1000 /* 100 ms */ +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + +#define RESET_DELAY_TIME (100 * 10) /* 600ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -72,136 +74,49 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ -/* This only differs in that translation is forced off. */ -#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x07 +#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ +#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x03 -#define KBC_FLAG_PS2 0x04 - -/* We need to redefine this: - Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 - for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling - controller mode, normally set according to the flags, but togglable on - AMIKey: - 0000 0000 0x00 IBM, AT - 0000 0001 0x01 MR - 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 - 0001 0000 0x10 Olivetti - 0010 0000 0x20 Toshiba - 0011 0000 0x30 Quadtel - 0100 0000 0x40 Phoenix MultiKey/42 - 0101 0000 0x50 AMI KF - 0101 0001 0x51 AMI KH - 0101 0010 0x52 AMIKey - 0101 0011 0x53 AMIKey-2 - 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) - 0110 0000 0x60 Award - 0110 0001 0x61 Award 286 (has some AMI commands apparently) - 0111 0000 0x70 Siemens -*/ - -/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -/* All commands are standard PS/2 */ +#define KBC_VEN_AMI 0x04 #define KBC_VEN_IBM_MCA 0x08 -/* Standard IBM commands, differs in input port bits */ -#define KBC_VEN_IBM_PS1 0x10 -/* Olivetti - proprietary commands and port 62h with switches - readout */ -#define KBC_VEN_OLIVETTI 0x20 -/* Toshiba T3100e - has a bunch of proprietary commands, also sets - IFULL on command AA */ -#define KBC_VEN_TOSHIBA 0x28 -/* Standard IBM commands, uses input port as a switches readout */ -#define KBC_VEN_NCR 0x30 -/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the - polarity of the video type bit in the input port is inverted */ -#define KBC_VEN_XI8088 0x38 -/* QuadtelKey - currently guesswork */ -#define KBC_VEN_QUADTEL 0x40 -/* Phoenix MultiKey/42 - not yet implemented */ -#define KBC_VEN_PHOENIX 0x48 -/* Generic commands, XI8088-like input port handling of video type, - maybe we just need a flag for that? */ -#define KBC_VEN_ACER 0x50 -/* AMI KF/KH/AMIKey/AMIKey-2 */ -#define KBC_VEN_AMI 0xf0 -/* Standard AMI commands, differs in input port bits */ -#define KBC_VEN_INTEL_AMI 0xf8 -#define KBC_VEN_MASK 0xf8 - - -/* Flags should be fully 32-bit: - Bits 7- 0: Vendor and revision/variant; - Bits 15- 8: Input port mask; - Bits 23-16: Input port bits that are always on; - Bits 31-24: Flags: - Bit 0: Invert P1 video type bit polarity; - Bit 1: Is PS/2; - Bit 2: Translation forced always off. - - So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ +#define KBC_VEN_QUADTEL 0x0c +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_XI8088 0x14 +#define KBC_VEN_IBM_PS1 0x18 +#define KBC_VEN_ACER 0x1c +#define KBC_VEN_INTEL_AMI 0x20 +#define KBC_VEN_OLIVETTI 0x24 +#define KBC_VEN_NCR 0x28 +#define KBC_VEN_SAMSUNG 0x2c +#define KBC_VEN_MASK 0x3c typedef struct { - uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, - secr_phase, mem_index, ami_stat, ami_mode, - kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, - kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, - kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, - mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, - kbc_written[3], kbc_data[3]; + uint8_t command, status, old_status, out, old_out, secr_phase, + mem_addr, input_port, output_port, old_output_port, + key_command, output_locked, ami_stat, want60, + wantirq, key_wantdata, refresh, first_write; - uint8_t mem_int[0x40], mem[0x240]; + uint8_t mem[0x100]; - uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; + int last_irq, old_last_irq, + reset_delay, + out_new, out_delayed; uint32_t flags; - pc_timer_t pulse_cb, send_delay_timer; + pc_timer_t refresh_time, pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); + + pc_timer_t send_delay_timer; } atkbd_t; -enum -{ - CHANNEL_KBC = 0, - CHANNEL_KBD, - CHANNEL_MOUSE -}; - -enum -{ - KBD_MAIN_LOOP = 0, - KBD_CMD_PROCESS -}; - -enum -{ - MOUSE_MAIN_LOOP_1 = 0, - MOUSE_CMD_PROCESS, - MOUSE_CMD_END, - MOUSE_MAIN_LOOP_2 -}; - -enum { - KBC_MAIN_LOOP = 0, - KBC_RESET = 1, - KBC_WAIT = 4, - KBC_WAIT_FOR_KBD, - KBC_WAIT_FOR_MOUSE, - KBC_WAIT_FOR_BOTH -}; - - -static void kbd_cmd_process(atkbd_t *dev); - -static void kbc_wait(atkbd_t *dev, uint8_t flags); - - /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -210,9 +125,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; -uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; - +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -653,27 +568,9 @@ static const scancode scancode_set3[512] = { }; -#define UISTR_LEN 256 -static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); -extern void ui_sb_bugui(char *__str); - - -static void -kbd_status(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsprintf(kbd_str, fmt, ap); - ui_sb_bugui(kbd_str); - va_end(ap); -} - - -// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -734,6 +631,9 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); + } else { + key_ctrl_queue_start = key_ctrl_queue_end = 0; + memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -741,6 +641,15 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + dev->status = (dev->status & 0x0f) | stat_hi; + if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -749,1042 +658,83 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else - fatal("Adding %02X to invalid channel %02X\n", val, channel); + } else { + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + } +} + + +static void +add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + kbd_log("ATkbc: Adding %02X to front...\n", val); + dev->wantirq = 0; + if (channel == 2) { + if (dev->mem[0] & 0x02) + picint(0x1000); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + dev->last_irq = 2; + } + dev->out = val; + if (channel == 2) + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; + else + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); return; } - - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } -static void -kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) -{ - dev->kbc_written[channel] = 1; - dev->kbc_data[channel] = val; -} - static void -kbd_send_to_host(atkbd_t *dev, uint8_t val) +add_data_kbd_direct(atkbd_t *dev, uint8_t val) { - kbc_send(dev, val, CHANNEL_KBD); -} + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); + uint8_t send; - -static void -kbd_chip_reset(atkbd_t *dev) -{ - kbc_queue_reset(1); - dev->kbc_written[1] = 0x00; - kbd_last_scan_code = 0x00; - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->kbd_phase = 0; - dev->kbd_in = 0; -} - - -static void -kbd_command(atkbd_t *dev) -{ - uint8_t val = dev->kbd_data; - - if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { - dev->kbd_phase++; - if (dev->kbd_phase == RESET_DELAY_TIME) { - kbd_send_to_host(dev, 0xaa); - dev->kbd_phase = 0; - dev->kbd_cmd = 0x00; - } - return; - } - - if (dev->kbd_phase == 2) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf2: - kbd_send_to_host(dev, 0x83); - break; - default: - fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } else if (dev->kbd_phase == 1) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf0: - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - kbd_send_to_host(dev, keyboard_mode & 3); - break; - case 0xf2: - kbd_send_to_host(dev, 0xab); - dev->kbd_phase = 2; - break; - default: - fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } - - if (dev->kbd_in && (val < 0xed)) { - dev->kbd_in = 0; - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set LEDs [%02x]\n", val); - kbd_send_to_host(dev, 0xfa); - break; - - case 0xf0: /* get/set scancode set */ - kbd_send_to_host(dev, 0xfa); - if (val == 0) - dev->kbd_phase = 1; - else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_send_to_host(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); - kbd_send_to_host(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - } else { - /* No keyboard command in progress. */ - dev->kbd_in = 0; - dev->kbd_cmd = 0x00; - dev->kbd_phase = 0; - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - kbd_send_to_host(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - kbd_send_to_host(dev, 0xfe); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - kbd_send_to_host(dev, 0xfa); - - dev->kbd_in = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - kbd_send_to_host(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", - val, keyboard_scan, dev->mem[0x20]); - kbd_send_to_host(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - kbd_send_to_host(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbd_chip_reset(dev); - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - kbd_send_to_host(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) - dev->kbd_cmd = val; - } -} - - -static void -kbd_do_command(atkbd_t *dev) -{ - kbd_command(dev); - if (dev->kbd_written) - dev->kbd_poll_phase = KBD_CMD_PROCESS; - else if ((dev->kbd_phase == 0) && !dev->kbd_in) { - dev->kbd_in_cmd = 0; - if (dev->kbd_data != 0xf5) - keyboard_scan = 1; - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else { - keyboard_scan = 0; - dev->kbd_in_cmd = 1; - dev->kbd_poll_phase = KBD_CMD_PROCESS; - } -} - - -static void -kbd_nack(atkbd_t *dev) -{ - kbd_send_to_host(dev, 0xfe); - dev->kbd_poll_phase = KBD_MAIN_LOOP; -} - - -static void -kbd_main_loop(atkbd_t *dev) -{ - uint8_t scan = !dev->kbd_inhibit && keyboard_scan; - - if (dev->kbd_written) { - dev->kbd_written = 0; - kbd_cmd_process(dev); - } else if (scan && (key_queue_start != key_queue_end)) { - /* Scan here. */ - kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); - kbd_send_to_host(dev, key_queue[key_queue_start]); - key_queue_start = (key_queue_start + 1) & 0xf; - } -} - - -static void -kbd_cmd_process(atkbd_t *dev) -{ - uint8_t written = dev->kbd_written; - - /* We want data, nothing has been written yet, return. */ - if (dev->kbd_in && !dev->kbd_written) + if (dev->reset_delay) return; - dev->kbd_written = 0; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { - kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); - kbd_do_command(dev); - } else if (dev->kbd_data == 0xfe) { - kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); - kbd_send_to_host(dev, kbd_last_scan_code); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data == 0xee) { - kbd_log("ATkbd: Echo EE\n"); - kbd_send_to_host(dev, 0xee); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data >= 0xed) { - kbd_log("ATkbd: Command %02X\n", dev->kbd_data); - if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { - kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); - keyboard_scan = 1; - dev->kbd_in_cmd = 0; - } - kbd_do_command(dev); - } else { - if (!keyboard_scan && dev->kbd_in_cmd) { - if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { - kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); - kbd_nack(dev); - } else { - kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); - kbd_do_command(dev); - } - } else { - kbd_log("ATkbd: Scanning or not in command, NACK\n"); - kbd_nack(dev); - } - } -} + if (translate) + send = nont_to_t[val]; + else + send = val; - -/* Keyboard processing */ -static void -kbd_process(atkbd_t *dev) -{ - /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ - if (dev->kbc_written[1] && dev->kbd_written) - dev->kbc_written[1] = 0; - - /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ - if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { - case KBD_MAIN_LOOP: - kbd_main_loop(dev); - break; - case KBD_CMD_PROCESS: - kbd_cmd_process(dev); - break; - } + add_data_kbd_queue(dev, 1, send); } static void -kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +add_data_kbd_raw(atkbd_t *dev, uint8_t val) { - uint8_t ch = (channel > 0) ? channel : 1; - uint8_t do_irq = (dev->mem[0x20] & ch); - int translate = (channel == 1) && (keyboard_mode & 0x60); - - if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) - return; - - stat_hi |= dev->inhibit; - - if (!dev->kbc_send_pending) { - dev->kbc_send_pending = 1; - dev->kbc_to_send = val; - dev->kbc_channel = channel; - dev->kbc_stat_hi = stat_hi; - return; - } - - if (translate) { - /* Allow for scan code translation. */ - if (val == 0xf0) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if ((sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - } - - dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; - if (do_irq) { - kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); - picint(dev->last_irq); - } - kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); - dev->ob = translate ? (nont_to_t[val] | sc_or) : val; - - dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); - if (ch == 2) - dev->status |= STAT_MFULL; - - if (translate && (sc_or == 0x80)) - sc_or = 0; -} - - -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); - - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - val |= ((dev->mem[0x20] << 4) & 0x30); - - dev->kbd_inhibit = (val & 0x40); - dev->mouse_inhibit = (val & 0x08); - - if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) { - kbd_log("ATkbc: write_output(): IRQ 12\n"); - picint(1 << 12); - } else - picintc(1 << 12); - } - if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) { - kbd_log("ATkbc: write_output(): IRQ 1\n"); - picint(1 << 1); - } else - picintc(1 << 1); - } - if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->p2 ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->p2 = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) - val &= ~CCB_TRANSLATE; - - dev->mem[0x20] = val; - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { - keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->p2); - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_p2 = dev->p2 & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xef; - dev->mem[0x20] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xdf; - dev->mem[0x20] |= (enable ? 0x00 : 0x20); -} - - -static void -kbc_transmit(atkbd_t *dev, uint8_t val) -{ - kbc_send_to_ob(dev, val, 0, 0x00); -} - - -static void -kbc_command(atkbd_t *dev) -{ - uint8_t mask, val = dev->ib; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - int bad = 1; - - if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { - if (dev-> kbc_phase < 16) - kbc_transmit(dev, dev->mem[dev->kbc_phase]); - else if (dev-> kbc_phase == 16) - kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); - else if (dev-> kbc_phase == 17) - kbc_transmit(dev, dev->p2); - else if (dev-> kbc_phase == 18) - kbc_transmit(dev, dev->status); - - dev->kbc_phase++; - if (dev->kbc_phase == 19) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } - return; - } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { - val = ami_copr[dev->kbc_phase]; - kbc_transmit(dev, val); - if (val == 0x00) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } else - dev->kbc_phase++; - return; - } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { - /* load security */ - kbd_log("ATkbc: load security\n"); - dev->mem[0x50 + dev->kbc_in - 0x01] = val; - if ((dev->kbc_in == 0x80) && (val != 0x00)) { - /* Security string too long, set it to 0x00. */ - dev->mem[0x50] = 0x00; - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else if (val == 0x00) { - /* Security string finished. */ - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else /* Increase pointer and request another byte. */ - dev->kbc_in++; - return; - } - - /* If the written port is 64, go straight to the beginning of the command. */ - if (!(dev->status & STAT_CD) && dev->kbc_in) { - /* Write data to controller. */ - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (dev->kbc_cmd) { - case 0x60 ... 0x7f: - if (dev->kbc_cmd == 0x60) - write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; - break; - - case 0xc7: /* or input port with system data */ - dev->p1 |= val; - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("New AMIKey mode: %02X\n", val); - dev->ami_mode = val; - dev->flags &= ~KBC_FLAG_PS2; - if (val & 1) - dev->flags |= KBC_FLAG_PS2; - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->p2_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->p2 & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - // kbc_send_to_ob(dev, val, 1, 0x00); - /* Should be channel 1, but we send to 0 to avoid translation, - since bytes output using this command do *NOT* get translated. */ - kbc_send_to_ob(dev, val, 0, 0x00); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - kbc_send_to_ob(dev, val, 2, 0x00); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (dev->flags & KBC_FLAG_PS2) { - set_enable_mouse(dev, 1); - dev->mem[0x20] &= ~0x20; - if (mouse_write && !dev->kbc_written[2]) { - kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); - dev->mouse_data = val; - dev->mouse_written = 1; - dev->kbc_wait_for_response = 2; - } else - kbc_send_to_ob(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - -#ifdef ENABLE_KEYBOARD_AT_LOG - if (bad) - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); -#endif - } - } else { - /* Controller command. */ - kbd_log("ATkbc: Controller command: %02X\n", val); - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (val) { - /* Read data from KBC memory. */ - case 0x20 ... 0x3f: - kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); - break; - - /* Write data to KBC memory. */ - case 0x60 ... 0x7f: - dev->kbc_in = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->kbd_in_cmd = dev->mouse_in_cmd = 0; - dev->status &= ~STAT_OFULL; - dev->last_irq = 0; - dev->kbc_phase = 0; - - /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ - if (dev->flags & KBC_FLAG_PS2) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - kbc_transmit(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - /* No error. */ - kbc_transmit(dev, 0x00); - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - kbc_transmit(dev, dev->mem[0x20]); - dev->kbc_phase = 1; - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xc7: /* or input port with system data */ - kbd_log("ATkbc: Phoenix - or input port with system data\n"); - dev->kbc_in = 1; - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - kbc_transmit(dev, dev->ami_mode); - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->kbc_in = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (dev->mem[0x20] & 0x10) - mask &= 0xbf; - if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) - mask &= 0xf7; - kbc_transmit(dev, dev->p2 & mask); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->kbc_in = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - dev->kbc_in = 1; - else - kbc_transmit(dev, 0x00); /* NCR */ - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - kbc_transmit(dev, 0x00); - break; - - case 0xe1: case 0xea: - kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); - write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); - } - - /* If the command needs data, remember the command. */ - if (dev->kbc_in || (dev->kbc_phase > 0)) - dev->kbc_cmd = val; - } -} - - -static void -kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) -{ - dev->kbc_written[channel] = 0; - kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); - kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); -} - - -static void -kbc_main_loop_scan(atkbd_t *dev) -{ - uint8_t port_dis = dev->mem[0x20] & 0x30; - uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); - - if (!ps2) - port_dis |= 0x20; - - if (!(dev->status & STAT_OFULL)) { - if (port_dis & 0x20) { - if (!(port_dis & 0x10)) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); - /* Enable communication with keyboard. */ - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 1); - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); - } -#endif - } else { - /* Enable communication with mouse. */ - dev->p2 &= 0xf7; - dev->mouse_inhibit = 0; - if (dev->mem[0x20] & 0x10) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); - kbc_wait(dev, 2); - } else { - /* Enable communication with keyboard. */ - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 3); - } - } - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - } -#endif -} - - -static void -kbc_process_ib(atkbd_t *dev) -{ - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - } else { - dev->mem[0x20] &= ~0x10; - dev->kbd_data = dev->ib; - dev->kbd_written = 1; - dev->kbc_wait_for_response = 1; - } - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - if (!dev->kbc_wait_for_response) - kbc_main_loop_scan(dev); -} - - -static void -kbc_wait(atkbd_t *dev, uint8_t flags) -{ - if ((flags & 1) && dev->kbc_written[1]) { - /* Disable communication with mouse. */ - dev->p2 |= 0x08; - dev->mouse_inhibit = 1; - /* Send keyboard byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_KBD); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if ((flags & 2) && dev->kbc_written[2]) { - /* Disable communication with keyboard. */ - dev->p2 |= 0x40; - dev->kbd_inhibit = 1; - /* Send mouse byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if (dev->status & STAT_IFULL) { - /* Disable communication with keyboard and mouse. */ - dev->p2 |= 0x48; - dev->kbd_inhibit = dev->mouse_inhibit = 1; - kbc_process_ib(dev); - } else - dev->kbc_poll_phase = KBC_WAIT | flags; -} - - -/* Controller processing */ -static void -kbc_process(atkbd_t *dev) -{ - // kbd_log("ATkbc: kbc_process()\n"); - - /* If we're waiting for the response from the keyboard or mouse, do nothing - until the device has repsonded back. */ - if (dev->kbc_wait_for_response > 0) { - if (dev->kbc_written[dev->kbc_wait_for_response]) - dev->kbc_wait_for_response = 0; - else - return; - } - - if (dev->kbc_send_pending) { - kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", - dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - dev->kbc_send_pending = 0; - } - - if (dev->kbc_poll_phase == KBC_RESET) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Reset loop()\n"); - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } - } - - return; - } - - if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: In a command\n"); - if (!dev->kbc_in && (dev->status & STAT_OFULL)) { - kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); - return; /* We do not want input and we're waiting for the host to read the data - we transmitted, but it has not done that yet, do nothing. */ - } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { - kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); - return; /* We want input and the host has not provided us with any yet, do nothing. */ - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbc: Normal condition\n"); -#endif - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - kbd_log("ATkbc: Resetting command\n"); - dev->kbc_phase = 0; - dev->kbc_in = 0; - } - } - - /* Process command. */ - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - - if (!(dev->status & STAT_OFULL)) - kbc_main_loop_scan(dev); - /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ - } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { - case KBC_MAIN_LOOP: - // kbd_log("ATkbc: Main loop\n"); - if (dev->status & STAT_IFULL) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: IBF full, process\n"); - kbc_process_ib(dev); - } else - kbc_main_loop_scan(dev); - break; - case KBC_WAIT_FOR_KBD: - case KBC_WAIT_FOR_MOUSE: - case KBC_WAIT_FOR_BOTH: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); - kbc_wait(dev, dev->kbc_poll_phase & 3); - break; - default: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); - break; - } + add_data_kbd_queue(dev, 1, val); } @@ -1792,29 +742,105 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; +#ifdef ENABLE_KEYBOARD_AT_LOG + const uint8_t channels[4] = { 1, 2, 0, 0 }; +#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - /* We process all three devices at the same time, in an arbitrary order. */ + if (dev->out_new != -1 && !dev->last_irq) { + dev->wantirq = 0; + if (dev->out_new & 0x100) { + if (dev->mem[0] & 0x02) + picint(0x1000); + kbd_log("ATkbc: %02X coming from channel 2\n"); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; + dev->last_irq = 2; + } + } - /* Keyboard processing */ - kbd_process(dev); + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); + dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { + kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); + dev->out_new = mouse_queue[mouse_queue_start] | 0x100; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { + kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); + dev->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } - /* TODO: Mouse processing */ - // mouse_process(dev); + if (dev->reset_delay) { + dev->reset_delay--; + if (!dev->reset_delay) { + kbd_log("ATkbc: Sending AA on keyboard reset...\n"); + add_data_kbd_direct(dev, 0xaa); + } + } +} - /* Controller processing */ - kbc_process(dev); + +static void +add_data(atkbd_t *dev, uint8_t val) +{ + kbd_log("ATkbc: add to queue\n"); + + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + kbc_queue_add(dev, val, 0, 0x00); + + if (!(dev->out_new & 0x300)) { + dev->out_delayed = dev->out_new; + dev->out_new = -1; + } } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); int i; + uint8_t or = 0; + uint8_t send; - for (i = 0; i < len; i++) - add_data_kbd_queue(dev, 0, val[i]); + if (dev->reset_delay) + return; + + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + + add_data_kbd_queue(dev, 0, send); + } } @@ -1822,21 +848,56 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->kbd_in || (dev->kbd_phase > 0)) + if (dev->reset_delay) return; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && - (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) - t3100e_notify_set((val + 2) & 0x0f); + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && + (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0a); break; /* Up */ + case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ + } + + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1969,7 +1030,18 @@ add_data_kbd(uint16_t val) break; default: - add_data_kbd_queue(dev, 0, val); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); + if (translate) { + kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbd_log("F0 "); + kbd_log("%02X)\n", val); + } else + kbd_log("%02X\n", val); +#endif + + add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); break; } @@ -1978,13 +1050,121 @@ add_data_kbd(uint16_t val) } +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) + val |= ((dev->mem[0] << 4) & 0x10); + + if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->output_port = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); + + if ((val & 1) && (dev->status & STAT_OFULL)) + dev->wantirq = 1; + if (!(val & 1) && dev->wantirq) + dev->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + dev->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || + ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { + keyboard_mode &= ~CCB_PCMODE; + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->output_port); + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_output_port = dev->output_port & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); + write_output(dev, dev->output_port & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); - write_output(dev, dev->p2 | dev->old_p2); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); + write_output(dev, dev->output_port | dev->old_output_port); +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xef; + dev->mem[0] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xdf; + dev->mem[0] |= (enable ? 0x00 : 0x20); } @@ -1993,70 +1173,49 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + switch (val) { case 0xa4: /* check if password installed */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: check if password installed\n"); - kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); - return 0; - } - break; - - case 0xa5: /* load security */ - if (dev->flags & KBC_FLAG_PS2) { - kbd_log("ATkbc: load security\n"); - dev->kbc_in = 1; + add_data(dev, 0xf1); return 0; } break; case 0xa7: /* disable mouse port */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: disable mouse port\n"); - // kbc_transmit(dev, 0); + set_enable_mouse(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: enable mouse port\n"); - // kbc_transmit(dev, 1); + set_enable_mouse(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if (dev->flags & KBC_FLAG_PS2) { - /* No error, this is testing the channel 2 interface. */ - kbc_transmit(dev, 0x00); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - kbc_transmit(dev, 0x00); + add_data(dev, 0x00); return 0; case 0xc0: /* read input port */ - /* IBM PS/1: - Bit 2 and 4 ignored (we return always 0), - Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". - Intel AMI: - Bit 2 ignored (we return always 1), - Bit 4 must be 1, - Bit 6 must be 1 or else error in SMM. - Acer: - Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), - Bit 4 must be 0, - Bit 6 ignored. - P6RP4: - Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -2064,8 +1223,11 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc) | + (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -2077,34 +1239,39 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } else { - pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); - // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); else - kbc_transmit(dev, dev->p1 | fixed_bits); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -2119,168 +1286,35 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; - switch(dev->kbc_cmd) { - /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - if (dev->kbc_cmd == 0x40) + switch(dev->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); - if (dev->secr_phase == 0) { - dev->mem_index = val; - dev->kbc_in = 1; - dev->secr_phase++; - } else if (dev->secr_phase == 1) { - if (dev->mem_index == 0x20) - write_cmd(dev, val); - else - dev->mem[dev->mem_index] = val; + kbd_log("ATkbc: AMI - set extended controller RAM\n"); + if (dev->secr_phase == 1) { + dev->mem_addr = val; + dev->want60 = 1; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; dev->secr_phase = 0; } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); - dev->mem_index = val; - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - dev->mem[index + dev->mem_index] = val; - } else if (dev->mem_index == 0x60) - write_cmd(dev, val); - else if (dev->mem_index == 0x42) - dev->status = val; - else if (dev->mem_index >= 0x40) - dev->mem[dev->mem_index - 0x40] = val; - else - dev->mem_int[dev->mem_index] = val; - return 0; - - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - dev->status = val; - break; - case 0x01: /* Password_ptr */ - dev->mem[0x1c] = val; - break; - case 0x02: /* Wakeup_Tsk_Reg */ - dev->mem[0x1e] = val; - break; - case 0x03: /* CCB */ - write_cmd(dev, val); - break; - case 0x04: /* Debounce_time */ - dev->mem[0x4d] = val; - break; - case 0x05: /* Pulse_Width */ - dev->mem[0x4e] = val; - break; - case 0x06: /* Pk_sel_byte */ - dev->mem[0x4c] = val; - break; - case 0x07: /* Func_Tsk_Reg */ - dev->mem[0x7e] = val; - break; - case 0x08: /* TypematicRate */ - dev->mem[0x80] = val; - break; - case 0x09: /* Led_Flag_Byte */ - dev->mem[0x81] = val; - break; - case 0x0a: /* Kbms_Command_St */ - dev->mem[0x87] = val; - break; - case 0x0b: /* Delay_Count_Byte */ - dev->mem[0x86] = val; - break; - case 0x0c: /* KBC_Flags */ - dev->mem[0x9b] = val; - break; - case 0x0d: /* SCODE_HK1 */ - dev->mem[0x50] = val; - break; - case 0x0e: /* SCODE_HK2 */ - dev->mem[0x51] = val; - break; - case 0x0f: /* SCODE_HK3 */ - dev->mem[0x52] = val; - break; - case 0x10: /* SCODE_HK4 */ - dev->mem[0x53] = val; - break; - case 0x11: /* SCODE_HK5 */ - dev->mem[0x54] = val; - break; - case 0x12: /* SCODE_HK6 */ - dev->mem[0x55] = val; - break; - case 0x13: /* TASK_HK1 */ - dev->mem[0x56] = val; - break; - case 0x14: /* TASK_HK2 */ - dev->mem[0x57] = val; - break; - case 0x15: /* TASK_HK3 */ - dev->mem[0x58] = val; - break; - case 0x16: /* TASK_HK4 */ - dev->mem[0x59] = val; - break; - case 0x17: /* TASK_HK5 */ - dev->mem[0x5a] = val; - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - dev->mem[0x5b] = val; - break; - case 0x19: /* Batt_Alarm_Reg1 */ - dev->mem[0x5c] = val; - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - dev->mem[0x5d] = val; - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - dev->mem[0x5e] = val; - break; - case 0x1c: /* Kbc_State1 */ - dev->mem[0x9d] = val; - break; - case 0x1d: /* Aux_Config */ - dev->mem[0x75] = val; - break; - case 0x1e: /* Kbc_State3 */ - dev->mem[0x73] = val; - break; - } - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); - dev->p1 = val; - return 0; - case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -2294,50 +1328,62 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; switch (val) { - case 0x00 ... 0x1f: + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - kbc_transmit(dev, dev->mem[val + 0x20]); + add_data(dev, dev->mem[val]); return 0; - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - dev->kbc_in = 1; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; return 0; case 0xa0: /* copyright message */ - kbc_transmit(dev, ami_copr[0]); - dev->kbc_phase = 1; - return 0; + add_data(dev, 0x28); + add_data(dev, 0x00); + break; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - // kbc_transmit(dev, 'H'); - kbc_transmit(dev, '5'); + add_data(dev, 'H'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->p2 & 0xf3); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port & 0xf3); + add_data(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->p2 | 0x0c); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port | 0x0c); + add_data(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -2345,7 +1391,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -2353,15 +1399,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read clock\n"); - kbc_transmit(dev, !!(dev->ami_stat & 1)); + add_data(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -2369,7 +1415,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -2377,237 +1423,68 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read cache\n"); - kbc_transmit(dev, !!(dev->ami_stat & 2)); + add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->kbc_in = 1; + dev->want60 = 1; + dev->secr_phase = 1; return 0; - case 0xb0 ... 0xb3: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { - dev->p1 &= ~(1 << (val & 0x03)); - } - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb1)) + dev->input_port &= ~(1 << (val & 0x03)); + add_data(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 & ~(4 << (val & 0x01))); - kbc_transmit(dev, 0x00); + if (! PCI) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_data(dev, 0x00); return 0; -#if 0 - case 0xb8 ... 0xbb: -#else - case 0xb9: -#endif + case 0xb8: case 0xb9: case 0xba: case 0xbb: /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { - dev->p1 |= (1 << (val & 0x03)); - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb9)) { + dev->input_port |= (1 << (val & 0x03)); + add_data(dev, 0x00); } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index\n"); - dev->kbc_in = 1; - return 0; - - case 0xba: - kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - kbc_transmit(dev, dev->mem[index + dev->mem_index]); - } else if (dev->mem_index == 0x42) - kbc_transmit(dev, dev->status); - else if (dev->mem_index >= 0x40) - kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); - else - kbc_transmit(dev, dev->mem_int[dev->mem_index]); - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - -#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 | (4 << (val & 0x01))); - kbc_transmit(dev, 0x00); - return 0; -#endif - - case 0xbc: - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - kbc_transmit(dev, dev->status); - break; - case 0x01: /* Password_ptr */ - kbc_transmit(dev, dev->mem[0x1c]); - break; - case 0x02: /* Wakeup_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x1e]); - break; - case 0x03: /* CCB */ - kbc_transmit(dev, dev->mem[0x20]); - break; - case 0x04: /* Debounce_time */ - kbc_transmit(dev, dev->mem[0x4d]); - break; - case 0x05: /* Pulse_Width */ - kbc_transmit(dev, dev->mem[0x4e]); - break; - case 0x06: /* Pk_sel_byte */ - kbc_transmit(dev, dev->mem[0x4c]); - break; - case 0x07: /* Func_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x7e]); - break; - case 0x08: /* TypematicRate */ - kbc_transmit(dev, dev->mem[0x80]); - break; - case 0x09: /* Led_Flag_Byte */ - kbc_transmit(dev, dev->mem[0x81]); - break; - case 0x0a: /* Kbms_Command_St */ - kbc_transmit(dev, dev->mem[0x87]); - break; - case 0x0b: /* Delay_Count_Byte */ - kbc_transmit(dev, dev->mem[0x86]); - break; - case 0x0c: /* KBC_Flags */ - kbc_transmit(dev, dev->mem[0x9b]); - break; - case 0x0d: /* SCODE_HK1 */ - kbc_transmit(dev, dev->mem[0x50]); - break; - case 0x0e: /* SCODE_HK2 */ - kbc_transmit(dev, dev->mem[0x51]); - break; - case 0x0f: /* SCODE_HK3 */ - kbc_transmit(dev, dev->mem[0x52]); - break; - case 0x10: /* SCODE_HK4 */ - kbc_transmit(dev, dev->mem[0x53]); - break; - case 0x11: /* SCODE_HK5 */ - kbc_transmit(dev, dev->mem[0x54]); - break; - case 0x12: /* SCODE_HK6 */ - kbc_transmit(dev, dev->mem[0x55]); - break; - case 0x13: /* TASK_HK1 */ - kbc_transmit(dev, dev->mem[0x56]); - break; - case 0x14: /* TASK_HK2 */ - kbc_transmit(dev, dev->mem[0x57]); - break; - case 0x15: /* TASK_HK3 */ - kbc_transmit(dev, dev->mem[0x58]); - break; - case 0x16: /* TASK_HK4 */ - kbc_transmit(dev, dev->mem[0x59]); - break; - case 0x17: /* TASK_HK5 */ - kbc_transmit(dev, dev->mem[0x5a]); - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - kbc_transmit(dev, dev->mem[0x5b]); - break; - case 0x19: /* Batt_Alarm_Reg1 */ - kbc_transmit(dev, dev->mem[0x5c]); - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - kbc_transmit(dev, dev->mem[0x5d]); - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x5e]); - break; - case 0x1c: /* Kbc_State1 */ - kbc_transmit(dev, dev->mem[0x9d]); - break; - case 0x1d: /* Aux_Config */ - kbc_transmit(dev, dev->mem[0x75]); - break; - case 0x1e: /* Kbc_State3 */ - kbc_transmit(dev, dev->mem[0x73]); - break; - default: - kbc_transmit(dev, 0x00); - break; - } - kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); + if (! PCI) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_data(dev, 0x00); return 0; - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write input port\n"); - dev->kbc_in = 1; - return 0; - - case 0xc4: - /* set KBC line P14 low */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); - dev->p1 &= 0xef; - kbc_transmit(dev, 0x00); - return 0; - case 0xc5: - /* set KBC line P15 low */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); - dev->p1 &= 0xdf; - kbc_transmit(dev, 0x00); - return 0; - - case 0xc8: case 0xc9: + case 0xc8: /* - * (un)block KBC lines P22/P23 + * unblock KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); - dev->p2_locked = (val & 1); + kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; - case 0xcc: - /* set KBC line P14 high */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); - dev->p1 |= 0x10; - kbc_transmit(dev, 0x00); - return 0; - case 0xcd: - /* set KBC line P15 high */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); - dev->p1 |= 0x20; - kbc_transmit(dev, 0x00); + case 0xc9: + /* + * block KBC lines P22/P23 + * (disallow command D1 from changing bits 2/3 of the port) + */ + kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -2628,20 +1505,23 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -2656,7 +1536,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -2665,34 +1545,12 @@ write60_quadtel(void *priv, uint8_t val) return 1; } - static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { - /* This appears to be a clone of "Read input port", in which case, the bis would be: - 7: M290 (AT KBC): - Keyboard lock (1 = unlocked, 0 = locked); - M300 (PS/2 KBC): - Bus expansion board present (1 = present, 0 = not present); - 6: Usually: - Display (1 = MDA, 0 = CGA, but can have its polarity inverted); - 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); - 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); - 3: Fast Ram check (if inactive keyboard works erratically); - 2: Keyboard fuse present - This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; - 1: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Mouse data in; - 0: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Key data in. - */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -2701,9 +1559,11 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); + add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); return 0; - } + } return write64_generic(dev, val); } @@ -2721,7 +1581,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } @@ -2734,7 +1594,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -2777,30 +1637,29 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - kbc_transmit(dev, t3100e_config_get()); + add_data(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - kbc_transmit(dev, t3100e_mono_get()); + add_data(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_FLAG_PS2; + dev->flags &= ~KBC_TYPE_MASK; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_FLAG_PS2; - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else + dev->flags |= KBC_TYPE_PS2_NOREF; + } else { kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); -#endif + dev->flags |= KBC_TYPE_ISA; + } return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -2810,9 +1669,8 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - kbc_transmit(dev, 0x04); - else - kbc_transmit(dev, 0x00); + add_data(dev, 0x04); + else add_data(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -2825,8 +1683,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbc_transmit(dev, dev->p1); + dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_data(dev, dev->input_port); return 0; } @@ -2839,46 +1697,423 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; + int i = 0, bad = 1; + uint8_t mask, kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; + + kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); switch (port) { case 0x60: - dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); + dev->status &= ~STAT_CD; + if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; -#if 0 - if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { - dev->status &= ~STAT_IFULL; - write_output(dev, val); - dev->fast_a20_phase = 0; + switch (dev->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->output_port & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + add_data_kbd_direct(dev, val); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (val == 0xbb) + break; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_mouse(dev, 1); + if (mouse_write) + mouse_write(val, mouse_p); + else + add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + + if (bad) { + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); + add_data_kbd(0xfe); + } + } + } else { + /* Write data to keyboard. */ + dev->mem[0] &= ~0x10; + + if (dev->key_wantdata) { + dev->key_wantdata = 0; + + /* + * Several system BIOSes and OS device drivers + * mess up with this, and repeat the command + * code many times. Fun! + */ + if (val == dev->key_command) { + /* Respond NAK and ignore it. */ + add_data_kbd(0xfe); + dev->key_command = 0x00; + break; + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd_direct(dev, 0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", val); + break; + + case 0xf0: /* get/set scancode set */ + add_data_kbd_direct(dev, 0xfa); + if (val == 0) { + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + add_data_kbd_direct(dev, keyboard_mode & 3); + } else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + add_data_kbd_direct(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); + add_data_kbd_direct(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + dev->key_command = 0x00; + } else { + /* No keyboard command in progress. */ + dev->key_command = 0x00; + + set_enable_kbd(dev, 1); + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + add_data_kbd_direct(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + add_data_kbd_direct(dev, 0xfe); + break; + + /* Sent by Pentium-era AMI BIOS'es.*/ + case 0x71: case 0x82: + kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + add_data_kbd_direct(dev, 0xfa); + + dev->key_wantdata = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + add_data_kbd_direct(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + add_data_kbd_direct(dev, 0xfa); + add_data_kbd_direct(dev, 0xab); + add_data_kbd_direct(dev, 0x83); + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", + val, keyboard_scan, dev->mem[0]); + add_data_kbd_direct(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + add_data_kbd_raw(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbc_queue_reset(1); + kbd_last_scan_code = 0x00; + add_data_kbd_direct(dev, 0xfa); + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->reset_delay = RESET_DELAY_TIME; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + add_data_kbd_direct(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = val; + } } -#endif break; - case 0x64: - dev->status |= (STAT_CD | STAT_IFULL); - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); -#if 0 - if (val == 0xd1) { - dev->status &= ~STAT_IFULL; - dev->fast_a20_phase = 1; - } else if (val == 0xfe) { - dev->status &= ~STAT_IFULL; - pulse_output(dev, 0x0e); - } else if ((val == 0xad) || (val == 0xae)) { - dev->status &= ~STAT_IFULL; - if (val & 0x01) - dev->mem[0x20] |= 0x10; - else - dev->mem[0x20] &= ~0x10; - } else if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); + case 0x61: + ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 1); + + if (kbc_ven == KBC_VEN_XI8088) + xi8088_turbo_set(!!(val & 0x04)); + break; + + case 0x64: + /* Controller command. */ + dev->want60 = 0; + dev->status |= STAT_CD; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + add_data(dev, dev->mem[val & 0x1f]); + break; + + /* Write data to KBC memory. */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->want60 = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) + dev->status |= STAT_IFULL; + write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0x00; + dev->status &= ~STAT_OFULL; + dev->last_irq = dev->old_last_irq = 0; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + add_data(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + add_data(dev, 0x00); /*no error*/ + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + for (i = 0; i < 16; i++) + add_data(dev, dev->mem[i]); + add_data(dev, (dev->input_port & 0xf0) | 0x80); + add_data(dev, dev->output_port); + add_data(dev, dev->status); + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->want60 = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) + mask &= 0xbf; + add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->want60 = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + dev->want60 = 1; + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + add_data(dev, 0x00); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); } -#endif + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = val; break; } } @@ -2889,20 +2124,83 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - // if (dev->flags & KBC_FLAG_PS2) - // cycles -= ISA_CYCLES(8); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + cycles -= ISA_CYCLES(8); + + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; switch (port) { case 0x60: - ret = dev->ob; + ret = dev->out; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + if (dev->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (kbc_ven == KBC_VEN_XI8088) { + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x62: + ret = 0xff; + if (kbc_ven == KBC_VEN_OLIVETTI) { + /* SWA on Olivetti M240 mainboard (off=1) */ + ret = 0x00; + if (ppi.pb & 0x8) { + /* Switches 4, 5 - floppy drives (number) */ + int i, fdd_count = 0; + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 2); + /* Switches 6, 7 - monitor type */ + if (video_is_mda()) + ret |= 0x3; + else if (video_is_cga()) + ret |= 0x2; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + } else { + /* bit 2 always on */ + ret |= 0x4; + /* Switch 8 - 8087 FPU. */ + if (hasfpu) + ret |= 0x02; + } + } + break; case 0x64: - ret = dev->status; + ret = (dev->status & 0xfb); + if (dev->mem[0] & STAT_SYSFLAG) + ret |= STAT_SYSFLAG; + /* Only clear the transmit timeout flag on non-PS/2 controllers, as on + PS/2 controller, it is the keyboard/mouse output source bit. */ + // dev->status &= ~STAT_RTIMEOUT; + if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && + (kbc_ven != KBC_VEN_IBM_MCA)) + dev->status &= ~STAT_TTIMEOUT; break; default: @@ -2910,12 +2208,22 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); + kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); return(ret); } +static void +kbd_refresh(void *priv) +{ + atkbd_t *dev = (atkbd_t *)priv; + + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); +} + + static void kbd_reset(void *priv) { @@ -2924,26 +2232,25 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; + dev->first_write = 1; + // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; + dev->mem[0] = 0x01; + dev->mem[0] |= CCB_TRANSLATE; + dev->wantirq = 0; write_output(dev, 0xcf); - dev->last_irq = 0; + dev->last_irq = dev->old_last_irq = 0; dev->secr_phase = 0; - dev->kbd_in = 0; - dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); + dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->p1 ^= 0x40; - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - dev->inhibit = ((dev->p1 & 0x80) >> 3); + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else - dev->inhibit = 0x10; - kbd_log("ATkbc: input port = %02x\n", dev->p1); + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbc: input port = %02x\n", dev->input_port); - keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2951,18 +2258,16 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->ob = 0xff; + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0; sc_or = 0; - for (i = 1; i <= 2; i++) - kbc_queue_reset(i); - memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); - - dev->mem[0x31] = 0xfe; } @@ -2984,6 +2289,7 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); + timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -3007,14 +2313,17 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - dev->kbc_poll_phase = KBC_RESET; - kbd_send_to_host(dev, 0xaa); + kbd_reset(dev); - io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); - io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + timer_add(&dev->refresh_time, kbd_refresh, dev, 1); + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -3030,14 +2339,12 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: - /* The Olivetti controller is a special case - starts directly in the - main loop instead of the reset loop. */ - dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: + case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -3057,8 +2364,6 @@ kbd_init(const device_t *info) break; } - kbd_reset(dev); - /* We need this, sadly. */ SavedKbd = dev; @@ -3086,6 +2391,16 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; +const device_t keyboard_at_samsung_device = { + "PC/AT Keyboard (Samsung)", + 0, + KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -3117,6 +2432,16 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -3129,7 +2454,7 @@ const device_t keyboard_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3139,7 +2464,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3159,7 +2484,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3169,7 +2494,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -3199,7 +2524,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -3209,7 +2534,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -3219,7 +2544,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3229,7 +2554,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -3239,7 +2564,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_ACER, + KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -3250,8 +2575,17 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - // mouse_write = func; - // mouse_p = priv; + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + + add_data_kbd_queue(dev, 0, val); } @@ -3264,30 +2598,10 @@ keyboard_at_adddata_mouse(uint8_t val) } -void -keyboard_at_adddata_mouse_direct(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - -void -keyboard_at_adddata_mouse_cmd(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - void keyboard_at_mouse_reset(void) { - // atkbd_t *dev = SavedKbd; - - return; + kbc_queue_reset(2); } @@ -3298,22 +2612,13 @@ keyboard_at_mouse_pos(void) } -int -keyboard_at_fixed_channel(void) -{ - // atkbd_t *dev = SavedKbd; - - return 0x000; -} - - void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -3327,7 +2632,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0] & 0x20) ? 0x00 : 0x10); } @@ -3336,17 +2641,5 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); -} - - -void -keyboard_at_set_mode(int ps2) -{ - atkbd_t *dev = SavedKbd; - - if (ps2) - dev->flags |= KBC_FLAG_PS2; - else - dev->flags &= ~KBC_FLAG_PS2; + write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); } From e26e387d2798ded42633279f5f272c82c6fb3c7d Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 06:59:06 +0200 Subject: [PATCH 023/140] Bring back the new keyboard_at.c. --- src/device/keyboard_at.c | 2793 ++++++++++++++++++++++++-------------- 1 file changed, 1750 insertions(+), 1043 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 581f55f30..92690db1f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,9 +57,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - -#define RESET_DELAY_TIME (100 * 10) /* 600ms */ +#define RESET_DELAY_TIME 1000 /* 100 ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -74,49 +72,136 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ -#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ -#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x03 +#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ +/* This only differs in that translation is forced off. */ +#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x07 +#define KBC_FLAG_PS2 0x04 + +/* We need to redefine this: + Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 + for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling + controller mode, normally set according to the flags, but togglable on + AMIKey: + 0000 0000 0x00 IBM, AT + 0000 0001 0x01 MR + 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 + 0001 0000 0x10 Olivetti + 0010 0000 0x20 Toshiba + 0011 0000 0x30 Quadtel + 0100 0000 0x40 Phoenix MultiKey/42 + 0101 0000 0x50 AMI KF + 0101 0001 0x51 AMI KH + 0101 0010 0x52 AMIKey + 0101 0011 0x53 AMIKey-2 + 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) + 0110 0000 0x60 Award + 0110 0001 0x61 Award 286 (has some AMI commands apparently) + 0111 0000 0x70 Siemens +*/ + +/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -#define KBC_VEN_AMI 0x04 +/* All commands are standard PS/2 */ #define KBC_VEN_IBM_MCA 0x08 -#define KBC_VEN_QUADTEL 0x0c -#define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_MASK 0x3c +/* Standard IBM commands, differs in input port bits */ +#define KBC_VEN_IBM_PS1 0x10 +/* Olivetti - proprietary commands and port 62h with switches + readout */ +#define KBC_VEN_OLIVETTI 0x20 +/* Toshiba T3100e - has a bunch of proprietary commands, also sets + IFULL on command AA */ +#define KBC_VEN_TOSHIBA 0x28 +/* Standard IBM commands, uses input port as a switches readout */ +#define KBC_VEN_NCR 0x30 +/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the + polarity of the video type bit in the input port is inverted */ +#define KBC_VEN_XI8088 0x38 +/* QuadtelKey - currently guesswork */ +#define KBC_VEN_QUADTEL 0x40 +/* Phoenix MultiKey/42 - not yet implemented */ +#define KBC_VEN_PHOENIX 0x48 +/* Generic commands, XI8088-like input port handling of video type, + maybe we just need a flag for that? */ +#define KBC_VEN_ACER 0x50 +/* AMI KF/KH/AMIKey/AMIKey-2 */ +#define KBC_VEN_AMI 0xf0 +/* Standard AMI commands, differs in input port bits */ +#define KBC_VEN_INTEL_AMI 0xf8 +#define KBC_VEN_MASK 0xf8 + + +/* Flags should be fully 32-bit: + Bits 7- 0: Vendor and revision/variant; + Bits 15- 8: Input port mask; + Bits 23-16: Input port bits that are always on; + Bits 31-24: Flags: + Bit 0: Invert P1 video type bit polarity; + Bit 1: Is PS/2; + Bit 2: Translation forced always off. + + So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ typedef struct { - uint8_t command, status, old_status, out, old_out, secr_phase, - mem_addr, input_port, output_port, old_output_port, - key_command, output_locked, ami_stat, want60, - wantirq, key_wantdata, refresh, first_write; + uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, + secr_phase, mem_index, ami_stat, ami_mode, + kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, + kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, + kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, + mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, + kbc_written[3], kbc_data[3]; - uint8_t mem[0x100]; + uint8_t mem_int[0x40], mem[0x240]; - int last_irq, old_last_irq, - reset_delay, - out_new, out_delayed; + uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb, send_delay_timer; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - - pc_timer_t send_delay_timer; } atkbd_t; +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbd_cmd_process(atkbd_t *dev); + +static void kbc_wait(atkbd_t *dev, uint8_t flags); + + /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -125,9 +210,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; +uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; + -static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -568,9 +653,27 @@ static const scancode scancode_set3[512] = { }; +#define UISTR_LEN 256 +static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); +extern void ui_sb_bugui(char *__str); + + +static void +kbd_status(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(kbd_str, fmt, ap); + ui_sb_bugui(kbd_str); + va_end(ap); +} + + +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -631,9 +734,6 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); - } else { - key_ctrl_queue_start = key_ctrl_queue_end = 0; - memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -641,15 +741,6 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - dev->status = (dev->status & 0x0f) | stat_hi; - if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -658,83 +749,1042 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else { - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - } -} - - -static void -add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - kbd_log("ATkbc: Adding %02X to front...\n", val); - dev->wantirq = 0; - if (channel == 2) { - if (dev->mem[0] & 0x02) - picint(0x1000); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - dev->last_irq = 2; - } - dev->out = val; - if (channel == 2) - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; - else - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; + } else + fatal("Adding %02X to invalid channel %02X\n", val, channel); } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); return; } - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } - static void -add_data_kbd_direct(atkbd_t *dev, uint8_t val) +kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); - uint8_t send; - - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - if (translate) - send = nont_to_t[val]; - else - send = val; - - add_data_kbd_queue(dev, 1, send); + dev->kbc_written[channel] = 1; + dev->kbc_data[channel] = val; } static void -add_data_kbd_raw(atkbd_t *dev, uint8_t val) +kbd_send_to_host(atkbd_t *dev, uint8_t val) { - add_data_kbd_queue(dev, 1, val); + kbc_send(dev, val, CHANNEL_KBD); +} + + +static void +kbd_chip_reset(atkbd_t *dev) +{ + kbc_queue_reset(1); + dev->kbc_written[1] = 0x00; + kbd_last_scan_code = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->kbd_phase = 0; + dev->kbd_in = 0; +} + + +static void +kbd_command(atkbd_t *dev) +{ + uint8_t val = dev->kbd_data; + + if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { + dev->kbd_phase++; + if (dev->kbd_phase == RESET_DELAY_TIME) { + kbd_send_to_host(dev, 0xaa); + dev->kbd_phase = 0; + dev->kbd_cmd = 0x00; + } + return; + } + + if (dev->kbd_phase == 2) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf2: + kbd_send_to_host(dev, 0x83); + break; + default: + fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } else if (dev->kbd_phase == 1) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf0: + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + kbd_send_to_host(dev, keyboard_mode & 3); + break; + case 0xf2: + kbd_send_to_host(dev, 0xab); + dev->kbd_phase = 2; + break; + default: + fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } + + if (dev->kbd_in && (val < 0xed)) { + dev->kbd_in = 0; + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set LEDs [%02x]\n", val); + kbd_send_to_host(dev, 0xfa); + break; + + case 0xf0: /* get/set scancode set */ + kbd_send_to_host(dev, 0xfa); + if (val == 0) + dev->kbd_phase = 1; + else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_send_to_host(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); + kbd_send_to_host(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + } else { + /* No keyboard command in progress. */ + dev->kbd_in = 0; + dev->kbd_cmd = 0x00; + dev->kbd_phase = 0; + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + kbd_send_to_host(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + kbd_send_to_host(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + kbd_send_to_host(dev, 0xfa); + + dev->kbd_in = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + kbd_send_to_host(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + val, keyboard_scan, dev->mem[0x20]); + kbd_send_to_host(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + kbd_send_to_host(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbd_chip_reset(dev); + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + kbd_send_to_host(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) + dev->kbd_cmd = val; + } +} + + +static void +kbd_do_command(atkbd_t *dev) +{ + kbd_command(dev); + if (dev->kbd_written) + dev->kbd_poll_phase = KBD_CMD_PROCESS; + else if ((dev->kbd_phase == 0) && !dev->kbd_in) { + dev->kbd_in_cmd = 0; + if (dev->kbd_data != 0xf5) + keyboard_scan = 1; + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else { + keyboard_scan = 0; + dev->kbd_in_cmd = 1; + dev->kbd_poll_phase = KBD_CMD_PROCESS; + } +} + + +static void +kbd_nack(atkbd_t *dev) +{ + kbd_send_to_host(dev, 0xfe); + dev->kbd_poll_phase = KBD_MAIN_LOOP; +} + + +static void +kbd_main_loop(atkbd_t *dev) +{ + uint8_t scan = !dev->kbd_inhibit && keyboard_scan; + + if (dev->kbd_written) { + dev->kbd_written = 0; + kbd_cmd_process(dev); + } else if (scan && (key_queue_start != key_queue_end)) { + /* Scan here. */ + kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); + kbd_send_to_host(dev, key_queue[key_queue_start]); + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +kbd_cmd_process(atkbd_t *dev) +{ + uint8_t written = dev->kbd_written; + + /* We want data, nothing has been written yet, return. */ + if (dev->kbd_in && !dev->kbd_written) + return; + + dev->kbd_written = 0; + + if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { + kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); + kbd_do_command(dev); + } else if (dev->kbd_data == 0xfe) { + kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); + kbd_send_to_host(dev, kbd_last_scan_code); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data == 0xee) { + kbd_log("ATkbd: Echo EE\n"); + kbd_send_to_host(dev, 0xee); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data >= 0xed) { + kbd_log("ATkbd: Command %02X\n", dev->kbd_data); + if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { + kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); + keyboard_scan = 1; + dev->kbd_in_cmd = 0; + } + kbd_do_command(dev); + } else { + if (!keyboard_scan && dev->kbd_in_cmd) { + if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { + kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); + kbd_nack(dev); + } else { + kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); + kbd_do_command(dev); + } + } else { + kbd_log("ATkbd: Scanning or not in command, NACK\n"); + kbd_nack(dev); + } + } +} + + +/* Keyboard processing */ +static void +kbd_process(atkbd_t *dev) +{ + /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ + if (dev->kbc_written[1] && dev->kbd_written) + dev->kbc_written[1] = 0; + + /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ + if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { + case KBD_MAIN_LOOP: + kbd_main_loop(dev); + break; + case KBD_CMD_PROCESS: + kbd_cmd_process(dev); + break; + } +} + + +static void +kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t ch = (channel > 0) ? channel : 1; + uint8_t do_irq = (dev->mem[0x20] & ch); + int translate = (channel == 1) && (keyboard_mode & 0x60); + + if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) + return; + + stat_hi |= dev->inhibit; + + if (!dev->kbc_send_pending) { + dev->kbc_send_pending = 1; + dev->kbc_to_send = val; + dev->kbc_channel = channel; + dev->kbc_stat_hi = stat_hi; + return; + } + + if (translate) { + /* Allow for scan code translation. */ + if (val == 0xf0) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if ((sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + } + + dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; + if (do_irq) { + kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); + picint(dev->last_irq); + } + kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); + dev->ob = translate ? (nont_to_t[val] | sc_or) : val; + + dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); + if (ch == 2) + dev->status |= STAT_MFULL; + + if (translate && (sc_or == 0x80)) + sc_or = 0; +} + + +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); + + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + val |= ((dev->mem[0x20] << 4) & 0x30); + + dev->kbd_inhibit = (val & 0x40); + dev->mouse_inhibit = (val & 0x08); + + if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) { + kbd_log("ATkbc: write_output(): IRQ 12\n"); + picint(1 << 12); + } else + picintc(1 << 12); + } + if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) { + kbd_log("ATkbc: write_output(): IRQ 1\n"); + picint(1 << 1); + } else + picintc(1 << 1); + } + if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->p2 ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->p2 = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + val &= ~CCB_TRANSLATE; + + dev->mem[0x20] = val; + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { + keyboard_mode &= ~CCB_PCMODE; + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + + +static void +kbc_transmit(atkbd_t *dev, uint8_t val) +{ + kbc_send_to_ob(dev, val, 0, 0x00); +} + + +static void +kbc_command(atkbd_t *dev) +{ + uint8_t mask, val = dev->ib; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int bad = 1; + + if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { + if (dev-> kbc_phase < 16) + kbc_transmit(dev, dev->mem[dev->kbc_phase]); + else if (dev-> kbc_phase == 16) + kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); + else if (dev-> kbc_phase == 17) + kbc_transmit(dev, dev->p2); + else if (dev-> kbc_phase == 18) + kbc_transmit(dev, dev->status); + + dev->kbc_phase++; + if (dev->kbc_phase == 19) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } + return; + } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { + val = ami_copr[dev->kbc_phase]; + kbc_transmit(dev, val); + if (val == 0x00) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } else + dev->kbc_phase++; + return; + } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { + /* load security */ + kbd_log("ATkbc: load security\n"); + dev->mem[0x50 + dev->kbc_in - 0x01] = val; + if ((dev->kbc_in == 0x80) && (val != 0x00)) { + /* Security string too long, set it to 0x00. */ + dev->mem[0x50] = 0x00; + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else if (val == 0x00) { + /* Security string finished. */ + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else /* Increase pointer and request another byte. */ + dev->kbc_in++; + return; + } + + /* If the written port is 64, go straight to the beginning of the command. */ + if (!(dev->status & STAT_CD) && dev->kbc_in) { + /* Write data to controller. */ + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (dev->kbc_cmd) { + case 0x60 ... 0x7f: + if (dev->kbc_cmd == 0x60) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + break; + + case 0xc7: /* or input port with system data */ + dev->p1 |= val; + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("New AMIKey mode: %02X\n", val); + dev->ami_mode = val; + dev->flags &= ~KBC_FLAG_PS2; + if (val & 1) + dev->flags |= KBC_FLAG_PS2; + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->p2_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->p2 & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + // kbc_send_to_ob(dev, val, 1, 0x00); + /* Should be channel 1, but we send to 0 to avoid translation, + since bytes output using this command do *NOT* get translated. */ + kbc_send_to_ob(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + kbc_send_to_ob(dev, val, 2, 0x00); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (dev->flags & KBC_FLAG_PS2) { + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x20; + if (mouse_write && !dev->kbc_written[2]) { + kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); + dev->mouse_data = val; + dev->mouse_written = 1; + dev->kbc_wait_for_response = 2; + } else + kbc_send_to_ob(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + +#ifdef ENABLE_KEYBOARD_AT_LOG + if (bad) + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); +#endif + } + } else { + /* Controller command. */ + kbd_log("ATkbc: Controller command: %02X\n", val); + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->kbc_in = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->kbd_in_cmd = dev->mouse_in_cmd = 0; + dev->status &= ~STAT_OFULL; + dev->last_irq = 0; + dev->kbc_phase = 0; + + /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ + if (dev->flags & KBC_FLAG_PS2) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + kbc_transmit(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + /* No error. */ + kbc_transmit(dev, 0x00); + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + kbc_transmit(dev, dev->mem[0x20]); + dev->kbc_phase = 1; + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* or input port with system data */ + kbd_log("ATkbc: Phoenix - or input port with system data\n"); + dev->kbc_in = 1; + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + kbc_transmit(dev, dev->ami_mode); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->kbc_in = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (dev->mem[0x20] & 0x10) + mask &= 0xbf; + if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) + mask &= 0xf7; + kbc_transmit(dev, dev->p2 & mask); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->kbc_in = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + dev->kbc_in = 1; + else + kbc_transmit(dev, 0x00); /* NCR */ + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + kbc_transmit(dev, 0x00); + break; + + case 0xe1: case 0xea: + kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); + write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); + } + + /* If the command needs data, remember the command. */ + if (dev->kbc_in || (dev->kbc_phase > 0)) + dev->kbc_cmd = val; + } +} + + +static void +kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) +{ + dev->kbc_written[channel] = 0; + kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); + kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); +} + + +static void +kbc_main_loop_scan(atkbd_t *dev) +{ + uint8_t port_dis = dev->mem[0x20] & 0x30; + uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); + + if (!ps2) + port_dis |= 0x20; + + if (!(dev->status & STAT_OFULL)) { + if (port_dis & 0x20) { + if (!(port_dis & 0x10)) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); + /* Enable communication with keyboard. */ + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 1); + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); + } +#endif + } else { + /* Enable communication with mouse. */ + dev->p2 &= 0xf7; + dev->mouse_inhibit = 0; + if (dev->mem[0x20] & 0x10) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); + kbc_wait(dev, 2); + } else { + /* Enable communication with keyboard. */ + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 3); + } + } + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + } +#endif +} + + +static void +kbc_process_ib(atkbd_t *dev) +{ + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + } else { + dev->mem[0x20] &= ~0x10; + dev->kbd_data = dev->ib; + dev->kbd_written = 1; + dev->kbc_wait_for_response = 1; + } + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response) + kbc_main_loop_scan(dev); +} + + +static void +kbc_wait(atkbd_t *dev, uint8_t flags) +{ + if ((flags & 1) && dev->kbc_written[1]) { + /* Disable communication with mouse. */ + dev->p2 |= 0x08; + dev->mouse_inhibit = 1; + /* Send keyboard byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_KBD); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if ((flags & 2) && dev->kbc_written[2]) { + /* Disable communication with keyboard. */ + dev->p2 |= 0x40; + dev->kbd_inhibit = 1; + /* Send mouse byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if (dev->status & STAT_IFULL) { + /* Disable communication with keyboard and mouse. */ + dev->p2 |= 0x48; + dev->kbd_inhibit = dev->mouse_inhibit = 1; + kbc_process_ib(dev); + } else + dev->kbc_poll_phase = KBC_WAIT | flags; +} + + +/* Controller processing */ +static void +kbc_process(atkbd_t *dev) +{ + // kbd_log("ATkbc: kbc_process()\n"); + + /* If we're waiting for the response from the keyboard or mouse, do nothing + until the device has repsonded back. */ + if (dev->kbc_wait_for_response > 0) { + if (dev->kbc_written[dev->kbc_wait_for_response]) + dev->kbc_wait_for_response = 0; + else + return; + } + + if (dev->kbc_send_pending) { + kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", + dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + dev->kbc_send_pending = 0; + } + + if (dev->kbc_poll_phase == KBC_RESET) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Reset loop()\n"); + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } + } + + return; + } + + if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: In a command\n"); + if (!dev->kbc_in && (dev->status & STAT_OFULL)) { + kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); + return; /* We do not want input and we're waiting for the host to read the data + we transmitted, but it has not done that yet, do nothing. */ + } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { + kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); + return; /* We want input and the host has not provided us with any yet, do nothing. */ + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: Normal condition\n"); +#endif + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + kbd_log("ATkbc: Resetting command\n"); + dev->kbc_phase = 0; + dev->kbc_in = 0; + } + } + + /* Process command. */ + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + + if (!(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ + } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { + case KBC_MAIN_LOOP: + // kbd_log("ATkbc: Main loop\n"); + if (dev->status & STAT_IFULL) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: IBF full, process\n"); + kbc_process_ib(dev); + } else + kbc_main_loop_scan(dev); + break; + case KBC_WAIT_FOR_KBD: + case KBC_WAIT_FOR_MOUSE: + case KBC_WAIT_FOR_BOTH: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); + kbc_wait(dev, dev->kbc_poll_phase & 3); + break; + default: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); + break; + } } @@ -742,105 +1792,29 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; -#ifdef ENABLE_KEYBOARD_AT_LOG - const uint8_t channels[4] = { 1, 2, 0, 0 }; -#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - if (dev->out_new != -1 && !dev->last_irq) { - dev->wantirq = 0; - if (dev->out_new & 0x100) { - if (dev->mem[0] & 0x02) - picint(0x1000); - kbd_log("ATkbc: %02X coming from channel 2\n"); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; - dev->last_irq = 2; - } - } + /* We process all three devices at the same time, in an arbitrary order. */ - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); - dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new = mouse_queue[mouse_queue_start] | 0x100; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { - kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - } + /* Keyboard processing */ + kbd_process(dev); - if (dev->reset_delay) { - dev->reset_delay--; - if (!dev->reset_delay) { - kbd_log("ATkbc: Sending AA on keyboard reset...\n"); - add_data_kbd_direct(dev, 0xaa); - } - } -} + /* TODO: Mouse processing */ + // mouse_process(dev); - -static void -add_data(atkbd_t *dev, uint8_t val) -{ - kbd_log("ATkbc: add to queue\n"); - - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - kbc_queue_add(dev, val, 0, 0x00); - - if (!(dev->out_new & 0x300)) { - dev->out_delayed = dev->out_new; - dev->out_new = -1; - } + /* Controller processing */ + kbc_process(dev); } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); int i; - uint8_t or = 0; - uint8_t send; - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - for (i = 0; i < len; i++) { - if (translate) { - if (val[i] == 0xf0) { - or = 0x80; - continue; - } - send = nont_to_t[val[i]] | or; - if (or == 0x80) - or = 0; - } else - send = val[i]; - - add_data_kbd_queue(dev, 0, send); - } + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, 0, val[i]); } @@ -848,56 +1822,21 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->reset_delay) + if (dev->kbd_in || (dev->kbd_phase > 0)) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Allow for scan code translation. */ - if (translate && (val == 0xf0)) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && - (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { - case 0x4f: t3100e_notify_set(0x01); break; /* End */ - case 0x50: t3100e_notify_set(0x02); break; /* Down */ - case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ - case 0x52: t3100e_notify_set(0x04); break; /* Ins */ - case 0x53: t3100e_notify_set(0x05); break; /* Del */ - case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ - case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ - case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ - case 0x47: t3100e_notify_set(0x09); break; /* Home */ - case 0x48: t3100e_notify_set(0x0a); break; /* Up */ - case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ - case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ - case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ - case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ - case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ - } + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && + (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) + t3100e_notify_set((val + 2) & 0x0f); - kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1030,18 +1969,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("scan code: "); - if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) - kbd_log("F0 "); - kbd_log("%02X)\n", val); - } else - kbd_log("%02X\n", val); -#endif - - add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); + add_data_kbd_queue(dev, 0, val); break; } @@ -1050,121 +1978,13 @@ add_data_kbd(uint16_t val) } -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) - val |= ((dev->mem[0] << 4) & 0x10); - - if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) - picint(1 << 12); - else - picintc(1 << 12); - } - if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) - picint(1 << 1); - else - picintc(1 << 1); - } - if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->output_port ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->output_port = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); - - if ((val & 1) && (dev->status & STAT_OFULL)) - dev->wantirq = 1; - if (!(val & 1) && dev->wantirq) - dev->wantirq = 0; - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { - val &= ~CCB_TRANSLATE; - dev->mem[0] &= ~CCB_TRANSLATE; - } - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || - ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { - keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->output_port); - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_output_port = dev->output_port & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); - write_output(dev, dev->output_port & (0xf0 | mask)); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); - write_output(dev, dev->output_port | dev->old_output_port); -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xef; - dev->mem[0] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xdf; - dev->mem[0] |= (enable ? 0x00 : 0x20); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); + write_output(dev, dev->p2 | dev->old_p2); } @@ -1173,49 +1993,70 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; switch (val) { case 0xa4: /* check if password installed */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: check if password installed\n"); - add_data(dev, 0xf1); + kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); + return 0; + } + break; + + case 0xa5: /* load security */ + if (dev->flags & KBC_FLAG_PS2) { + kbd_log("ATkbc: load security\n"); + dev->kbc_in = 1; return 0; } break; case 0xa7: /* disable mouse port */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: disable mouse port\n"); - set_enable_mouse(dev, 0); + // kbc_transmit(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: enable mouse port\n"); - set_enable_mouse(dev, 1); + // kbc_transmit(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ + if (dev->flags & KBC_FLAG_PS2) { + /* No error, this is testing the channel 2 interface. */ + kbc_transmit(dev, 0x00); return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - add_data(dev, 0x00); + kbc_transmit(dev, 0x00); return 0; case 0xc0: /* read input port */ + /* IBM PS/1: + Bit 2 and 4 ignored (we return always 0), + Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". + Intel AMI: + Bit 2 ignored (we return always 1), + Bit 4 must be 1, + Bit 6 must be 1 or else error in SMM. + Acer: + Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), + Bit 4 must be 0, + Bit 6 ignored. + P6RP4: + Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -1223,11 +2064,8 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc) | - (fdd_is_525(current_drive) ? 0x40 : 0x00); + kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -1239,39 +2077,34 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && - ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); + pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); + // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); else - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, dev->p1 | fixed_bits); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -1286,35 +2119,168 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; - switch(dev->command) { - /* 0x40 - 0x5F are aliases for 0x60-0x7F */ - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) + switch(dev->kbc_cmd) { + /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + if (dev->kbc_cmd == 0x40) write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM\n"); - if (dev->secr_phase == 1) { - dev->mem_addr = val; - dev->want60 = 1; - dev->secr_phase = 2; - } else if (dev->secr_phase == 2) { - dev->mem[dev->mem_addr] = val; + kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); + if (dev->secr_phase == 0) { + dev->mem_index = val; + dev->kbc_in = 1; + dev->secr_phase++; + } else if (dev->secr_phase == 1) { + if (dev->mem_index == 0x20) + write_cmd(dev, val); + else + dev->mem[dev->mem_index] = val; dev->secr_phase = 0; } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); + dev->mem_index = val; + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + dev->mem[index + dev->mem_index] = val; + } else if (dev->mem_index == 0x60) + write_cmd(dev, val); + else if (dev->mem_index == 0x42) + dev->status = val; + else if (dev->mem_index >= 0x40) + dev->mem[dev->mem_index - 0x40] = val; + else + dev->mem_int[dev->mem_index] = val; + return 0; + + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + dev->status = val; + break; + case 0x01: /* Password_ptr */ + dev->mem[0x1c] = val; + break; + case 0x02: /* Wakeup_Tsk_Reg */ + dev->mem[0x1e] = val; + break; + case 0x03: /* CCB */ + write_cmd(dev, val); + break; + case 0x04: /* Debounce_time */ + dev->mem[0x4d] = val; + break; + case 0x05: /* Pulse_Width */ + dev->mem[0x4e] = val; + break; + case 0x06: /* Pk_sel_byte */ + dev->mem[0x4c] = val; + break; + case 0x07: /* Func_Tsk_Reg */ + dev->mem[0x7e] = val; + break; + case 0x08: /* TypematicRate */ + dev->mem[0x80] = val; + break; + case 0x09: /* Led_Flag_Byte */ + dev->mem[0x81] = val; + break; + case 0x0a: /* Kbms_Command_St */ + dev->mem[0x87] = val; + break; + case 0x0b: /* Delay_Count_Byte */ + dev->mem[0x86] = val; + break; + case 0x0c: /* KBC_Flags */ + dev->mem[0x9b] = val; + break; + case 0x0d: /* SCODE_HK1 */ + dev->mem[0x50] = val; + break; + case 0x0e: /* SCODE_HK2 */ + dev->mem[0x51] = val; + break; + case 0x0f: /* SCODE_HK3 */ + dev->mem[0x52] = val; + break; + case 0x10: /* SCODE_HK4 */ + dev->mem[0x53] = val; + break; + case 0x11: /* SCODE_HK5 */ + dev->mem[0x54] = val; + break; + case 0x12: /* SCODE_HK6 */ + dev->mem[0x55] = val; + break; + case 0x13: /* TASK_HK1 */ + dev->mem[0x56] = val; + break; + case 0x14: /* TASK_HK2 */ + dev->mem[0x57] = val; + break; + case 0x15: /* TASK_HK3 */ + dev->mem[0x58] = val; + break; + case 0x16: /* TASK_HK4 */ + dev->mem[0x59] = val; + break; + case 0x17: /* TASK_HK5 */ + dev->mem[0x5a] = val; + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + dev->mem[0x5b] = val; + break; + case 0x19: /* Batt_Alarm_Reg1 */ + dev->mem[0x5c] = val; + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + dev->mem[0x5d] = val; + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + dev->mem[0x5e] = val; + break; + case 0x1c: /* Kbc_State1 */ + dev->mem[0x9d] = val; + break; + case 0x1d: /* Aux_Config */ + dev->mem[0x75] = val; + break; + case 0x1e: /* Kbc_State3 */ + dev->mem[0x73] = val; + break; + } + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->p1 = val; + return 0; + case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -1328,62 +2294,50 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; switch (val) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x00 ... 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - add_data(dev, dev->mem[val]); + kbc_transmit(dev, dev->mem[val + 0x20]); return 0; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->want60 = 1; + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + dev->kbc_in = 1; return 0; case 0xa0: /* copyright message */ - add_data(dev, 0x28); - add_data(dev, 0x00); - break; + kbc_transmit(dev, ami_copr[0]); + dev->kbc_phase = 1; + return 0; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - add_data(dev, 'H'); + // kbc_transmit(dev, 'H'); + kbc_transmit(dev, '5'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->output_port & 0xf3); - add_data(dev, 0x00); + write_output(dev, dev->p2 & 0xf3); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->output_port | 0x0c); - add_data(dev, 0x00); + write_output(dev, dev->p2 | 0x0c); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -1391,7 +2345,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -1399,15 +2353,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read clock\n"); - add_data(dev, !!(dev->ami_stat & 1)); + kbc_transmit(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -1415,7 +2369,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -1423,68 +2377,237 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read cache\n"); - add_data(dev, !!(dev->ami_stat & 2)); + kbc_transmit(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->want60 = 1; - dev->secr_phase = 1; + dev->kbc_in = 1; return 0; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb0 ... 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!PCI || (val > 0xb1)) - dev->input_port &= ~(1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { + dev->p1 &= ~(1 << (val & 0x03)); + } + kbc_transmit(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (! PCI) - write_output(dev, dev->output_port & ~(4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 & ~(4 << (val & 0x01))); + kbc_transmit(dev, 0x00); return 0; - case 0xb8: case 0xb9: case 0xba: case 0xbb: +#if 0 + case 0xb8 ... 0xbb: +#else + case 0xb9: +#endif /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!PCI || (val > 0xb9)) { - dev->input_port |= (1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + kbc_transmit(dev, 0x00); } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index\n"); + dev->kbc_in = 1; + return 0; + + case 0xba: + kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + kbc_transmit(dev, dev->mem[index + dev->mem_index]); + } else if (dev->mem_index == 0x42) + kbc_transmit(dev, dev->status); + else if (dev->mem_index >= 0x40) + kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); + else + kbc_transmit(dev, dev->mem_int[dev->mem_index]); + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + +#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (! PCI) - write_output(dev, dev->output_port | (4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 | (4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; +#endif + + case 0xbc: + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + kbc_transmit(dev, dev->status); + break; + case 0x01: /* Password_ptr */ + kbc_transmit(dev, dev->mem[0x1c]); + break; + case 0x02: /* Wakeup_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x1e]); + break; + case 0x03: /* CCB */ + kbc_transmit(dev, dev->mem[0x20]); + break; + case 0x04: /* Debounce_time */ + kbc_transmit(dev, dev->mem[0x4d]); + break; + case 0x05: /* Pulse_Width */ + kbc_transmit(dev, dev->mem[0x4e]); + break; + case 0x06: /* Pk_sel_byte */ + kbc_transmit(dev, dev->mem[0x4c]); + break; + case 0x07: /* Func_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x7e]); + break; + case 0x08: /* TypematicRate */ + kbc_transmit(dev, dev->mem[0x80]); + break; + case 0x09: /* Led_Flag_Byte */ + kbc_transmit(dev, dev->mem[0x81]); + break; + case 0x0a: /* Kbms_Command_St */ + kbc_transmit(dev, dev->mem[0x87]); + break; + case 0x0b: /* Delay_Count_Byte */ + kbc_transmit(dev, dev->mem[0x86]); + break; + case 0x0c: /* KBC_Flags */ + kbc_transmit(dev, dev->mem[0x9b]); + break; + case 0x0d: /* SCODE_HK1 */ + kbc_transmit(dev, dev->mem[0x50]); + break; + case 0x0e: /* SCODE_HK2 */ + kbc_transmit(dev, dev->mem[0x51]); + break; + case 0x0f: /* SCODE_HK3 */ + kbc_transmit(dev, dev->mem[0x52]); + break; + case 0x10: /* SCODE_HK4 */ + kbc_transmit(dev, dev->mem[0x53]); + break; + case 0x11: /* SCODE_HK5 */ + kbc_transmit(dev, dev->mem[0x54]); + break; + case 0x12: /* SCODE_HK6 */ + kbc_transmit(dev, dev->mem[0x55]); + break; + case 0x13: /* TASK_HK1 */ + kbc_transmit(dev, dev->mem[0x56]); + break; + case 0x14: /* TASK_HK2 */ + kbc_transmit(dev, dev->mem[0x57]); + break; + case 0x15: /* TASK_HK3 */ + kbc_transmit(dev, dev->mem[0x58]); + break; + case 0x16: /* TASK_HK4 */ + kbc_transmit(dev, dev->mem[0x59]); + break; + case 0x17: /* TASK_HK5 */ + kbc_transmit(dev, dev->mem[0x5a]); + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + kbc_transmit(dev, dev->mem[0x5b]); + break; + case 0x19: /* Batt_Alarm_Reg1 */ + kbc_transmit(dev, dev->mem[0x5c]); + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + kbc_transmit(dev, dev->mem[0x5d]); + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x5e]); + break; + case 0x1c: /* Kbc_State1 */ + kbc_transmit(dev, dev->mem[0x9d]); + break; + case 0x1d: /* Aux_Config */ + kbc_transmit(dev, dev->mem[0x75]); + break; + case 0x1e: /* Kbc_State3 */ + kbc_transmit(dev, dev->mem[0x73]); + break; + default: + kbc_transmit(dev, 0x00); + break; + } + kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); return 0; - case 0xc8: + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->kbc_in = 1; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->p1 &= 0xef; + kbc_transmit(dev, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->p1 &= 0xdf; + kbc_transmit(dev, 0x00); + return 0; + + case 0xc8: case 0xc9: /* - * unblock KBC lines P22/P23 + * (un)block KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); - dev->output_locked = 1; + kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); + dev->p2_locked = (val & 1); return 0; - case 0xc9: - /* - * block KBC lines P22/P23 - * (disallow command D1 from changing bits 2/3 of the port) - */ - kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); - dev->output_locked = 1; + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->p1 |= 0x10; + kbc_transmit(dev, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->p1 |= 0x20; + kbc_transmit(dev, 0x00); return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -1505,23 +2628,20 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -1536,7 +2656,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -1545,12 +2665,34 @@ write60_quadtel(void *priv, uint8_t val) return 1; } + static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { + /* This appears to be a clone of "Read input port", in which case, the bis would be: + 7: M290 (AT KBC): + Keyboard lock (1 = unlocked, 0 = locked); + M300 (PS/2 KBC): + Bus expansion board present (1 = present, 0 = not present); + 6: Usually: + Display (1 = MDA, 0 = CGA, but can have its polarity inverted); + 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); + 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); + 3: Fast Ram check (if inactive keyboard works erratically); + 2: Keyboard fuse present + This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; + 1: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Mouse data in; + 0: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Key data in. + */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -1559,11 +2701,9 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); return 0; - } + } return write64_generic(dev, val); } @@ -1581,7 +2721,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } @@ -1594,7 +2734,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -1637,29 +2777,30 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - add_data(dev, t3100e_config_get()); + kbc_transmit(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - add_data(dev, t3100e_mono_get()); + kbc_transmit(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_TYPE_MASK; + dev->flags &= ~KBC_FLAG_PS2; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_TYPE_PS2_NOREF; - } else { - kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); - dev->flags |= KBC_TYPE_ISA; + dev->flags |= KBC_FLAG_PS2; } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); +#endif return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -1669,8 +2810,9 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - add_data(dev, 0x04); - else add_data(dev, 0x00); + kbc_transmit(dev, 0x04); + else + kbc_transmit(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -1683,8 +2825,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - add_data(dev, dev->input_port); + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + kbc_transmit(dev, dev->p1); return 0; } @@ -1697,423 +2839,46 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i = 0, bad = 1; - uint8_t mask, kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - - kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); + kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); switch (port) { case 0x60: - dev->status &= ~STAT_CD; - if (dev->want60) { - /* Write data to controller. */ - dev->want60 = 0; + dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (dev->command) { - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) - write_cmd(dev, val); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->output_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->output_port & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - add_data_kbd_direct(dev, val); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - keyboard_at_adddata_mouse(val); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (val == 0xbb) - break; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - set_enable_mouse(dev, 1); - if (mouse_write) - mouse_write(val, mouse_p); - else - add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - - if (bad) { - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); - add_data_kbd(0xfe); - } - } - } else { - /* Write data to keyboard. */ - dev->mem[0] &= ~0x10; - - if (dev->key_wantdata) { - dev->key_wantdata = 0; - - /* - * Several system BIOSes and OS device drivers - * mess up with this, and repeat the command - * code many times. Fun! - */ - if (val == dev->key_command) { - /* Respond NAK and ignore it. */ - add_data_kbd(0xfe); - dev->key_command = 0x00; - break; - } - - switch (dev->key_command) { - case 0xed: /* set/reset LEDs */ - add_data_kbd_direct(dev, 0xfa); - kbd_log("ATkbd: set LEDs [%02x]\n", val); - break; - - case 0xf0: /* get/set scancode set */ - add_data_kbd_direct(dev, 0xfa); - if (val == 0) { - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - add_data_kbd_direct(dev, keyboard_mode & 3); - } else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - add_data_kbd_direct(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); - add_data_kbd_direct(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - dev->key_command = 0x00; - } else { - /* No keyboard command in progress. */ - dev->key_command = 0x00; - - set_enable_kbd(dev, 1); - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - add_data_kbd_direct(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - add_data_kbd_direct(dev, 0xfe); - break; - - /* Sent by Pentium-era AMI BIOS'es.*/ - case 0x71: case 0x82: - kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - add_data_kbd_direct(dev, 0xfa); - - dev->key_wantdata = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - add_data_kbd_direct(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - add_data_kbd_direct(dev, 0xfa); - add_data_kbd_direct(dev, 0xab); - add_data_kbd_direct(dev, 0x83); - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", - val, keyboard_scan, dev->mem[0]); - add_data_kbd_direct(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_raw(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbc_queue_reset(1); - kbd_last_scan_code = 0x00; - add_data_kbd_direct(dev, 0xfa); - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->reset_delay = RESET_DELAY_TIME; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - add_data_kbd_direct(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if (dev->key_wantdata == 1) - dev->key_command = val; - } +#if 0 + if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { + dev->status &= ~STAT_IFULL; + write_output(dev, val); + dev->fast_a20_phase = 0; } +#endif break; - - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if (kbc_ven == KBC_VEN_XI8088) - xi8088_turbo_set(!!(val & 0x04)); - break; - case 0x64: - /* Controller command. */ - dev->want60 = 0; - dev->status |= STAT_CD; + dev->status |= (STAT_CD | STAT_IFULL); + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (val) { - /* Read data from KBC memory. */ - case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - add_data(dev, dev->mem[val & 0x1f]); - break; - - /* Write data to KBC memory. */ - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->want60 = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) - dev->status |= STAT_IFULL; - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - dev->last_irq = dev->old_last_irq = 0; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_data(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - add_data(dev, 0x00); /*no error*/ - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - for (i = 0; i < 16; i++) - add_data(dev, dev->mem[i]); - add_data(dev, (dev->input_port & 0xf0) | 0x80); - add_data(dev, dev->output_port); - add_data(dev, dev->status); - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->want60 = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) - mask &= 0xbf; - add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->want60 = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - dev->want60 = 1; - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - add_data(dev, 0x00); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); +#if 0 + if (val == 0xd1) { + dev->status &= ~STAT_IFULL; + dev->fast_a20_phase = 1; + } else if (val == 0xfe) { + dev->status &= ~STAT_IFULL; + pulse_output(dev, 0x0e); + } else if ((val == 0xad) || (val == 0xae)) { + dev->status &= ~STAT_IFULL; + if (val & 0x01) + dev->mem[0x20] |= 0x10; + else + dev->mem[0x20] &= ~0x10; + } else if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); } - - /* If the command needs data, remember the command. */ - if (dev->want60) - dev->command = val; +#endif break; } } @@ -2124,83 +2889,20 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - cycles -= ISA_CYCLES(8); - - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; + // if (dev->flags & KBC_FLAG_PS2) + // cycles -= ISA_CYCLES(8); switch (port) { case 0x60: - ret = dev->out; + ret = dev->ob; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if (kbc_ven == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) - ret |= 0x04; - else - ret &= ~0x04; - } - break; - - case 0x62: - ret = 0xff; - if (kbc_ven == KBC_VEN_OLIVETTI) { - /* SWA on Olivetti M240 mainboard (off=1) */ - ret = 0x00; - if (ppi.pb & 0x8) { - /* Switches 4, 5 - floppy drives (number) */ - int i, fdd_count = 0; - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } - if (!fdd_count) - ret |= 0x00; - else - ret |= ((fdd_count - 1) << 2); - /* Switches 6, 7 - monitor type */ - if (video_is_mda()) - ret |= 0x3; - else if (video_is_cga()) - ret |= 0x2; /* 0x10 would be 40x25 */ - else - ret |= 0x0; - } else { - /* bit 2 always on */ - ret |= 0x4; - /* Switch 8 - 8087 FPU. */ - if (hasfpu) - ret |= 0x02; - } - } - break; case 0x64: - ret = (dev->status & 0xfb); - if (dev->mem[0] & STAT_SYSFLAG) - ret |= STAT_SYSFLAG; - /* Only clear the transmit timeout flag on non-PS/2 controllers, as on - PS/2 controller, it is the keyboard/mouse output source bit. */ - // dev->status &= ~STAT_RTIMEOUT; - if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && - (kbc_ven != KBC_VEN_IBM_MCA)) - dev->status &= ~STAT_TTIMEOUT; + ret = dev->status; break; default: @@ -2208,22 +2910,12 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); + kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); return(ret); } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { @@ -2232,25 +2924,26 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; - dev->first_write = 1; - // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0] = 0x01; - dev->mem[0] |= CCB_TRANSLATE; - dev->wantirq = 0; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; write_output(dev, 0xcf); - dev->last_irq = dev->old_last_irq = 0; + dev->last_irq = 0; dev->secr_phase = 0; - dev->key_wantdata = 0; + dev->kbd_in = 0; + dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); /* Set up the correct Video Type bits. */ + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + dev->p1 ^= 0x40; + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + dev->inhibit = ((dev->p1 & 0x80) >> 3); else - dev->input_port = video_is_mda() ? 0xf0 : 0xb0; - kbd_log("ATkbc: input port = %02x\n", dev->input_port); + dev->inhibit = 0x10; + kbd_log("ATkbc: input port = %02x\n", dev->p1); - keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2258,16 +2951,18 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0; + dev->ob = 0xff; sc_or = 0; + for (i = 1; i <= 2; i++) + kbc_queue_reset(i); + memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->mem[0x31] = 0xfe; } @@ -2289,7 +2984,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2313,17 +3007,14 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - kbd_reset(dev); + dev->kbc_poll_phase = KBC_RESET; + kbd_send_to_host(dev, 0xaa); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -2339,12 +3030,14 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: + /* The Olivetti controller is a special case - starts directly in the + main loop instead of the reset loop. */ + dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2364,6 +3057,8 @@ kbd_init(const device_t *info) break; } + kbd_reset(dev); + /* We need this, sadly. */ SavedKbd = dev; @@ -2391,16 +3086,6 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; -const device_t keyboard_at_samsung_device = { - "PC/AT Keyboard (Samsung)", - 0, - KBC_TYPE_ISA | KBC_VEN_SAMSUNG, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -2432,16 +3117,6 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -2454,7 +3129,7 @@ const device_t keyboard_ps2_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2464,7 +3139,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2484,7 +3159,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2494,7 +3169,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -2524,7 +3199,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -2534,7 +3209,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2544,7 +3219,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2554,7 +3229,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -2564,7 +3239,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + KBC_TYPE_PS2_1 | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -2575,17 +3250,8 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - mouse_write = func; - mouse_p = priv; -} - - -void -keyboard_at_adddata_keyboard_raw(uint8_t val) -{ - atkbd_t *dev = SavedKbd; - - add_data_kbd_queue(dev, 0, val); + // mouse_write = func; + // mouse_p = priv; } @@ -2598,10 +3264,30 @@ keyboard_at_adddata_mouse(uint8_t val) } +void +keyboard_at_adddata_mouse_direct(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + void keyboard_at_mouse_reset(void) { - kbc_queue_reset(2); + // atkbd_t *dev = SavedKbd; + + return; } @@ -2612,13 +3298,22 @@ keyboard_at_mouse_pos(void) } +int +keyboard_at_fixed_channel(void) +{ + // atkbd_t *dev = SavedKbd; + + return 0x000; +} + + void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -2632,7 +3327,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); } @@ -2641,5 +3336,17 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); + write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); +} + + +void +keyboard_at_set_mode(int ps2) +{ + atkbd_t *dev = SavedKbd; + + if (ps2) + dev->flags |= KBC_FLAG_PS2; + else + dev->flags &= ~KBC_FLAG_PS2; } From d38a90bbcc4b24f69b1d34701421729afb2bb3d4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 06:59:46 +0200 Subject: [PATCH 024/140] And Makefile.mingw. --- src/win/Makefile.mingw | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 4390235a9..42b3fbbbc 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -631,6 +631,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o +ifeq ($(NEW_KBC), y) DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ From a1e6872a440dbfbbc0d30d9f0631adc4208aa265 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 22:07:23 +0200 Subject: [PATCH 025/140] The Contaq now uses the correct functions for ISA clock dividers. --- src/chipset/contaq_82c59x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 19a3d5b44..33f972780 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -75,16 +75,16 @@ contaq_82c59x_isa_speed_recalc(contaq_82c59x_t *dev) /* TODO: ISA clock dividers for 386 and alt. 486. */ switch (dev->regs[0x10] & 0x03) { case 0x00: - cpu_set_isa_pci_div(4); + cpu_set_isa_speed(cpu_busspeed / 4); break; case 0x01: - cpu_set_isa_pci_div(6); + cpu_set_isa_speed(cpu_busspeed / 6); break; case 0x02: - cpu_set_isa_pci_div(8); + cpu_set_isa_speed(cpu_busspeed / 8); break; case 0x04: - cpu_set_isa_pci_div(5); + cpu_set_isa_speed(cpu_busspeed / 5); break; } } From bee63961d29dc7d06b6221c769a0e9483ddb94b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 22:10:20 +0200 Subject: [PATCH 026/140] Some Contaq clean-ups. --- src/chipset/contaq_82c59x.c | 120 +++--------------------------------- 1 file changed, 8 insertions(+), 112 deletions(-) diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 33f972780..eb9ed9cdd 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -205,11 +205,7 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) cpu_update_waitstates(); break; - case 0x12: - dev->regs[dev->index] = val; - break; - - case 0x13: + case 0x12: case 0x13: dev->regs[dev->index] = val; break; @@ -223,27 +219,7 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) contaq_82c59x_shadow_recalc(dev); break; - case 0x16: - dev->regs[dev->index] = val; - break; - - case 0x17: - dev->regs[dev->index] = val; - break; - - case 0x18: - dev->regs[dev->index] = val; - break; - - case 0x19: - dev->regs[dev->index] = val; - break; - - case 0x1a: - dev->regs[dev->index] = val; - break; - - case 0x1b: + case 0x16 ... 0x1b: dev->regs[dev->index] = val; break; @@ -253,32 +229,12 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) contaq_82c59x_isa_speed_recalc(dev); break; - case 0x1d: - dev->regs[dev->index] = val; - break; - - case 0x1e: - dev->regs[dev->index] = val; - break; - - case 0x1f: + case 0x1d ... 0x1f: dev->regs[dev->index] = val; break; /* Green (82C597-specific) registers. */ - case 0x60: - dev->regs[dev->index] = val; - break; - - case 0x61: - dev->regs[dev->index] = val; - break; - - case 0x62: - dev->regs[dev->index] = val; - break; - - case 0x63: + case 0x60 ... 0x63: dev->regs[dev->index] = val; break; @@ -291,23 +247,7 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) } break; - case 0x65: - dev->regs[dev->index] = val; - break; - - case 0x66: - dev->regs[dev->index] = val; - break; - - case 0x67: - dev->regs[dev->index] = val; - break; - - case 0x68: - dev->regs[dev->index] = val; - break; - - case 0x69: + case 0x65 ... 0x69: dev->regs[dev->index] = val; break; @@ -316,15 +256,7 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) dev->smi_status_set = !!(val & 0x80); break; - case 0x6b: - dev->regs[dev->index] = val; - break; - - case 0x6c: - dev->regs[dev->index] = val; - break; - - case 0x6d: + case 0x6b ... 0x6d: dev->regs[dev->index] = val; break; @@ -338,47 +270,11 @@ contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) contaq_82c59x_smram_recalc(dev); break; - case 0x71: + case 0x71 ... 0x79: dev->regs[dev->index] = val; break; - case 0x72: - dev->regs[dev->index] = val; - break; - - case 0x73: - dev->regs[dev->index] = val; - break; - - case 0x74: - dev->regs[dev->index] = val; - break; - - case 0x75: - dev->regs[dev->index] = val; - break; - - case 0x76: - dev->regs[dev->index] = val; - break; - - case 0x77: - dev->regs[dev->index] = val; - break; - - case 0x78: - dev->regs[dev->index] = val; - break; - - case 0x79: - dev->regs[dev->index] = val; - break; - - case 0x7b: - dev->regs[dev->index] = val; - break; - - case 0x7c: + case 0x7b: case 0x7c: dev->regs[dev->index] = val; break; } From f8046a8745c9fcfbb3adac2b944c9989687a950c Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Aug 2021 22:12:14 +0200 Subject: [PATCH 027/140] And another Contaq fix. --- src/chipset/contaq_82c59x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index eb9ed9cdd..93c841b9b 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -83,7 +83,7 @@ contaq_82c59x_isa_speed_recalc(contaq_82c59x_t *dev) case 0x02: cpu_set_isa_speed(cpu_busspeed / 8); break; - case 0x04: + case 0x03: cpu_set_isa_speed(cpu_busspeed / 5); break; } From e2a227552ed06d949b635bb4f70e230f7b2b5e3b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:03:27 +0200 Subject: [PATCH 028/140] Change #1 for attempted conflict resolution. --- src/machine/m_at_sockets7.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index 47ee28a29..2ab21d856 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -40,6 +40,7 @@ #include <86box/video.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/snd_ac97.h> #include <86box/clock.h> From 43bfecaa6e04da7502913cc97c851ce2acba045b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:05:20 +0200 Subject: [PATCH 029/140] And another. --- src/machine/m_at_sockets7.c | 139 ------------------------------------ 1 file changed, 139 deletions(-) diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index 2ab21d856..be27801cb 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -41,145 +41,6 @@ #include "cpu.h" #include <86box/machine.h> #include <86box/snd_ac97.h> -#include <86box/clock.h> - - -int -machine_at_p5a_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/p5a/1011.005", - 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); - device_add(&ali1541_device); - device_add(&ali1543c_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); - device_add(&w83781d_p5a_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ - - return ret; -} - - -int -machine_at_m579_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/m579/MS6260S_Socket7_ALi_M1542_AMI.BIN", - 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&ali1541_device); - device_add(&ali1543c_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} - - -int -machine_at_ga_5aa_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ga-5aa/GA-5AA.F7b", - 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - device_add(&ali1541_device); - device_add(&ali1543c_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} - - -int -machine_at_ga_5ax_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ga-5ax/5AX.F4", - 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&ali1541_device); - device_add(&ali1543c_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - return ret; -} int From 66da8a9905fd31da877fe17e52e680d7e7656e81 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:14:47 +0200 Subject: [PATCH 030/140] And another. --- src/machine/machine_table.c | 519 +++++------------------------------- 1 file changed, 61 insertions(+), 458 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 124a1236b..f8a4f3bb7 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -39,12 +39,10 @@ const machine_type_t machine_types[] = { { "8086", MACHINE_TYPE_8086 }, { "80286", MACHINE_TYPE_286 }, { "i386SX", MACHINE_TYPE_386SX }, - { "486SLC", MACHINE_TYPE_486SLC }, { "i386DX", MACHINE_TYPE_386DX }, { "i386DX/i486", MACHINE_TYPE_386DX_486 }, { "i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, - { "i486 (Socket 2)", MACHINE_TYPE_486_S2 }, - { "i486 (Socket 3)", MACHINE_TYPE_486_S3 }, + { "i486 (Socket 2 and 3)", MACHINE_TYPE_486_S3 }, { "i486 (Miscellaneous)", MACHINE_TYPE_486_MISC }, { "Socket 4", MACHINE_TYPE_SOCKET4 }, { "Socket 5", MACHINE_TYPE_SOCKET5 }, @@ -60,49 +58,6 @@ const machine_type_t machine_types[] = { }; -/* Machines to add before machine freeze: - - Jetway J-403TG MR BIOS v2.02; - - Matsonic MS6260S (AMI Super Socket 7 with Aladdin V chipset); - - PCChips M773 (440BX + SMSC with AMI BIOS); - - Rise R418 (was removed on my end, has to be re-added); - - TMC Mycomp PCI54ST; - - Zeos Quadtel 486. - - NOTE: The AMI MegaKey tests were done on a real Intel Advanced/ATX - (thanks, MrKsoft for running my AMIKEY.COM on it), but the - technical specifications of the other Intel machines confirm - that the other boards also have the MegaKey. - - NOTE: The later (ie. not AMI Color) Intel AMI BIOS'es execute a - sequence of commands (B8, BA, BB) during one of the very first - phases of POST, in a way that is only valid on the AMIKey-3 - KBC firmware, that includes the Classic PCI/ED (Ninja) BIOS - which otherwise does not execute any AMI KBC commands, which - indicates that the sequence is a leftover of whatever AMI - BIOS (likely a laptop one since the AMIKey-3 is a laptop KBC - firmware!) Intel forked. - - NOTE: The VIA VT82C42N returns 0x46 ('F') in command 0xA1 (so it - emulates the AMI KF/AMIKey KBC firmware), and 0x42 ('B') in - command 0xAF. - The version on the VIA VT82C686B southbridge also returns - 'F' in command 0xA1, but 0x45 ('E') in command 0xAF. - - NOTE: The AMI MegaKey commands blanked in the technical reference - are CC and and C4, which are Set P14 High and Set P14 Low, - respectively. Also, AMI KBC command C1, mysteriously missing - from the technical references of AMI MegaKey and earlier, is - Write Input Port, same as on AMIKey-3. - - Machines to remove: - - Hedaka HED-919; - - A-Trend ATC-1415; - - ECS Elite UM8810PAIO; - - Shuttle HOT-433A; - - Azza 5IVG (if a more interesting machine with Prime3C is found). -*/ - - const machine_t machines[] = { /* 8088 Machines */ { "[8088] IBM PC (1981)", "ibmpc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 16, 64, 16, 0, machine_pc_init, NULL }, @@ -114,10 +69,10 @@ const machine_t machines[] = { { "[8088] AMI XT clone", "amixt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, { "[8088] Columbia Data Products MPC-1600", "mpc1600", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 512, 64, 0, machine_xt_mpc1600_init, NULL }, { "[8088] Compaq Portable", "portable", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_portable_init, NULL }, - { "[8088] DTK PIM-TB10-Z", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] DTK XT clone", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, { "[8088] Eagle PC Spirit", "pcspirit", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pcspirit_init, NULL }, { "[8088] Generic XT clone", "genxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_genxt_init, NULL }, - { "[8088] Juko ST", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] Juko XT clone", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, { "[8088] Multitech PC-700", "pc700", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pc700_init, NULL }, { "[8088] NCR PC4i", "pc4i", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_pc4i_init, NULL }, { "[8088] Olivetti M19", "m19", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 4772728, 7159092, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 256, 640, 256, 0, machine_xt_m19_init, m19_get_device }, @@ -132,7 +87,6 @@ const machine_t machines[] = { #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", "ltxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, #endif - /* Has a standard PS/2 KBC (so, use IBM PS/2 Type 1). */ { "[8088] Xi8088", "xi8088", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, { "[8088] Zenith Data Systems Z-151/152/161","zdsz151", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z151_init, NULL }, { "[8088] Zenith Data Systems Z-159", "zdsz159", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z159_init, NULL }, @@ -148,7 +102,6 @@ const machine_t machines[] = { { "[8086] Amstrad PPC512/640", "ppc512", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, { "[8086] Compaq Deskpro", "deskpro", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_deskpro_init, NULL }, { "[8086] Olivetti M21/24/24SP", "m24", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_xt_m24_init, m24_get_device }, - /* Has Olivetti KBC firmware. */ { "[8086] Olivetti M240", "m240", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_m240_init, NULL }, { "[8086] Schetmash Iskra-3104", "iskra3104", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_iskra3104_init, NULL }, { "[8086] Tandy 1000 SL/2", "tandy1000sl2", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, tandy1k_sl_get_device }, @@ -158,710 +111,360 @@ const machine_t machines[] = { { "[8086] VTech Laser XT3", "lxt3", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, #endif + /* 286 XT machines */ +#if defined(DEV_BRANCH) && defined(USE_HEDAKA) + { "[Citygate D30 XT] Hedaka HED-919", "hed919", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 1024, 64, 0, machine_xt_hed919_init, NULL }, +#endif + /* 286 AT machines */ - /* Has IBM AT KBC firmware. */ { "[ISA] IBM AT", "ibmat", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibm_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/1 model 2011", "ibmps1es", MACHINE_TYPE_286, CPU_PKG_286, 0, 10000000, 10000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 512, 16384, 512, 63, machine_ps1_m2011_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 1024, 16384,1024, 127, machine_ps2_m30_286_init, NULL }, - /* Has IBM AT KBC firmware. */ { "[ISA] IBM XT Model 286", "ibmxt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 6000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 127, machine_at_ibmxt286_init, NULL }, - /* AMI BIOS for a chipset-less machine, most likely has AMI 'F' KBC firmware. */ { "[ISA] AMI IBM AT", "ibmatami", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatami_init, NULL }, - /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to the - IBM AT KBC firmware unless evidence emerges of any proprietary commands. */ { "[ISA] Commodore PC 30 III", "cmdpc30", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_cmdpc_init, NULL }, - /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable II", "portableii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_portableii_init, NULL }, - /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III", "portableiii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 640, 16384, 128, 127, machine_at_portableiii_init, at_cpqiii_get_device }, - /* Has IBM AT KBC firmware. */ { "[ISA] MR 286 clone", "mr286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_mr286_init, NULL }, - /* Has IBM AT KBC firmware. */ { "[ISA] NCR PC8/810/710/3390/3392", "pc8", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_pc8_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_OLIVETTI) - /* Has Olivetti KBC firmware. */ { "[ISA] Olivetti M290", "m290", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_m290_init, NULL }, #endif -#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) - /* Has IBM AT KBC firmware. */ + #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) { "[ISA] OpenAT", "openat", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_openat_init, NULL }, #endif - /* Has IBM AT KBC firmware. */ { "[ISA] Phoenix IBM AT", "ibmatpx", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatpx_init, NULL }, - /* Has Quadtel KBC firmware. */ { "[ISA] Quadtel IBM AT", "ibmatquadtel", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, - /* This has a Siemens proprietary KBC which is completely undocumented. */ { "[ISA] Siemens PCD-2L", "siemens", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_siemens_init, NULL }, - /* This has Toshiba's proprietary KBC, which is already implemented. */ { "[ISA] Toshiba T3100e", "t3100e", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO_FIXED, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, - /* Has Quadtel KBC firmware. */ { "[GC103] Quadtel 286 clone", "quadt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_quadt286_init, NULL }, - /* Most likely has AMI 'F' KBC firmware. */ { "[GC103] Trigem 286M", "tg286m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, - /* This has "AMI KEYBOARD BIOS", most likely 'F'. */ - { "[NEAT] Dataexpert 286", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, - /* Has IBM AT KBC firmware. */ + { "[NEAT] AMI 286 clone", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, { "[NEAT] NCR 3302", "3302", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 512, 16384, 128, 127, machine_at_3302_init, NULL }, - /* Has IBM AT KBC firmware. */ { "[NEAT] Phoenix 286 clone", "px286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_px286_init, NULL }, - /* Has Chips & Technologies KBC firmware. */ + { "[SCAT] Award 286 clone", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, { "[SCAT] GW-286CT GEAR", "gw286ct", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_gw286ct_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Goldstar GDC-212M", "gdc212m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2, 512, 4096, 512, 127, machine_at_gdc212m_init, NULL }, - /* Has a VIA VT82C42N KBC. */ - { "[SCAT] Hyundai Solomon 286KP", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, - /* Has a VIA VT82C42N KBC. */ { "[SCAT] Hyundai Super-286TR", "super286tr", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_super286tr_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4200P", "spc4200p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4216P", "spc4216p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 1024, 5120,1024, 127, machine_at_spc4216p_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4620P", "spc4620p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 5120,1024, 127, machine_at_spc4620p_init, NULL }, - /* Has IBM AT KBC firmware. */ { "[SCAT] Samsung Deskmaster 286", "deskmaster286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_deskmaster286_init, NULL }, /* 286 machines that utilize the MCA bus */ - /* Has IBM PS/2 Type 2 KBC firmware. */ { "[MCA] IBM PS/2 model 50", "ibmps2_m50", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 10240,1024, 63, machine_ps2_model_50_init, NULL }, /* 386SX machines */ - /* ISA slots available because an official IBM expansion for that existed. */ - /* Has IBM PS/2 Type 1 KBC firmware. */ - { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, - /* Has IBM AT KBC firmware. */ - { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, - /* Has Quadtel KBC firmware. */ - { "[ISA] QTC-SXM KT X20T02/HI", "quadt386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_quadt386sx_init, NULL }, + { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO_FIXED, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, + { "[ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, + { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_M6117) - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser AR-B1375", "arb1375", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_arb1375_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, #endif - /* Has an AMI KBC firmware, the only photo of this is too low resolution - for me to read what's on the KBC chip, so I'm going to assume AMI 'F' - based on the other known HT18 AMI BIOS strings. */ - { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, - /* Has an AMI KBC firmware, the only photo of this is too low resolution - for me to read what's on the KBC chip, so I'm going to assume AMI 'F' - based on the other known HT18 AMI BIOS strings. */ + { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, { "[HT18] AMA-932J", "ama932j", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, - /* Has an unknown KBC firmware with commands B8 and BB in the style of - Phoenix MultiKey and AMIKey-3(!), but also commands E1 and EA with - unknown functions. */ - { "[Intel 82335 ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, - /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ + { "[Intel 82335] ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, { "[Intel 82335] Shuttle 386SX", "shuttle386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_shuttle386sx_init, NULL }, - /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to - the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any - proprietary commands. */ { "[NEAT] Commodore SL386SX-16", "cmdsl386sx16", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 8192, 512, 127, machine_at_cmdsl386sx16_init, NULL }, - /* Has IBM AT KBC firmware. */ { "[NEAT] DTK 386SX clone", "dtk386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_init, NULL }, - /* Has IBM AT KBC firmware. */ + { "[OPTi 283] Olivetti M300-08", "m30008", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 20000000, 20000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30008_init, at_m30008_get_device }, + { "[OPTi 283] Olivetti M300-15", "m30015", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 25000000, 25000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30015_init, NULL }, { "[OPTi 291] DTK PPM-3333P", "awardsx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_awardsx_init, NULL }, - /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to - the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any - proprietary commands. */ { "[SCAMP] Commodore SL386SX-25", "cmdsl386sx25", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 8192, 512, 127, machine_at_cmdsl386sx25_init, at_cmdsl386sx25_get_device }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAMP] Samsung SPC-6033P", "spc6033p", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 12288, 2048, 127, machine_at_spc6033p_init, at_spc6033p_get_device }, - /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a - photo or real hardware BIOS string is found. */ { "[SCAT] KMX-C-02", "kmxc02", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 512, 127, machine_at_kmxc02_init, NULL }, - /* Has Quadtel KBC firmware. */ { "[WD76C10] Amstrad MegaPC", "megapc", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_wd76c10_init, NULL }, /* 386SX machines which utilize the MCA bus */ - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 8192, 1024, 63, machine_ps2_model_55sx_init, NULL }, - /* 486SLC machines */ - /* 486SLC machines with just the ISA slot */ - /* Has AMIKey H KBC firmware. */ - { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486SLC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, - /* 386DX machines */ { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_acc386_init, NULL }, - /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_ecs386_init, NULL }, { "[C&T 386] Samsung SPC-6000A", "spc6000a", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_spc6000a_init, NULL }, - /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 1024, 14336, 1024, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, - /* Has IBM AT KBC firmware. */ - { "[ISA] Micronics 09-00021", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, - /* Has AMIKey F KBC firmware. */ - { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 32768, 1024, 127, machine_at_asus386_init, NULL }, + { "[ISA] Micronics 386 clone", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, + { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, /* 386DX machines which utilize the MCA bus */ - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 16384, 2048, 63, machine_ps2_model_70_type3_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 80", "ibmps2_m80", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 12288, 1024, 63, machine_ps2_model_80_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 80 (type 3)", "ibmps2_m80_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 12288, 2048, 63, machine_ps2_model_80_axx_init, NULL }, /* 386DX/486 machines */ - /* The BIOS sends commands C9 without a parameter and D5, both of which are - Phoenix MultiKey commands. */ - { "[OPTi 495] Award 486 clone", "award495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, - /* Has AMIKey F KBC firmware. */ - { "[OPTi 495] Dataexpert SX495", "ami495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, - /* Has AMIKey F KBC firmware (it's just the MR BIOS for the above machine). */ - { "[OPTi 495] Dataexpert SX495 (MR BIOS)", "mr495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, + { "[OPTi 495] Award 486 clone", "award486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, + { "[OPTi 495] Dataexpert SX495 (486)", "ami486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, + { "[OPTi 495] MR 486 clone", "mr486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, /* 486 machines - Socket 1 */ - /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. - It also has those Ex commands also seen on the VIA VT82C42N (the BIOS - supposedly sends command EF. - The board was also seen in 2003 with a -H string - perhaps someone swapped - the KBC? */ { "[ALi M1429] Olystar LIL1429", "ali1429", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_ali1429_init, NULL }, - /* Has JetKey 5 KBC Firmware - but the BIOS string ends in a hardcoded -F, and - the BIOS also explicitly expects command A1 to return a 'F', so it looks like - the JetKey 5 is a clone of AMIKey type F. */ { "[CS4031] AMI 486 CS4031", "cs4031", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_cs4031_init, NULL }, - /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix - copyright. */ + { "[ETEQ ET6000] Olivetti PCS-46C", "pcs46c", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE | MACHINE_VIDEO, 4096, 32768, 4096, 127, machine_at_pcs46c_init, at_pcs46c_get_device }, { "[OPTi 895] Mylex MVI486", "mvi486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_mvi486_init, NULL }, - /* Has AMI KF KBC firmware. */ - { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, - /* Has AMIKey H KBC firmware, per the screenshot in "How computers & MS-DOS work". */ - { "[SiS 401] Chaintech 433SC", "sis401", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, - /* Has AMIKey F KBC firmware, per a photo of a monitor with the BIOS screen on - eBay. */ - { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, - /* Has a MR (!) KBC firmware, which is a clone of the standard IBM PS/2 KBC firmware. */ - { "[SiS 471] SiS VL-BUS 471 REV. A1", "px471", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, - /* The chip is a Lance LT38C41, a clone of the Intel 8041, and the BIOS sends - commands BC, BD, and C9 which exist on both AMIKey and Phoenix MultiKey/42, - but it does not write a byte after C9, which is consistent with AMIKey, so - this must have some form of AMIKey. */ { "[VIA VT82C495] FIC 486-VC-HD", "486vchd", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 64512, 1024, 127, machine_at_486vchd_init, NULL }, - /* According to Deksor on the Win3x.org forum, the BIOS string ends in a -0, - indicating an unknown KBC firmware. But it does send the AMIKey get version - command, so it must expect an AMIKey. */ { "[VLSI 82C480] HP Vectra 486VL", "vect486vl", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_vect486vl_init, at_vect486vl_get_device }, - /* Has a standard IBM PS/2 KBC firmware or a clone thereof. */ - { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, - - /* 486 machines - Socket 2 */ - /* 486 machines with just the ISA slot */ - /* Uses some variant of Phoenix MultiKey/42 as the BIOS sends keyboard controller - command C7 (OR input byte with received data byte). */ - { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, - /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V4.01H). */ - { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, - /* There are two similar BIOS strings with -H, and one with -U, so I'm going to - give it an AMIKey H KBC firmware. */ - { "[ALi M1429G] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, - /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ - { "[SiS 461] Acer V10", "acerv10", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_acerv10_init, NULL }, - /* The BIOS does not send any non-standard keyboard controller commands and wants - a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */ - { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, - /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an - 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. - The photo of the board shows an AMIKey KBC which is indeed F. */ - { "[SiS 471] ABit AB-AH4", "win471", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, + { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, /* 486 machines - Socket 3 */ /* 486 machines with just the ISA slot */ - /* Has AMI MegaKey KBC firmware. */ - { "[Contaq 82C597] Green-B", "green-b", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_green_b_init, NULL }, - /* Has a VIA VT82C42N KBC. */ + { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, + { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, + { "[ALi M1429] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, { "[OPTi 895] Jetway J-403TG", "403tg", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_init, NULL }, - /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ - { "[OPTi 895] Jetway J-403TG Rev D", "403tg_rev_d", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_init, NULL }, - /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ - { "[OPTi 895] Jetway J-403TG Rev D (MR BIOS)","403tg_rev_d_mr", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_mr_init, NULL }, - /* Has AMIKey H keyboard BIOS. */ + { "[SiS 401] AMI 486 Clone", "sis401", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, + { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, + { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, + { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, + { "[SiS 471] AMI 486 Clone", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, + { "[SiS 471] AMI WinBIOS 486 clone", "win471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, { "[SiS 471] AOpen Vi15G", "vi15g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_vi15g_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ - { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, - /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, - /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ - { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, + { "[SiS 471] Phoenix SiS 471", "px471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, /* 486 machines which utilize the PCI bus */ - /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT - KBC. */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, - /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT - KBC. - The BIOS string always ends in -U, but the BIOS will send AMIKey commands 0xCA - and 0xCB if command 0xA1 returns a letter in the 0x5x or 0x7x ranges, so I'm - going to give it an AMI 'U' KBC. */ { "[ALi M1489] AMI WinBIOS 486 PCI", "win486pci", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_win486pci_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_486ap4_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. */ - { "[i420EX] Intel Classic/PCI ED", "ninja", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_ninja_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. Also has a - SST 29EE010 Flash chip. */ { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3g_init, NULL }, - /* I'm going to assume this as an AMIKey-2 like the other two 486SP3's. */ { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. */ { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] Lucky Star LS-486E", "ls486e", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ls486e_init, NULL }, - /* The BIOS does not send a single non-standard KBC command, so it has a standard PS/2 KBC. */ { "[SiS 496] Micronics M4Li", "m4li", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_m4li_init, NULL }, - /* Has a BestKey KBC which clones AMI type 'H'. */ { "[SiS 496] Rise Computer R418", "r418", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_r418_init, NULL }, - /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it - must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[SiS 496] Soyo 4SA2", "4sa2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4sa2_init, NULL }, - /* According to MrKsoft, his real 4DPS has an AMIKey-2, which is an updated version - of type 'H'. */ { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, - /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ - { "[VIA VT82C496G] DFI G486VPA", "g486vpa", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_g486vpa_init, NULL }, - /* Has a VIA VT82C42N KBC. */ + { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, + { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, + { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, { "[VIA VT82C496G] FIC VIP-IO2", "486vipio2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_486vipio2_init, NULL }, /* 486 machines - Miscellaneous */ + /* 486 machines with just the ISA slot */ + { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486_MISC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, + /* 486 machines which utilize the PCI bus */ - /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[STPC Client] ITOX STAR", "itoxstar", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 75000000, 0, 0, 1.0, 1.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_itoxstar_init, NULL }, - /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[STPC Consumer-II] Acrosser AR-B1479", "arb1479", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 163840, 8192, 255, machine_at_arb1479_init, NULL }, - /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[STPC Elite] Advantech PCM-9340", "pcm9340", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 98304, 8192, 255, machine_at_pcm9340_init, NULL }, - /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[STPC Atlas] AAEON PCM-5330", "pcm5330", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 131072,32768, 255, machine_at_pcm5330_init, NULL }, /* Socket 4 machines */ /* 430LX */ - /* Has AMIKey F KBC firmware (AMIKey). */ { "[i430LX] ASUS P/I-P5MP3", "p5mp3", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 196608, 2048, 127, machine_at_p5mp3_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell Dimension XPS P60", "dellxp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 131072, 2048, 127, machine_at_dellxp60_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell OptiPlex 560/L", "opti560l", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_opti560l_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. - This is basically an Intel Batman (*NOT* Batman's Revenge) with a fancier - POST screen */ { "[i430LX] AMBRA DP60 PCI", "ambradp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp60_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] IBM PS/ValuePoint P60", "valuepointp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_valuepointp60_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. */ - { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_revenge_init, NULL }, - /* Has AMI MegaKey KBC firmware. */ + { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_batman_init, NULL }, { "[i430LX] Micro Star 586MC1", "586mc1", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_586mc1_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. */ { "[i430LX] Packard Bell PB520R", "pb520r", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 139264, 2048, 127, machine_at_pb520r_init, at_pb520r_get_device }, /* OPTi 596/597 */ - /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the - PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF - (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_VLB | MACHINE_IDE, 2048, 65536, 2048, 127, machine_at_excalibur_init, NULL }, - /* OPTi 596/597/822 */ - /* This has AMIKey 'F' KBC firmware. */ - { "[OPTi 597] Supermicro P5VL-PCI", "p5vl", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p5vl_init, NULL }, - /* SiS 85C50x */ - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, /* Socket 5 machines */ /* 430NX */ - /* This has the Phoenix MultiKey KBC firmware. */ { "[i430NX] Intel Premiere/PCI II", "plato", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_plato_init, NULL }, - /* This has the Phoenix MultiKey KBC firmware. - This is basically an Intel Premiere/PCI II with a fancier POST screen. */ { "[i430NX] AMBRA DP90 PCI", "ambradp90", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp90_init, NULL }, - /* Has AMI MegaKey KBC firmware. */ { "[i430NX] Gigabyte GA-586IP", "430nx", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_430nx_init, NULL }, /* 430FX */ - /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V5.0). */ { "[i430FX] Acer V30", "acerv30", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_acerv30_init, NULL }, - /* Has AMIKey F KBC firmware. */ { "[i430FX] AMI Apollo", "apollo", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_apollo_init, NULL }, - /* Has AMIKey H KBC firmware. */ - { "[i430FX] Dataexpert EXP8551", "exp8551", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_exp8551_init, NULL }, - /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O - chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 511, machine_at_vectra54_init, at_vectra54_get_device }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ZP", "zappa", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_zappa_init, NULL }, - /* The BIOS sends KBC command B3 which indicates an AMI (or VIA VT82C42N) KBC. */ { "[i430FX] NEC PowerMate V", "powermatev", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_powermatev_init, NULL }, - /* Has a VIA VT82C42N KBC. */ { "[i430FX] PC Partner MB500N", "mb500n", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb500n_init, NULL }, - /* Has AMIKey Z(!) KBC firmware. */ - { "[i430FX] Trigem Hawk", "hawk", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_hawk_init, NULL }, /* OPTi 596/597 */ - /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the - PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF - (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] TMC PAT54PV", "pat54pv", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_VLB, 2048, 65536, 2048, 127, machine_at_pat54pv_init, NULL }, /* OPTi 596/597/822 */ { "[OPTi 597] Shuttle HOT-543", "hot543", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_hot543_init, NULL }, + { "[OPTi 597] Supermicro P54VL-PCI", "p54vl", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p54vl_init, NULL }, /* SiS 85C50x */ - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P54SP4", "p54sp4", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54sp4_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] BCM SQ-588", "sq588", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_PENTIUMMMX), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_sq588_init, NULL }, + /* UMC 889x */ + { "[UMC 889x] Shuttle HOT-539", "hot539", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3600, 1.5, 2.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_hot539_init, NULL }, + /* Socket 7 (Single Voltage) machines */ /* 430FX */ - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54tp4xe_init, NULL }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE (MR BIOS)", "mr586", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mr586_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_gw2katx_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_thor_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/EV", "endeavor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_endeavor_init, at_endeavor_get_device }, - /* This has an AMIKey-2, which is an updated version of type 'H'. */ - { "[i430FX] MSI MS-5119", "ms5119", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ms5119_init, NULL }, - /* This most likely uses AMI MegaKey KBC firmware as well due to having the same - Super I/O chip (that has the KBC firmware on it) as eg. the Advanced/EV. */ { "[i430FX] Packard Bell PB640", "pb640", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_pb640_init, at_pb640_get_device }, - /* Has an AMI 'H' KBC firmware (1992). */ - { "[i430FX] QDI FMB", "fmb", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_fmb_init, NULL }, + { "[i430FX] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_chariot_init, NULL }, /* 430HX */ - /* I can't determine what KBC firmware this has, but given that the Acer V35N and - V60 have Phoenix MultiKey KBC firmware on the chip, I'm going to assume so - does the M3A. */ { "[i430HX] Acer M3A", "acerm3a", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerm3a_init, NULL }, - /* Has AMIKey F KBC firmware. */ { "[i430HX] AOpen AP53", "ap53", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3450, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap53_init, NULL }, - /* [TEST] Has a VIA 82C42N KBC, with AMIKey F KBC firmware. */ { "[i430HX] Biostar MB-8500TUC", "8500tuc", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_8500tuc_init, NULL }, - /* [TEST] Unable to determine what KBC this has. A list on a Danish site shows - the BIOS as having a -0 string, indicating non-AMI KBC firmware. */ { "[i430HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_p55t2s_init, NULL }, /* 430VX */ - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Gateway 2000 Tigereye", "gw2kte", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_gw2kte_init, NULL }, /* SiS 5511 */ - /* Has AMIKey H KBC firmware (AMIKey-2). */ - { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, + { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, /* Socket 7 (Dual Voltage) machines */ /* 430HX */ - /* Has SST flash and the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Acer V35N", "acerv35n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_Cx6x86MX), 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerv35n_init, NULL }, - /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_p55t2p4_init, NULL }, - /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Micronics M7S-Hi", "m7shi", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 511, machine_at_m7shi_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Intel TC430HX", "tc430hx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_tc430hx_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Toshiba Equium 5200D", "equium5200", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_equium5200_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . - Yes, this is an Intel AMI BIOS with a fancy splash screen. */ { "[i430HX] Sony Vaio PCV-240", "pcv240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_pcv240_init, NULL }, - /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p65up5_cp55t2d_init, NULL }, /* 430VX */ - /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55tvp4_init, NULL }, - /* The BIOS does not send a single non-standard KBC command, so it must have a standard IBM - PS/2 KBC firmware or a clone thereof. */ { "[i430VX] Azza 5IVG", "5ivg", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_5ivg_init, NULL }, - /* [TEST] Has AMIKey 'F' KBC firmware. */ { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_8500tvxa_init, NULL }, - /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O - chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430VX] Compaq Presario 2240", "presario2240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario2240_init, NULL }, - /* This most likely has AMI MegaKey as above. */ { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario4500_init, NULL }, - /* The BIOS sends KBC command CB which is an AMI KBC command, so it has an AMI KBC firmware. */ { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55va_init, NULL }, - /* The BIOS does not send a single non-standard KBC command. */ { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL }, - /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it - likely clones the behavior of AMIKey 'H'. */ { "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL }, - /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it - must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, /* 430TX */ - /* The BIOS sends KBC command B8, CA, and CB, so it has an AMI KBC firmware. */ { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL }, - /* This has the AMIKey KBC firmware, which is an updated 'F' type (YM430TX is based on the TX97). */ { "[i430TX] ASUS TX97", "tx97", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_tx97_init, NULL }, #if defined(DEV_BRANCH) && defined(NO_SIO) - /* This has the Phoenix MultiKey KBC firmware. */ { "[i430TX] Intel AN430TX", "an430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_an430tx_init, NULL }, #endif - /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ { "[i430TX] Intel YM430TX", "ym430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ym430tx_init, NULL }, - /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. */ { "[i430TX] PC Partner MB540N", "mb540n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2700, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_mb540n_init, NULL }, - /* [TEST] Has AMIKey 'H' KBC firmware. */ { "[i430TX] SuperMicro Super P5MMS98", "p5mms98", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_p5mms98_init, NULL }, /* Apollo VPX */ - /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA VPX] FIC VA-502", "ficva502", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ficva502_init, NULL }, /* Apollo VP3 */ - /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA VP3] FIC PA-2012", "ficpa2012", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 55000000, 75000000, 2100, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_ficpa2012_init, NULL }, /* SiS 5571 */ - /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] Rise R534F", "r534f", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 127, machine_at_r534f_init, NULL }, - /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] MSI MS-5146", "ms5146", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_ms5146_init, NULL }, + /* SiS 5598 */ + { "[SiS 5598] ASUS SP97-XV", "sp97xv", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3200, 1.5, 2.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_sp97xv_init, NULL }, + { "[SiS 5598] PC Chips M571", "m571", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3500, 1.5, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m571_init, NULL }, + /* ALi ALADDiN IV */ - /* Has the ALi M1543 southbridge with on-chip KBC. */ +#if defined(DEV_BRANCH) && defined(USE_M154X) { "[ALi ALADDiN IV] PC Chips M560", "m560", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m560_init, NULL }, - /* Has the ALi M1543 southbridge with on-chip KBC. */ { "[ALi ALADDiN IV] MSI MS-5164", "ms5164", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ms5164_init, NULL }, +#endif /* Super Socket 7 machines */ - /* ALi ALADDiN V */ - /* Has the ALi M1543C southbridge with on-chip KBC. */ - { "[ALi ALADDiN V] ASUS P5A", "p5a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_p5a_init, NULL }, - /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge - with on-chip KBC. */ - { "[ALi ALADDiN V] PC Chips M579", "m579", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m579_init, NULL }, - /* Has the ALi M1543C southbridge with on-chip KBC. */ - { "[ALi ALADDiN V] Gigabyte GA-5AA", "ga-5aa", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5aa_init, NULL }, - /* Has the ALi M1543C southbridge with on-chip KBC. */ - { "[ALi ALADDiN V] Gigabyte GA-5AX", "ga-5ax", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5ax_init, NULL }, - /* Apollo MVP3 */ - /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA MVP3] AOpen AX59 Pro", "ax59pro", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1300, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_ax59pro_init, NULL }, - /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA MVP3] FIC VA-503+", "ficva503p", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_mvp3_init, NULL }, - /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA MVP3] FIC VA-503A", "ficva503a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1800, 3100, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ficva503a_init, NULL }, /* Socket 8 machines */ /* 450KX */ #if defined(DEV_BRANCH) && defined(USE_I450KX) - /* This has an AMIKey, which is an updated version of type 'F'. */ { "[i450KX] ASUS P/I-P6RP4", "p6rp4", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p6rp4_init, NULL }, #endif /* 440FX */ - /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Acer V60N", "v60n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2500, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_v60n_init, NULL }, - /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-P6ND)", "p65up5_cp6nd", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cp6nd_init, NULL }, - /* The MB-8600TTX has an AMIKey 'F' KBC firmware, so I'm going to assume so does - the MB-8600TTC until someone can actually identify it. */ { "[i440FX] Biostar MB-8600TTC", "8600ttc", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 50000000, 66666667, 2900, 3300, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_8500ttc_init, NULL }, { "[i440FX] Gigabyte GA-686NX", "686nx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_686nx_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel AP440FX", "ap440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ap440fx_init, NULL }, - /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the - PC87306 Super I/O chip, command 0xA1 returns '5'. - Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel VS440FX", "vs440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_vs440fx_init, NULL }, - /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Micronics M6Mi", "m6mi", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2900, 3300, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_m6mi_init, NULL }, - /* I found a BIOS string of it that ends in -S, but it could be a typo for -5 - (there's quite a few AMI BIOS strings around with typo'd KBC codes), so I'm - going to give it an AMI MegaKey. */ { "[i440FX] PC Partner MB600N", "mb600n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_mb600n_init, NULL }, /* Slot 1 machines */ - /* ALi ALADDiN V */ - /* Has the ALi M1543C southbridge with on-chip KBC. */ - { "[ALi ALADDiN-PRO II] PC Chips M729", "m729", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m729_init, NULL }, - /* 440FX */ - /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-PKND)", "p65up5_cpknd", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cpknd_init, NULL }, - /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it - must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i440FX] ASUS KN97", "kn97", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 83333333, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_kn97_init, NULL }, /* 440LX */ - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440LX] ABIT LX6", "lx6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 100000000, 1500, 3500, 2.0, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_lx6_init, NULL }, - /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix - MultiKey KBC firmware. */ { "[i440LX] Micronics Spitfire", "spitfire", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_spitfire_init, NULL }, /* 440EX */ - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440EX] QDI EXCELLENT II", "p6i440e2", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 83333333, 1800, 3500, 3.0, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_p6i440e2_init, NULL }, /* 440BX */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] ASUS P2B-LS", "p2bls", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 112121212, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p2bls_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] ASUS P3B-F", "p3bf", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p3bf_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] ABIT BF6", "bf6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_bf6_init, NULL }, - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] AOpen AX6BC", "ax6bc", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ax6bc_init, NULL }, - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] Gigabyte GA-686BX", "686bx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_686bx_init, NULL }, - /* Has a SM(S)C FDC37M60x Super I/O chip with on-chip KBC with most likely - AMIKey-2 KBC firmware. */ { "[i440BX] HP Vectra VEi 8", "vei8", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vei8_init, NULL }, - /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC - with most likely AMIKey-2 KBC firmware. */ { "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_SOUND, 8192,1048576, 8192, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device }, - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] SuperMicro Super P6SBA", "p6sba", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_p6sba_init, NULL }, +#if defined(DEV_BRANCH) && defined(NO_SIO) + { "[i440BX] Fujitsu ErgoPro x365", "ergox365", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 511, machine_at_ergox365_init, NULL }, +#endif /* 440ZX */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440ZX] MSI MS-6168", "ms6168", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_ms6168_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440ZX] Packard Bell Bora Pro", "borapro", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_borapro_init, NULL }, /* SMSC VictoryBX-66 */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC6310BXII","atc6310bxii", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_atc6310bxii_init, NULL }, /* VIA Apollo Pro */ - /* Has the VIA VT82C596B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA Apollo Pro] FIC KA-6130", "ficka6130", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_ficka6130_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[VIA Apollo Pro133] ASUS P3V133", "p3v133", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p3v133_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[VIA Apollo Pro133A] ASUS P3V4X", "p3v4x", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,2097152, 8192, 255, machine_at_p3v4x_init, NULL }, /* Slot 1/2 machines */ /* 440GX */ - /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC - with most likely AMIKey-2 KBC firmware. */ { "[i440GX] Freeway FW-6400GX", "fw6400gx", MACHINE_TYPE_SLOT1_2, CPU_PKG_SLOT1 | CPU_PKG_SLOT2, 0, 100000000, 150000000, 1800, 3500, 3.0, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2080768,16384, 511, machine_at_fw6400gx_init, NULL }, /* Slot 2 machines */ /* 440GX */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440GX] Gigabyte GA-6GXU", "6gxu", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_6gxu_init, NULL }, - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440GX] SuperMicro Super S2DGE", "s2dge", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_s2dge_init, NULL }, /* PGA370 machines */ /* 440LX */ - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440LX] SuperMicro Super 370SLM", "s370slm", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_s370slm_init, NULL }, /* 440BX */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] AEWIN AW-O671R", "awo671r", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_awo671r_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] ASUS CUBX", "cubx", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_cubx_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] AmazePC AM-BX133", "ambx133", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ambx133_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] Tyan Trinity 371", "trinity371", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_trinity371_init, NULL }, /* 440ZX */ - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440ZX] Soltek SL-63A1", "63a", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_63a_init, NULL }, /* SMSC VictoryBX-66 */ - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC7020BXII","atc7020bxii", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_atc7020bxii_init, NULL }, /* VIA Apollo Pro */ - /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ { "[VIA Apollo Pro] PC Partner APAS3", "apas3", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_apas3_init, NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[VIA Apollo Pro133] ECS P6BAP", "p6bap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p6bap_init, NULL }, - /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[VIA Apollo Pro133A] AEWIN WCF-681", "wcf681", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_wcf681_init, NULL }, - /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ - { "[VIA Apollo Pro133A] ASUS CUV4X-LS", "cuv4xls", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,1572864, 8192, 255, machine_at_cuv4xls_init, NULL }, - /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA - VT82C42N. */ - { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, + { "[VIA Apollo Pro133A] ASUS CUV4X-LS", "cuv4xls", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_BUS_AC97 | MACHINE_IDE_DUAL,16384,1572864, 8192, 255, machine_at_cuv4xls_init, NULL }, + { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, + { "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL }, /* Miscellaneous/Fake/Hypervisor machines */ - /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL }, { NULL, NULL, MACHINE_TYPE_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } From 5b81bad4e89548f0ba6cd501fb6fc13691183e72 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:19:21 +0200 Subject: [PATCH 031/140] And a restoration. --- src/machine/m_at_sockets7.c | 172 ++++++++++++ src/machine/machine_table.c | 527 +++++++++++++++++++++++++++++++----- 2 files changed, 637 insertions(+), 62 deletions(-) diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index ca6c957e2..ba26fdb99 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -41,6 +41,178 @@ #include "cpu.h" #include <86box/machine.h> #include <86box/snd_ac97.h> +#include <86box/clock.h> + + +int +machine_at_p5a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5a/1011.005", + 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&w83781d_p5a_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + + return ret; +} + + +int +machine_at_m579_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m579/MS6260S_Socket7_ALi_M1542_AMI.BIN", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + +int +machine_at_ga_5aa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ga-5aa/GA-5AA.F7b", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + +int +machine_at_ga_5ax_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ga-5ax/5AX.F4", + 0x000e0000, 131072, 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(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + + +int +machine_at_ax59pro_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ax59pro/AX59P236.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, 1, 2, 0, 0); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&via_mvp3_device); + device_add(&via_vt82c586b_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877tf_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} int diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f8a4f3bb7..b6f7d86ec 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -39,10 +39,12 @@ const machine_type_t machine_types[] = { { "8086", MACHINE_TYPE_8086 }, { "80286", MACHINE_TYPE_286 }, { "i386SX", MACHINE_TYPE_386SX }, + { "486SLC", MACHINE_TYPE_486SLC }, { "i386DX", MACHINE_TYPE_386DX }, { "i386DX/i486", MACHINE_TYPE_386DX_486 }, { "i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, - { "i486 (Socket 2 and 3)", MACHINE_TYPE_486_S3 }, + { "i486 (Socket 2)", MACHINE_TYPE_486_S2 }, + { "i486 (Socket 3)", MACHINE_TYPE_486_S3 }, { "i486 (Miscellaneous)", MACHINE_TYPE_486_MISC }, { "Socket 4", MACHINE_TYPE_SOCKET4 }, { "Socket 5", MACHINE_TYPE_SOCKET5 }, @@ -58,6 +60,53 @@ const machine_type_t machine_types[] = { }; +/* Machines to add before machine freeze: + - Jetway J-403TG MR BIOS v2.02; + - Matsonic MS6260S (AMI Super Socket 7 with Aladdin V chipset); + - PCChips M773 (440BX + SMSC with AMI BIOS); + - Rise R418 (was removed on my end, has to be re-added); + - TMC Mycomp PCI54ST; + - Zeos Quadtel 486. + + NOTE: The AMI MegaKey tests were done on a real Intel Advanced/ATX + (thanks, MrKsoft for running my AMIKEY.COM on it), but the + technical specifications of the other Intel machines confirm + that the other boards also have the MegaKey. + + NOTE: The later (ie. not AMI Color) Intel AMI BIOS'es execute a + sequence of commands (B8, BA, BB) during one of the very first + phases of POST, in a way that is only valid on the AMIKey-3 + KBC firmware, that includes the Classic PCI/ED (Ninja) BIOS + which otherwise does not execute any AMI KBC commands, which + indicates that the sequence is a leftover of whatever AMI + BIOS (likely a laptop one since the AMIKey-3 is a laptop KBC + firmware!) Intel forked. + + NOTE: The VIA VT82C42N returns 0x46 ('F') in command 0xA1 (so it + emulates the AMI KF/AMIKey KBC firmware), and 0x42 ('B') in + command 0xAF. + The version on the VIA VT82C686B southbridge also returns + 'F' in command 0xA1, but 0x45 ('E') in command 0xAF. + The version on the VIA VT82C586B southbridge also returns + 'F' in command 0xA1, but 0x44 ('D') in command 0xAF. + The version on the VIA VT82C586A southbridge also returns + 'F' in command 0xA1, but 0x43 ('C') in command 0xAF. + + NOTE: The AMI MegaKey commands blanked in the technical reference + are CC and and C4, which are Set P14 High and Set P14 Low, + respectively. Also, AMI KBC command C1, mysteriously missing + from the technical references of AMI MegaKey and earlier, is + Write Input Port, same as on AMIKey-3. + + Machines to remove: + - Hedaka HED-919; + - A-Trend ATC-1415; + - ECS Elite UM8810PAIO; + - Shuttle HOT-433A; + - Azza 5IVG (if a more interesting machine with Prime3C is found). +*/ + + const machine_t machines[] = { /* 8088 Machines */ { "[8088] IBM PC (1981)", "ibmpc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 16, 64, 16, 0, machine_pc_init, NULL }, @@ -69,10 +118,10 @@ const machine_t machines[] = { { "[8088] AMI XT clone", "amixt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, { "[8088] Columbia Data Products MPC-1600", "mpc1600", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 512, 64, 0, machine_xt_mpc1600_init, NULL }, { "[8088] Compaq Portable", "portable", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_portable_init, NULL }, - { "[8088] DTK XT clone", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] DTK PIM-TB10-Z", "dtk", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, { "[8088] Eagle PC Spirit", "pcspirit", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pcspirit_init, NULL }, { "[8088] Generic XT clone", "genxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_genxt_init, NULL }, - { "[8088] Juko XT clone", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] Juko ST", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, { "[8088] Multitech PC-700", "pc700", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pc700_init, NULL }, { "[8088] NCR PC4i", "pc4i", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_pc4i_init, NULL }, { "[8088] Olivetti M19", "m19", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 4772728, 7159092, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 256, 640, 256, 0, machine_xt_m19_init, m19_get_device }, @@ -87,6 +136,7 @@ const machine_t machines[] = { #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", "ltxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, #endif + /* Has a standard PS/2 KBC (so, use IBM PS/2 Type 1). */ { "[8088] Xi8088", "xi8088", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, { "[8088] Zenith Data Systems Z-151/152/161","zdsz151", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z151_init, NULL }, { "[8088] Zenith Data Systems Z-159", "zdsz159", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_z159_init, NULL }, @@ -102,6 +152,7 @@ const machine_t machines[] = { { "[8086] Amstrad PPC512/640", "ppc512", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, { "[8086] Compaq Deskpro", "deskpro", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_compaq_deskpro_init, NULL }, { "[8086] Olivetti M21/24/24SP", "m24", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_xt_m24_init, m24_get_device }, + /* Has Olivetti KBC firmware. */ { "[8086] Olivetti M240", "m240", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_m240_init, NULL }, { "[8086] Schetmash Iskra-3104", "iskra3104", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 128, 0, machine_xt_iskra3104_init, NULL }, { "[8086] Tandy 1000 SL/2", "tandy1000sl2", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, tandy1k_sl_get_device }, @@ -111,360 +162,712 @@ const machine_t machines[] = { { "[8086] VTech Laser XT3", "lxt3", MACHINE_TYPE_8086, CPU_PKG_8086, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, #endif - /* 286 XT machines */ -#if defined(DEV_BRANCH) && defined(USE_HEDAKA) - { "[Citygate D30 XT] Hedaka HED-919", "hed919", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 1024, 64, 0, machine_xt_hed919_init, NULL }, -#endif - /* 286 AT machines */ + /* Has IBM AT KBC firmware. */ { "[ISA] IBM AT", "ibmat", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibm_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/1 model 2011", "ibmps1es", MACHINE_TYPE_286, CPU_PKG_286, 0, 10000000, 10000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 512, 16384, 512, 63, machine_ps1_m2011_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_XTA | MACHINE_VIDEO_FIXED, 1024, 16384,1024, 127, machine_ps2_m30_286_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[ISA] IBM XT Model 286", "ibmxt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 6000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 127, machine_at_ibmxt286_init, NULL }, + /* AMI BIOS for a chipset-less machine, most likely has AMI 'F' KBC firmware. */ { "[ISA] AMI IBM AT", "ibmatami", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatami_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to the + IBM AT KBC firmware unless evidence emerges of any proprietary commands. */ { "[ISA] Commodore PC 30 III", "cmdpc30", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_cmdpc_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable II", "portableii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_portableii_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III", "portableiii", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 640, 16384, 128, 127, machine_at_portableiii_init, at_cpqiii_get_device }, + /* Has IBM AT KBC firmware. */ { "[ISA] MR 286 clone", "mr286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_mr286_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[ISA] NCR PC8/810/710/3390/3392", "pc8", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_pc8_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_OLIVETTI) + /* Has Olivetti KBC firmware. */ { "[ISA] Olivetti M290", "m290", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 640, 16384, 128, 127, machine_at_m290_init, NULL }, #endif - #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + /* Has IBM AT KBC firmware. */ { "[ISA] OpenAT", "openat", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_openat_init, NULL }, #endif + /* Has IBM AT KBC firmware. */ { "[ISA] Phoenix IBM AT", "ibmatpx", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatpx_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[ISA] Quadtel IBM AT", "ibmatquadtel", MACHINE_TYPE_286, CPU_PKG_286, 0, 6000000, 8000000, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, + /* This has a Siemens proprietary KBC which is completely undocumented. */ { "[ISA] Siemens PCD-2L", "siemens", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 256, 15872, 128, 63, machine_at_siemens_init, NULL }, + /* This has Toshiba's proprietary KBC, which is already implemented. */ { "[ISA] Toshiba T3100e", "t3100e", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO_FIXED, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[GC103] Quadtel 286 clone", "quadt286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_quadt286_init, NULL }, + /* Most likely has AMI 'F' KBC firmware. */ { "[GC103] Trigem 286M", "tg286m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, - { "[NEAT] AMI 286 clone", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + /* This has "AMI KEYBOARD BIOS", most likely 'F'. */ + { "[NEAT] Dataexpert 286", "ami286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] NCR 3302", "3302", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_VIDEO, 512, 16384, 128, 127, machine_at_3302_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] Phoenix 286 clone", "px286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_px286_init, NULL }, - { "[SCAT] Award 286 clone", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, + /* Has Chips & Technologies KBC firmware. */ { "[SCAT] GW-286CT GEAR", "gw286ct", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 512, 16384, 128, 127, machine_at_gw286ct_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Goldstar GDC-212M", "gdc212m", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2, 512, 4096, 512, 127, machine_at_gdc212m_init, NULL }, + /* Has a VIA VT82C42N KBC. */ + { "[SCAT] Hyundai Solomon 286KP", "award286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_award286_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[SCAT] Hyundai Super-286TR", "super286tr", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_super286tr_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4200P", "spc4200p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4216P", "spc4216p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2, 1024, 5120,1024, 127, machine_at_spc4216p_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAT] Samsung SPC-4620P", "spc4620p", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 5120,1024, 127, machine_at_spc4620p_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[SCAT] Samsung Deskmaster 286", "deskmaster286", MACHINE_TYPE_286, CPU_PKG_286, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_deskmaster286_init, NULL }, /* 286 machines that utilize the MCA bus */ + /* Has IBM PS/2 Type 2 KBC firmware. */ { "[MCA] IBM PS/2 model 50", "ibmps2_m50", MACHINE_TYPE_286, CPU_PKG_286 | CPU_PKG_486SLC_IBM, 0, 10000000, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 10240,1024, 63, machine_ps2_model_50_init, NULL }, /* 386SX machines */ - { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO_FIXED, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, - { "[ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, - { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, + /* ISA slots available because an official IBM expansion for that existed. */ + /* Has IBM PS/2 Type 1 KBC firmware. */ + { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 6144,1024, 63, machine_ps1_m2121_init, NULL }, + /* Has IBM AT KBC firmware. */ + { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, + /* Has Quadtel KBC firmware. */ + { "[ISA] QTC-SXM KT X20T02/HI", "quadt386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_quadt386sx_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_M6117) + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser AR-B1375", "arb1375", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_arb1375_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, #endif - { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ + { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ { "[HT18] AMA-932J", "ama932j", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, - { "[Intel 82335] ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, + /* Has an unknown KBC firmware with commands B8 and BB in the style of + Phoenix MultiKey and AMIKey-3(!), but also commands E1 and EA with + unknown functions. */ + { "[Intel 82335 ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[Intel 82335] Shuttle 386SX", "shuttle386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_shuttle386sx_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ { "[NEAT] Commodore SL386SX-16", "cmdsl386sx16", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 8192, 512, 127, machine_at_cmdsl386sx16_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[NEAT] DTK 386SX clone", "dtk386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_init, NULL }, - { "[OPTi 283] Olivetti M300-08", "m30008", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 20000000, 20000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30008_init, at_m30008_get_device }, - { "[OPTi 283] Olivetti M300-15", "m30015", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 25000000, 25000000, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 16384, 2048, 127, machine_at_m30015_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[OPTi 291] DTK PPM-3333P", "awardsx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_awardsx_init, NULL }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ { "[SCAMP] Commodore SL386SX-25", "cmdsl386sx25", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 8192, 512, 127, machine_at_cmdsl386sx25_init, at_cmdsl386sx25_get_device }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAMP] Samsung SPC-6033P", "spc6033p", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 12288, 2048, 127, machine_at_spc6033p_init, at_spc6033p_get_device }, + /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a + photo or real hardware BIOS string is found. */ { "[SCAT] KMX-C-02", "kmxc02", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 512, 127, machine_at_kmxc02_init, NULL }, + /* Has Quadtel KBC firmware. */ { "[WD76C10] Amstrad MegaPC", "megapc", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_wd76c10_init, NULL }, /* 386SX machines which utilize the MCA bus */ + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 8192, 1024, 63, machine_ps2_model_55sx_init, NULL }, + /* 486SLC machines */ + /* 486SLC machines with just the ISA slot */ + /* Has AMIKey H KBC firmware. */ + { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486SLC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, + /* 386DX machines */ { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_acc386_init, NULL }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_ecs386_init, NULL }, { "[C&T 386] Samsung SPC-6000A", "spc6000a", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_spc6000a_init, NULL }, + /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 1024, 14336, 1024, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, - { "[ISA] Micronics 386 clone", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, - { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, + /* Has IBM AT KBC firmware. */ + { "[ISA] Micronics 09-00021", "micronics386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, + /* Has AMIKey F KBC firmware. */ + { "[SiS 310] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 32768, 1024, 127, machine_at_asus386_init, NULL }, /* 386DX machines which utilize the MCA bus */ + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 16384, 2048, 63, machine_ps2_model_70_type3_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 80", "ibmps2_m80", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 1024, 12288, 1024, 63, machine_ps2_model_80_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[MCA] IBM PS/2 model 80 (type 3)", "ibmps2_m80_type3", MACHINE_TYPE_386DX, CPU_PKG_386DX | CPU_PKG_486BL, 0, 0, 0, 0, 0, 0, 0, MACHINE_MCA | MACHINE_BUS_PS2 | MACHINE_VIDEO, 2048, 12288, 2048, 63, machine_ps2_model_80_axx_init, NULL }, /* 386DX/486 machines */ - { "[OPTi 495] Award 486 clone", "award486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, - { "[OPTi 495] Dataexpert SX495 (486)", "ami486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, - { "[OPTi 495] MR 486 clone", "mr486", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, + /* The BIOS sends commands C9 without a parameter and D5, both of which are + Phoenix MultiKey commands. */ + { "[OPTi 495] Award 486 clone", "award495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_init, NULL }, + /* Has AMIKey F KBC firmware. */ + { "[OPTi 495] Dataexpert SX495", "ami495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_ami_init, NULL }, + /* Has AMIKey F KBC firmware (it's just the MR BIOS for the above machine). */ + { "[OPTi 495] Dataexpert SX495 (MR BIOS)", "mr495", MACHINE_TYPE_386DX_486, CPU_PKG_386DX | CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_opti495_mr_init, NULL }, /* 486 machines - Socket 1 */ + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. + It also has those Ex commands also seen on the VIA VT82C42N (the BIOS + supposedly sends command EF. + The board was also seen in 2003 with a -H string - perhaps someone swapped + the KBC? */ { "[ALi M1429] Olystar LIL1429", "ali1429", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_ali1429_init, NULL }, + /* Has JetKey 5 KBC Firmware - but the BIOS string ends in a hardcoded -F, and + the BIOS also explicitly expects command A1 to return a 'F', so it looks like + the JetKey 5 is a clone of AMIKey type F. */ { "[CS4031] AMI 486 CS4031", "cs4031", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_cs4031_init, NULL }, - { "[ETEQ ET6000] Olivetti PCS-46C", "pcs46c", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE | MACHINE_VIDEO, 4096, 32768, 4096, 127, machine_at_pcs46c_init, at_pcs46c_get_device }, + /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix + copyright. */ { "[OPTi 895] Mylex MVI486", "mvi486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_mvi486_init, NULL }, + /* Has AMI KF KBC firmware. */ + { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, + /* Has AMIKey H KBC firmware, per the screenshot in "How computers & MS-DOS work". */ + { "[SiS 401] Chaintech 433SC", "sis401", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, + /* Has AMIKey F KBC firmware, per a photo of a monitor with the BIOS screen on + eBay. */ + { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, + /* Has a MR (!) KBC firmware, which is a clone of the standard IBM PS/2 KBC firmware. */ + { "[SiS 471] SiS VL-BUS 471 REV. A1", "px471", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, + /* The chip is a Lance LT38C41, a clone of the Intel 8041, and the BIOS sends + commands BC, BD, and C9 which exist on both AMIKey and Phoenix MultiKey/42, + but it does not write a byte after C9, which is consistent with AMIKey, so + this must have some form of AMIKey. */ { "[VIA VT82C495] FIC 486-VC-HD", "486vchd", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 64512, 1024, 127, machine_at_486vchd_init, NULL }, + /* According to Deksor on the Win3x.org forum, the BIOS string ends in a -0, + indicating an unknown KBC firmware. But it does send the AMIKey get version + command, so it must expect an AMIKey. */ { "[VLSI 82C480] HP Vectra 486VL", "vect486vl", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_vect486vl_init, at_vect486vl_get_device }, - { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, + /* Has a standard IBM PS/2 KBC firmware or a clone thereof. */ + { "[VLSI 82C481] Siemens Nixdorf D824", "d824", MACHINE_TYPE_486, CPU_PKG_SOCKET1, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 32768, 2048, 127, machine_at_d824_init, at_d824_get_device }, + + /* 486 machines - Socket 2 */ + /* 486 machines with just the ISA slot */ + /* Uses some variant of Phoenix MultiKey/42 as the BIOS sends keyboard controller + command C7 (OR input byte with received data byte). */ + { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V4.01H). */ + { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, + /* There are two similar BIOS strings with -H, and one with -U, so I'm going to + give it an AMIKey H KBC firmware. */ + { "[ALi M1429G] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, + /* Uses an Intel KBC with Phoenix MultiKey KBC firmware. */ + { "[SiS 461] DEC DECpc LPV", "decpc_lpv", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_decpc_lpv_init, NULL }, + /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ + { "[SiS 461] Acer V10", "acerv10", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_acerv10_init, NULL }, + /* The BIOS does not send any non-standard keyboard controller commands and wants + a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */ + { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, + /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an + 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. + The photo of the board shows an AMIKey KBC which is indeed F. */ + { "[SiS 471] ABit AB-AH4", "win471", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, /* 486 machines - Socket 3 */ /* 486 machines with just the ISA slot */ - { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_pb410a_init, NULL }, - { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, - { "[ALi M1429] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, + /* Has AMI MegaKey KBC firmware. */ + { "[Contaq 82C597] Green-B", "green-b", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_green_b_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[OPTi 895] Jetway J-403TG", "403tg", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_init, NULL }, - { "[SiS 401] AMI 486 Clone", "sis401", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_sis401_init, NULL }, - { "[SiS 401] ASUS ISA-486", "isa486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_isa486_init, NULL }, - { "[SiS 460] ABIT AV4", "av4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_av4_init, NULL }, - { "[SiS 461] IBM PS/ValuePoint 433DX/Si", "valuepoint433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 65536, 1024, 127, machine_at_valuepoint433_init, NULL }, - { "[SiS 471] AMI 486 Clone", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, - { "[SiS 471] AMI WinBIOS 486 clone", "win471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { "[OPTi 895] Jetway J-403TG Rev D", "403tg_rev_d", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { "[OPTi 895] Jetway J-403TG Rev D (MR BIOS)","403tg_rev_d_mr", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB, 1024, 65536, 1024, 127, machine_at_403tg_rev_d_mr_init, NULL }, + /* Has AMIKey H keyboard BIOS. */ { "[SiS 471] AOpen Vi15G", "vi15g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_vi15g_init, NULL }, - { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, - { "[SiS 471] Phoenix SiS 471", "px471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, + /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ + { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, /* 486 machines which utilize the PCI bus */ + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. + The BIOS string always ends in -U, but the BIOS will send AMIKey commands 0xCA + and 0xCB if command 0xA1 returns a letter in the 0x5x or 0x7x ranges, so I'm + going to give it an AMI 'U' KBC. */ { "[ALi M1489] AMI WinBIOS 486 PCI", "win486pci", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_win486pci_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_486ap4_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { "[i420EX] Intel Classic/PCI ED", "ninja", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_ninja_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. Also has a + SST 29EE010 Flash chip. */ { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3g_init, NULL }, + /* I'm going to assume this as an AMIKey-2 like the other two 486SP3's. */ { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] Lucky Star LS-486E", "ls486e", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ls486e_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, so it has a standard PS/2 KBC. */ { "[SiS 496] Micronics M4Li", "m4li", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_m4li_init, NULL }, + /* Has a BestKey KBC which clones AMI type 'H'. */ { "[SiS 496] Rise Computer R418", "r418", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_r418_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[SiS 496] Soyo 4SA2", "4sa2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4sa2_init, NULL }, + /* According to MrKsoft, his real 4DPS has an AMIKey-2, which is an updated version + of type 'H'. */ { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, - { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, - { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, - { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, + /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ + { "[VIA VT82C496G] DFI G486VPA", "g486vpa", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_g486vpa_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[VIA VT82C496G] FIC VIP-IO2", "486vipio2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_486vipio2_init, NULL }, /* 486 machines - Miscellaneous */ - /* 486 machines with just the ISA slot */ - { "[OPTi 283] RYC Leopard LX", "rycleopardlx", MACHINE_TYPE_486_MISC, CPU_PKG_486SLC_IBM, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_rycleopardlx_init, NULL }, - /* 486 machines which utilize the PCI bus */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Client] ITOX STAR", "itoxstar", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 75000000, 0, 0, 1.0, 1.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_itoxstar_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Consumer-II] Acrosser AR-B1479", "arb1479", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 163840, 8192, 255, machine_at_arb1479_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Elite] Advantech PCM-9340", "pcm9340", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 98304, 8192, 255, machine_at_pcm9340_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[STPC Atlas] AAEON PCM-5330", "pcm5330", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 131072,32768, 255, machine_at_pcm5330_init, NULL }, /* Socket 4 machines */ /* 430LX */ + /* Has AMIKey F KBC firmware (AMIKey). */ { "[i430LX] ASUS P/I-P5MP3", "p5mp3", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 196608, 2048, 127, machine_at_p5mp3_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell Dimension XPS P60", "dellxp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 131072, 2048, 127, machine_at_dellxp60_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] Dell OptiPlex 560/L", "opti560l", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_opti560l_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Batman (*NOT* Batman's Revenge) with a fancier + POST screen */ { "[i430LX] AMBRA DP60 PCI", "ambradp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp60_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ { "[i430LX] IBM PS/ValuePoint P60", "valuepointp60", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_valuepointp60_init, NULL }, - { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_batman_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_revenge_init, NULL }, + /* Has AMI MegaKey KBC firmware. */ { "[i430LX] Micro Star 586MC1", "586mc1", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_586mc1_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430LX] Packard Bell PB520R", "pb520r", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 139264, 2048, 127, machine_at_pb520r_init, at_pb520r_get_device }, /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_VLB | MACHINE_IDE, 2048, 65536, 2048, 127, machine_at_excalibur_init, NULL }, + /* OPTi 596/597/822 */ + /* This has AMIKey 'F' KBC firmware. */ + { "[OPTi 597] Supermicro P5VL-PCI", "p5vl", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p5vl_init, NULL }, + /* SiS 85C50x */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, /* Socket 5 machines */ /* 430NX */ + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430NX] Intel Premiere/PCI II", "plato", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_plato_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Premiere/PCI II with a fancier POST screen. */ { "[i430NX] AMBRA DP90 PCI", "ambradp90", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_ambradp90_init, NULL }, + /* Has AMI MegaKey KBC firmware. */ { "[i430NX] Gigabyte GA-586IP", "430nx", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_430nx_init, NULL }, /* 430FX */ + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V5.0). */ { "[i430FX] Acer V30", "acerv30", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_acerv30_init, NULL }, + /* Has AMIKey F KBC firmware. */ { "[i430FX] AMI Apollo", "apollo", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_apollo_init, NULL }, + /* Has AMIKey H KBC firmware. */ + { "[i430FX] Dataexpert EXP8551", "exp8551", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_exp8551_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 511, machine_at_vectra54_init, at_vectra54_get_device }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ZP", "zappa", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_zappa_init, NULL }, + /* The BIOS sends KBC command B3 which indicates an AMI (or VIA VT82C42N) KBC. */ { "[i430FX] NEC PowerMate V", "powermatev", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_powermatev_init, NULL }, + /* Has a VIA VT82C42N KBC. */ { "[i430FX] PC Partner MB500N", "mb500n", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb500n_init, NULL }, + /* Has AMIKey Z(!) KBC firmware. */ + { "[i430FX] Trigem Hawk", "hawk", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_hawk_init, NULL }, /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ { "[OPTi 597] TMC PAT54PV", "pat54pv", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_VLB, 2048, 65536, 2048, 127, machine_at_pat54pv_init, NULL }, /* OPTi 596/597/822 */ { "[OPTi 597] Shuttle HOT-543", "hot543", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_hot543_init, NULL }, - { "[OPTi 597] Supermicro P54VL-PCI", "p54vl", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p54vl_init, NULL }, /* SiS 85C50x */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] ASUS PCI/I-P54SP4", "p54sp4", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54sp4_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 85C50x] BCM SQ-588", "sq588", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_PENTIUMMMX), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_sq588_init, NULL }, - /* UMC 889x */ - { "[UMC 889x] Shuttle HOT-539", "hot539", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3600, 1.5, 2.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_hot539_init, NULL }, - /* Socket 7 (Single Voltage) machines */ /* 430FX */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54tp4xe_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i430FX] ASUS P/I-P54TP4XE (MR BIOS)", "mr586", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3600, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mr586_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_gw2katx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_thor_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430FX] Intel Advanced/EV", "endeavor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_endeavor_init, at_endeavor_get_device }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[i430FX] MSI MS-5119", "ms5119", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ms5119_init, NULL }, + /* This most likely uses AMI MegaKey KBC firmware as well due to having the same + Super I/O chip (that has the KBC firmware on it) as eg. the Advanced/EV. */ { "[i430FX] Packard Bell PB640", "pb640", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[i430FX] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_chariot_init, NULL }, + /* Has an AMI 'H' KBC firmware (1992). */ + { "[i430FX] QDI FMB", "fmb", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_fmb_init, NULL }, /* 430HX */ + /* I can't determine what KBC firmware this has, but given that the Acer V35N and + V60 have Phoenix MultiKey KBC firmware on the chip, I'm going to assume so + does the M3A. */ { "[i430HX] Acer M3A", "acerm3a", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerm3a_init, NULL }, + /* Has AMIKey F KBC firmware. */ { "[i430HX] AOpen AP53", "ap53", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3450, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap53_init, NULL }, + /* [TEST] Has a VIA 82C42N KBC, with AMIKey F KBC firmware. */ { "[i430HX] Biostar MB-8500TUC", "8500tuc", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_8500tuc_init, NULL }, + /* [TEST] Unable to determine what KBC this has. A list on a Danish site shows + the BIOS as having a -0 string, indicating non-AMI KBC firmware. */ { "[i430HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_p55t2s_init, NULL }, /* 430VX */ + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Gateway 2000 Tigereye", "gw2kte", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_gw2kte_init, NULL }, /* SiS 5511 */ - { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { "[SiS 5511] AOpen AP5S", "ap5s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ap5s_init, NULL }, /* Socket 7 (Dual Voltage) machines */ /* 430HX */ + /* Has SST flash and the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Acer V35N", "acerv35n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_Cx6x86MX), 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerv35n_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_p55t2p4_init, NULL }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i430HX] Micronics M7S-Hi", "m7shi", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 511, machine_at_m7shi_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Intel TC430HX", "tc430hx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_tc430hx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430HX] Toshiba Equium 5200D", "equium5200", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_equium5200_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . + Yes, this is an Intel AMI BIOS with a fancy splash screen. */ { "[i430HX] Sony Vaio PCV-240", "pcv240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_pcv240_init, NULL }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p65up5_cp55t2d_init, NULL }, /* 430VX */ + /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55tvp4_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, so it must have a standard IBM + PS/2 KBC firmware or a clone thereof. */ { "[i430VX] Azza 5IVG", "5ivg", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_5ivg_init, NULL }, + /* [TEST] Has AMIKey 'F' KBC firmware. */ { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_8500tvxa_init, NULL }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ { "[i430VX] Compaq Presario 2240", "presario2240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario2240_init, NULL }, + /* This most likely has AMI MegaKey as above. */ { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario4500_init, NULL }, + /* The BIOS sends KBC command CB which is an AMI KBC command, so it has an AMI KBC firmware. */ { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55va_init, NULL }, + /* The BIOS does not send a single non-standard KBC command. */ { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL }, + /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it + likely clones the behavior of AMIKey 'H'. */ { "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, /* 430TX */ + /* The BIOS sends KBC command B8, CA, and CB, so it has an AMI KBC firmware. */ { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL }, + /* This has the AMIKey KBC firmware, which is an updated 'F' type (YM430TX is based on the TX97). */ { "[i430TX] ASUS TX97", "tx97", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_tx97_init, NULL }, #if defined(DEV_BRANCH) && defined(NO_SIO) + /* This has the Phoenix MultiKey KBC firmware. */ { "[i430TX] Intel AN430TX", "an430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_an430tx_init, NULL }, #endif + /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ { "[i430TX] Intel YM430TX", "ym430tx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ym430tx_init, NULL }, + /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. */ { "[i430TX] PC Partner MB540N", "mb540n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2700, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_mb540n_init, NULL }, + /* [TEST] Has AMIKey 'H' KBC firmware. */ { "[i430TX] SuperMicro Super P5MMS98", "p5mms98", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_p5mms98_init, NULL }, /* Apollo VPX */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA VPX] FIC VA-502", "ficva502", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_ficva502_init, NULL }, /* Apollo VP3 */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA VP3] FIC PA-2012", "ficpa2012", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 55000000, 75000000, 2100, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_ficpa2012_init, NULL }, /* SiS 5571 */ + /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] Rise R534F", "r534f", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 127, machine_at_r534f_init, NULL }, + /* Has the SiS 5571 chipset with on-chip KBC. */ { "[SiS 5571] MSI MS-5146", "ms5146", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_ms5146_init, NULL }, - /* SiS 5598 */ - { "[SiS 5598] ASUS SP97-XV", "sp97xv", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3200, 1.5, 2.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_sp97xv_init, NULL }, - { "[SiS 5598] PC Chips M571", "m571", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 75000000, 2500, 3500, 1.5, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m571_init, NULL }, - - /* ALi ALADDiN IV */ -#if defined(DEV_BRANCH) && defined(USE_M154X) - { "[ALi ALADDiN IV] PC Chips M560", "m560", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m560_init, NULL }, - { "[ALi ALADDiN IV] MSI MS-5164", "ms5164", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ms5164_init, NULL }, -#endif + /* ALi ALADDiN IV+ */ + /* Has the ALi M1543 southbridge with on-chip KBC. */ + { "[ALi ALADDiN IV+] PC Chips M560", "m560", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 83333333, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_m560_init, NULL }, + /* Has the ALi M1543 southbridge with on-chip KBC. */ + { "[ALi ALADDiN IV+] MSI MS-5164", "ms5164", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 2100, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_ms5164_init, NULL }, /* Super Socket 7 machines */ + /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN V] ASUS P5A", "p5a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_p5a_init, NULL }, + /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge + with on-chip KBC. */ + { "[ALi ALADDiN V] PC Chips M579", "m579", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m579_init, NULL }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN V] Gigabyte GA-5AA", "ga-5aa", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5aa_init, NULL }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN V] Gigabyte GA-5AX", "ga-5ax", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_ga_5ax_init, NULL }, + /* Apollo MVP3 */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] AOpen AX59 Pro", "ax59pro", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1300, 3520, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_ax59pro_init, NULL }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] FIC VA-503+", "ficva503p", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 2000, 3200, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_mvp3_init, NULL }, + /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA MVP3] FIC VA-503A", "ficva503a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1800, 3100, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ficva503a_init, NULL }, /* Socket 8 machines */ /* 450KX */ #if defined(DEV_BRANCH) && defined(USE_I450KX) + /* This has an AMIKey, which is an updated version of type 'F'. */ { "[i450KX] ASUS P/I-P6RP4", "p6rp4", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p6rp4_init, NULL }, #endif /* 440FX */ + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Acer V60N", "v60n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2500, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_v60n_init, NULL }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-P6ND)", "p65up5_cp6nd", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cp6nd_init, NULL }, + /* The MB-8600TTX has an AMIKey 'F' KBC firmware, so I'm going to assume so does + the MB-8600TTC until someone can actually identify it. */ { "[i440FX] Biostar MB-8600TTC", "8600ttc", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 50000000, 66666667, 2900, 3300, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_8500ttc_init, NULL }, { "[i440FX] Gigabyte GA-686NX", "686nx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_686nx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel AP440FX", "ap440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_ap440fx_init, NULL }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ { "[i440FX] Intel VS440FX", "vs440fx", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 2.0, 3.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_vs440fx_init, NULL }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ { "[i440FX] Micronics M6Mi", "m6mi", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2900, 3300, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_m6mi_init, NULL }, + /* I found a BIOS string of it that ends in -S, but it could be a typo for -5 + (there's quite a few AMI BIOS strings around with typo'd KBC codes), so I'm + going to give it an AMI MegaKey. */ { "[i440FX] PC Partner MB600N", "mb600n", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_mb600n_init, NULL }, /* Slot 1 machines */ + /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { "[ALi ALADDiN-PRO II] PC Chips M729", "m729", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024,2097152, 8192, 255, machine_at_m729_init, NULL }, + /* 440FX */ + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ { "[i440FX] ASUS P/I-P65UP5 (C-PKND)", "p65up5_cpknd", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 127, machine_at_p65up5_cpknd_init, NULL }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ { "[i440FX] ASUS KN97", "kn97", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 83333333, 1800, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_kn97_init, NULL }, /* 440LX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440LX] ABIT LX6", "lx6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 60000000, 100000000, 1500, 3500, 2.0, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_lx6_init, NULL }, + /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix + MultiKey KBC firmware. */ { "[i440LX] Micronics Spitfire", "spitfire", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_spitfire_init, NULL }, /* 440EX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440EX] QDI EXCELLENT II", "p6i440e2", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 83333333, 1800, 3500, 3.0, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_p6i440e2_init, NULL }, /* 440BX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS P2B-LS", "p2bls", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 50000000, 112121212, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p2bls_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS P3B-F", "p3bf", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_p3bf_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ABIT BF6", "bf6", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_bf6_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AOpen AX6BC", "ax6bc", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ax6bc_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Gigabyte GA-686BX", "686bx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_686bx_init, NULL }, + /* Has a SM(S)C FDC37M60x Super I/O chip with on-chip KBC with most likely + AMIKey-2 KBC firmware. */ { "[i440BX] HP Vectra VEi 8", "vei8", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vei8_init, NULL }, + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ { "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 112121212, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_SOUND, 8192,1048576, 8192, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] SuperMicro Super P6SBA", "p6sba", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_p6sba_init, NULL }, -#if defined(DEV_BRANCH) && defined(NO_SIO) - { "[i440BX] Fujitsu ErgoPro x365", "ergox365", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 393216, 8192, 511, machine_at_ergox365_init, NULL }, -#endif /* 440ZX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] MSI MS-6168", "ms6168", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_ms6168_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] Packard Bell Bora Pro", "borapro", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 66666667, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND,8192, 524288, 8192, 255, machine_at_borapro_init, NULL }, /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC6310BXII","atc6310bxii", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_atc6310bxii_init, NULL }, /* VIA Apollo Pro */ + /* Has the VIA VT82C596B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro] FIC KA-6130", "ficka6130", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_ficka6130_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133] ASUS P3V133", "p3v133", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p3v133_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133A] ASUS P3V4X", "p3v4x", MACHINE_TYPE_SLOT1, CPU_PKG_SLOT1, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,2097152, 8192, 255, machine_at_p3v4x_init, NULL }, /* Slot 1/2 machines */ /* 440GX */ + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ { "[i440GX] Freeway FW-6400GX", "fw6400gx", MACHINE_TYPE_SLOT1_2, CPU_PKG_SLOT1 | CPU_PKG_SLOT2, 0, 100000000, 150000000, 1800, 3500, 3.0, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2080768,16384, 511, machine_at_fw6400gx_init, NULL }, /* Slot 2 machines */ /* 440GX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440GX] Gigabyte GA-6GXU", "6gxu", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 133333333, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_6gxu_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440GX] SuperMicro Super S2DGE", "s2dge", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_s2dge_init, NULL }, /* PGA370 machines */ /* 440LX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440LX] SuperMicro Super 370SLM", "s370slm", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_s370slm_init, NULL }, /* 440BX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AEWIN AW-O671R", "awo671r", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_awo671r_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] ASUS CUBX", "cubx", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_cubx_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] AmazePC AM-BX133", "ambx133", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ambx133_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Tyan Trinity 371", "trinity371", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_trinity371_init, NULL }, /* 440ZX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440ZX] Soltek SL-63A1", "63a", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 255, machine_at_63a_init, NULL }, /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[SMSC VictoryBX-66] A-Trend ATC7020BXII","atc7020bxii", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_atc7020bxii_init, NULL }, /* VIA Apollo Pro */ + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro] PC Partner APAS3", "apas3", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 100000000, 1800, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_apas3_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133] ECS P6BAP", "p6bap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_p6bap_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[VIA Apollo Pro133A] AEWIN WCF-681", "wcf681", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 133333333, 1300, 3500, 1.5, 8.0, /* limits assumed */ MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_wcf681_init, NULL }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro133A] ASUS CUV4X-LS", "cuv4xls", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_BUS_AC97 | MACHINE_IDE_DUAL,16384,1572864, 8192, 255, machine_at_cuv4xls_init, NULL }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, - { "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL }, /* Miscellaneous/Fake/Hypervisor machines */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL }, { NULL, NULL, MACHINE_TYPE_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } From 996803083291348ed997c224a4b4378086aa1c73 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:43:53 +0200 Subject: [PATCH 032/140] The missing DEC LPC stuff. --- src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 38d7b3cbf..89613c2ca 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -312,6 +312,7 @@ extern int machine_at_cs4031_init(const machine_t *); extern int machine_at_pb410a_init(const machine_t *); +extern int machine_at_decpc_lpv_init(const machine_t *); extern int machine_at_acerv10_init(const machine_t *); extern int machine_at_acera1g_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 4497b1b97..598d61146 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -454,6 +454,29 @@ machine_at_acerv10_init(const machine_t *model) } +int +machine_at_decpc_lpv_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/decpc_lpv/bios.bin-5f2c71ca0a0a5135083487.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&sis_85c461_device); + /* TODO: Phoenix MultiKey KBC */ + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_isa_2ch_device); + device_add(&fdc37c663_device); + /* TODO: On-board S3 805 with AT&T 490 RAM DAC. */ + + return ret; +} + static void machine_at_ali1429_common_init(const machine_t *model) { From 8f486a6c0632ee592deebf678f56a30eb7263ff5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Aug 2021 09:56:22 +0200 Subject: [PATCH 033/140] Fixed the double definition of the AX95 Pro init function. --- src/machine/m_at_sockets7.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index ba26fdb99..e9487ecfe 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -215,39 +215,6 @@ machine_at_ax59pro_init(const machine_t *model) } -int -machine_at_ax59pro_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/ax59pro/AX59P236.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, 1, 2, 0, 0); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - - device_add(&via_mvp3_device); - device_add(&via_vt82c586b_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83877tf_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - - int machine_at_mvp3_init(const machine_t *model) { From 5ecf3ac6cb83b87d2f76d12c1a756768ac38f7a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 5 Aug 2021 18:16:17 +0200 Subject: [PATCH 034/140] Merged the ALi M1217 into the M6117 (that's based on the M1217), moved the M6117 out of the Dev branch, removed the broken M6117 Acrosser, and added three M1217 machines. This finishes the ALi work. --- src/chipset/CMakeLists.txt | 8 +- src/chipset/ali1217.c | 145 ----------------------------------- src/chipset/ali6117.c | 43 ++++++++--- src/include/86box/chipset.h | 2 - src/include/86box/machine.h | 8 +- src/machine/m_at_286_386sx.c | 61 ++++++++++++--- src/machine/machine_table.c | 17 ++-- src/win/Makefile.mingw | 13 +--- 8 files changed, 102 insertions(+), 195 deletions(-) delete mode 100644 src/chipset/ali1217.c diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 14ca76962..c015e900d 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,8 +13,8 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c ali1531.c ali1541.c - ali1543.c ali1621.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c +add_library(chipset OBJECT acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c + ali1621.c ali6117.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c @@ -25,10 +25,6 @@ if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) endif() -if(M6117) - target_sources(chipset PRIVATE ali6117.c) -endif() - if(OLIVETTI) target_sources(chipset PRIVATE olivetti_eva.c) endif() \ No newline at end of file diff --git a/src/chipset/ali1217.c b/src/chipset/ali1217.c deleted file mode 100644 index ab05ac0a0..000000000 --- a/src/chipset/ali1217.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 ALi M1217 chipset. - * - * Note: This chipset has no datasheet, everything were done via - * reverse engineering the BIOS of various machines using it. - * - * Authors: Tiseno100 - * - * Copyright 2021 Tiseno100 - * - */ - -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include <86box/timer.h> -#include <86box/io.h> -#include <86box/device.h> -#include <86box/mem.h> -#include <86box/port_92.h> -#include <86box/chipset.h> - - -#ifdef ENABLE_ALI1217_LOG -int ali1217_do_log = ENABLE_ALI1217_LOG; -static void -ali1217_log(const char *fmt, ...) -{ - va_list ap; - - if (ali1217_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define ali1217_log(fmt, ...) -#endif - -typedef struct -{ - uint8_t index, regs[256]; - int cfg_locked; -} ali1217_t; - -static void ali1217_shadow_recalc(int reg_15, ali1217_t *dev) -{ - for (uint8_t i = 0; i < 4; i++) - mem_set_mem_state_both((reg_15 ? 0xe0000 : 0xc0000) + (i << 15), 0x8000, ((dev->regs[0x14 + reg_15] & (1 << (i * 2))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x14 + reg_15] & (1 << ((i * 2) + 1))) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); - - flushmmucache_nopc(); -} - -static void -ali1217_write(uint16_t addr, uint8_t val, void *priv) -{ - ali1217_t *dev = (ali1217_t *)priv; - - switch (addr) - { - case 0x22: - dev->index = val; - break; - case 0x23: - if (dev->index != 0x13) - ali1217_log("ALi M1217: dev->regs[%02x] = %02x\n", dev->index, val); - else - dev->cfg_locked = !(val == 0xc5); - - if (!dev->cfg_locked) - { - dev->regs[dev->index] = val; - - if ((dev->index == 0x14) || (dev->index == 0x15)) - ali1217_shadow_recalc(dev->index & 1, dev); - } - break; - } -} - -static uint8_t -ali1217_read(uint16_t addr, void *priv) -{ - ali1217_t *dev = (ali1217_t *)priv; - - return (addr == 0x23) ? dev->regs[dev->index] : 0xff; -} - -static void -ali1217_close(void *priv) -{ - ali1217_t *dev = (ali1217_t *)priv; - - free(dev); -} - -static void * -ali1217_init(const device_t *info) -{ - ali1217_t *dev = (ali1217_t *)malloc(sizeof(ali1217_t)); - memset(dev, 0, sizeof(ali1217_t)); - - device_add(&port_92_device); - - dev->cfg_locked = 1; - - /* - - ALi M1217 Ports - - 22h Index Port - 23h Data Port - - */ - io_sethandler(0x0022, 0x0002, ali1217_read, NULL, NULL, ali1217_write, NULL, NULL, dev); - - return dev; -} - -const device_t ali1217_device = { - "ALi M1217", - 0, - 0, - ali1217_init, - ali1217_close, - NULL, - {NULL}, - NULL, - NULL, - NULL}; diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index ae4a30e61..e7196f952 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -109,7 +109,7 @@ ali6117_recalcmapping(ali6117_t *dev) } } - flushmmucache(); + flushmmucache_nopc(); } @@ -127,12 +127,16 @@ ali6117_reg_write(uint16_t addr, uint8_t val, void *priv) else if (dev->unlocked) { ali6117_log("ALI6117: regs[%02X] = %02X\n", dev->reg_offset, val); - switch (dev->reg_offset) { + if (!(dev->local & 0x08) || (dev->reg_offset < 0x30)) switch (dev->reg_offset) { case 0x30: case 0x34: case 0x35: case 0x3e: case 0x3f: case 0x46: case 0x4c: case 0x6a: case 0x73: return; /* read-only registers */ + case 0x10: + refresh_at_enable = !(val & 0x02) || !!(dev->regs[0x20] & 0x80); + break; + case 0x12: val &= 0xf7; /* FALL-THROUGH */ @@ -184,7 +188,7 @@ ali6117_reg_write(uint16_t addr, uint8_t val, void *priv) case 0x20: val &= 0xbf; - refresh_at_enable = !!(val & 0x80); + refresh_at_enable = !(dev->regs[0x10] & 0x02) || !!(val & 0x80); break; case 0x31: @@ -311,13 +315,17 @@ ali6117_reset(void *priv) dev->regs[0x1b] = 0xf0; dev->regs[0x1d] = 0xff; dev->regs[0x20] = 0x80; - dev->regs[0x30] = 0x08; - dev->regs[0x31] = 0x01; - dev->regs[0x34] = 0x04; /* enable internal RTC */ - dev->regs[0x35] = 0x20; /* enable internal KBC */ - dev->regs[0x36] = dev->local & 0x4; /* M6117D ID */ + if (dev->local & 0x08) { + dev->regs[0x30] = 0x08; + dev->regs[0x31] = 0x01; + dev->regs[0x34] = 0x04; /* enable internal RTC */ + dev->regs[0x35] = 0x20; /* enable internal KBC */ + dev->regs[0x36] = dev->local & 0x07; /* M6117D ID */ + } cpu_set_isa_speed(7159091); + + refresh_at_enable = 1; } @@ -361,13 +369,28 @@ ali6117_init(const device_t *info) ali6117_setup(dev); ali6117_reset(dev); - pic_elcr_io_handler(0); - refresh_at_enable = 0; + if (!(dev->local & 0x08)) + pic_elcr_io_handler(0); return dev; } +const device_t ali1217_device = +{ + "ALi M1217", + DEVICE_AT, + 0x8, + ali6117_init, + ali6117_close, + ali6117_reset, + { NULL }, + NULL, + NULL, + NULL +}; + + const device_t ali6117d_device = { "ALi M6117D", diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index c94205277..4ecff681e 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -30,9 +30,7 @@ extern const device_t ali1541_device; extern const device_t ali1543_device; extern const device_t ali1543c_device; extern const device_t ali1621_device; -#if defined(DEV_BRANCH) && defined(USE_M6117) extern const device_t ali6117d_device; -#endif /* AMD */ extern const device_t amd640_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 89613c2ca..f482d63d7 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -279,13 +279,13 @@ extern int machine_at_cmdsl386sx16_init(const machine_t *); extern int machine_at_cmdsl386sx25_init(const machine_t *); extern int machine_at_spc6033p_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); +extern int machine_at_arb1374_init(const machine_t *); +extern int machine_at_sbc_350a_init(const machine_t *); extern int machine_at_flytech386_init(const machine_t *); +extern int machine_at_mr1217_init(const machine_t *); +extern int machine_at_pja511m_init(const machine_t *); extern int machine_at_awardsx_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_M6117) -extern int machine_at_arb1375_init(const machine_t *); -extern int machine_at_pja511m_init(const machine_t *); -#endif extern int machine_at_pc916sx_init(const machine_t *); diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 347448b6b..81321a2d7 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -678,6 +678,49 @@ machine_at_awardsx_init(const machine_t *model) return ret; } + +int +machine_at_arb1374_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/arb1374/1374s.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&w83787f_ide_en_device); + device_add(&keyboard_ps2_ami_device); + + return ret; +} + + +int +machine_at_sbc_350a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sbc_350a/350a.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&sio_detect_device); + device_add(&keyboard_at_device); + + return ret; +} + + int machine_at_flytech386_init(const machine_t *model) { @@ -701,30 +744,31 @@ machine_at_flytech386_init(const machine_t *model) return ret; } + const device_t * at_flytech386_get_device(void) { return &tvga8900d_device; } -#if defined(DEV_BRANCH) && defined(USE_M6117) + int -machine_at_arb1375_init(const machine_t *model) +machine_at_mr1217_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/arb1375/a1375v25.u11-a", - 0x000e0000, 131072, 0); + ret = bios_load_linear("roms/machines/mr1217/mrbios.BIN", + 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_common_init(model); - device_add(&fdc37c669_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&ali6117d_device); - device_add(&sst_flash_29ee010_device); + device_add(&ali1217_device); + device_add(&fdc_at_device); + device_add(&ide_isa_device); + device_add(&keyboard_ps2_device); return ret; } @@ -752,7 +796,6 @@ machine_at_pja511m_init(const machine_t *model) return ret; } -#endif /* * Current bugs: diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b6f7d86ec..2d5039fb2 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -239,16 +239,19 @@ const machine_t machines[] = { { "[ISA] NCR PC916SX", "pc916sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_pc916sx_init, NULL }, /* Has Quadtel KBC firmware. */ { "[ISA] QTC-SXM KT X20T02/HI", "quadt386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 128, 127, machine_at_quadt386sx_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_M6117) - /* Has IBM PS/2 Type 1 KBC firmware. */ - { "[ALi M6117] Acrosser AR-B1375", "arb1375", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_arb1375_init, NULL }, - /* Has IBM PS/2 Type 1 KBC firmware. */ - { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, -#endif + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[ALi M1217] Acrosser AR-B1374", "arb1374", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_arb1374_init, NULL }, + /* Has the AMIKey KBC firmware, which is an updated 'F' type. */ + { "[ALi M1217] AAEON SBC-350A", "sbc-350a", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 16384, 1024, 127, machine_at_sbc_350a_init, NULL }, /* Has an AMI KBC firmware, the only photo of this is too low resolution for me to read what's on the KBC chip, so I'm going to assume AMI 'F' based on the other known HT18 AMI BIOS strings. */ { "[ALi M1217] Flytech 386", "flytech386", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_flytech386_init, at_flytech386_get_device }, + /* I'm going to assume this has a standard/generic IBM-compatible AT KBC + firmware until the board is identified. */ + { "[ALi M1217] MR 386SX clone", "mr1217", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_mr1217_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, /* Has an AMI KBC firmware, the only photo of this is too low resolution for me to read what's on the KBC chip, so I'm going to assume AMI 'F' based on the other known HT18 AMI BIOS strings. */ @@ -256,7 +259,7 @@ const machine_t machines[] = { /* Has an unknown KBC firmware with commands B8 and BB in the style of Phoenix MultiKey and AMIKey-3(!), but also commands E1 and EA with unknown functions. */ - { "[Intel 82335 ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, + { "[Intel 82335 ADI 386SX", "adi386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_adi386sx_init, NULL }, /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[Intel 82335] Shuttle 386SX", "shuttle386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 512, 8192, 128, 127, machine_at_shuttle386sx_init, NULL }, /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 543e15d60..9b01db329 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -75,9 +75,6 @@ ifeq ($(DEV_BUILD), y) ifndef SIO_DETECT SIO_DETECT := y endif - ifndef M6117 - M6117 := y - endif ifndef VGAWONDER VGAWONDER := y endif @@ -145,9 +142,6 @@ else ifndef SIO_DETECT SIO_DETECT := n endif - ifndef M6117 - M6117 := n - endif ifndef VGAWONDER VGAWONDER := n endif @@ -551,11 +545,6 @@ OPTS += -DUSE_SIO_DETECT DEVBROBJ += sio_detect.o endif -ifeq ($(M6117), y) -OPTS += -DUSE_M6117 -DEVBROBJ += ali6117.o -endif - ifeq ($(VGAWONDER), y) OPTS += -DUSE_VGAWONDER endif @@ -602,7 +591,7 @@ CPUOBJ := cpu.o cpu_table.o fpu.o x86.o \ CHIPSETOBJ := acc2168.o \ contaq_82c59x.o \ cs4031.o cs8230.o \ - ali1217.o ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o \ + ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ gc100.o headland.o \ intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o \ From 89f35be8065791c0efec682b2eadf066e8a721ab Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 5 Aug 2021 18:23:59 +0200 Subject: [PATCH 035/140] Fixed some compile-breaking mistakes. --- src/machine/m_at_286_386sx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 81321a2d7..091723b3c 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -714,7 +714,7 @@ machine_at_sbc_350a_init(const machine_t *model) machine_at_common_init(model); device_add(&ali1217_device); - device_add(&sio_detect_device); + device_add(&fdc37c665_ide_device); device_add(&keyboard_at_device); return ret; From df00d0ac58dd8594cf6304453584e768dc98bc0c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 7 Aug 2021 12:28:33 +0200 Subject: [PATCH 036/140] Added three ALi M1487/89 machines and that 430VX machine with Award 4.50PG BIOS. --- src/chipset/ali1489.c | 2 +- src/device/keyboard_at.c | 7 ++- src/include/86box/machine.h | 4 ++ src/machine/m_at_386dx_486.c | 85 +++++++++++++++++++++++++++++++++++ src/machine/m_at_socket7_3v.c | 30 +++++++++++++ src/machine/machine_table.c | 12 +++++ src/sio/sio_detect.c | 2 +- 7 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index 03c1f4519..6c90cf7d0 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -105,7 +105,7 @@ ali1489_shadow_recalc(ali1489_t *dev) } } - flushmmucache(); + flushmmucache_nopc(); } diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 92690db1f..13356127b 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2315,7 +2315,7 @@ write64_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); // kbc_transmit(dev, 'H'); - kbc_transmit(dev, '5'); + kbc_transmit(dev, 'Z'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ @@ -2878,6 +2878,11 @@ kbd_write(uint16_t port, uint8_t val, void *priv) dev->status &= ~STAT_IFULL; kbc_send_to_ob(dev, 'H', 0, 0x00); } +#else + if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); + } #endif break; } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index f482d63d7..a04b423ef 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -360,6 +360,9 @@ extern int machine_at_g486vpa_init(const machine_t *); extern int machine_at_486vipio2_init(const machine_t *); extern int machine_at_abpb4_init(const machine_t *); extern int machine_at_win486pci_init(const machine_t *); +extern int machine_at_ms4145_init(const machine_t *); +extern int machine_at_sbc_490_init(const machine_t *); +extern int machine_at_tf_486_init(const machine_t *); extern int machine_at_itoxstar_init(const machine_t *); extern int machine_at_arb1479_init(const machine_t *); @@ -451,6 +454,7 @@ extern int machine_at_ap53_init(const machine_t *); extern int machine_at_8500tuc_init(const machine_t *); extern int machine_at_p55t2s_init(const machine_t *); +extern int machine_at_p5vxb_init(const machine_t *); extern int machine_at_gw2kte_init(const machine_t *); extern int machine_at_ap5s_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 598d61146..f9f19514c 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1320,6 +1320,91 @@ machine_at_win486pci_init(const machine_t *model) } +int +machine_at_ms4145_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms4145/AG56S.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&ali1489_device); + device_add(&w83787f_device); + device_add(&keyboard_at_ami_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_sbc_490_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sbc-490/07159589.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_VIDEO, 4, 1, 2, 3); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&ali1489_device); + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_tf_486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tf-486/tf486v10.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&ali1489_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + int machine_at_itoxstar_init(const machine_t *model) { diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index f31aeed33..1b1f7c7be 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -449,6 +449,36 @@ machine_at_p55t2s_init(const machine_t *model) } +int +machine_at_p5vxb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5vxb/P5VXB10.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + int machine_at_gw2kte_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 2d5039fb2..5a5ae8b21 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -397,6 +397,8 @@ const machine_t machines[] = { { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, /* 486 machines which utilize the PCI bus */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[ALi M1489] AAEON SBC-490", "sbc-490", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_sbc_490_init, NULL }, /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT KBC. */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, @@ -406,6 +408,14 @@ const machine_t machines[] = { and 0xCB if command 0xA1 returns a letter in the 0x5x or 0x7x ranges, so I'm going to give it an AMI 'U' KBC. */ { "[ALi M1489] AMI WinBIOS 486 PCI", "win486pci", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_win486pci_init, NULL }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. + The known BIOS string ends in -E, and the BIOS returns whatever command 0xA1 + returns (but only if command 0xA1 is instant response), so said ALi keyboard + controller likely returns 'E'. */ + { "[ALi M1489] MSI MS-4145", "ms4145", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_ms4145_init, NULL }, + /* Has an ALi M5042 keyboard controller with Phoenix MultiKey/42 v1.40 firmware. */ + { "[ALi M1489] ESA TF-486", "tf-486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_tf_486_init, NULL }, /* Has IBM PS/2 Type 1 KBC firmware. */ { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ @@ -578,6 +588,8 @@ const machine_t machines[] = { { "[i430HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 127, machine_at_p55t2s_init, NULL }, /* 430VX */ + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { "[i430VX] ECS P5VX-B", "p5vxb", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5vxb_init, NULL }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index 7a0f8821e..8df3864c3 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -53,7 +53,7 @@ sio_detect_read(uint16_t port, void *priv) pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]); - return dev->regs[port & 1]; + return 0xff /*dev->regs[port & 1]*/; } From 1060e62747a3c0ab5d0ffc07a09c7dc1d5fed9dc Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 9 Aug 2021 07:46:02 +0200 Subject: [PATCH 037/140] Some AT / PS/2 KBC fixes, fixes the QDI Excellent II. --- src/device/keyboard_at.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 13356127b..eebfd2c63 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -673,7 +673,7 @@ kbd_status(const char *fmt, ...) } -// #define ENABLE_KEYBOARD_AT_LOG 1 +#define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -1184,7 +1184,7 @@ write_output(atkbd_t *dev, uint8_t val) uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + if (!(dev->flags & KBC_FLAG_PS2)) val |= ((dev->mem[0x20] << 4) & 0x30); dev->kbd_inhibit = (val & 0x40); @@ -1245,12 +1245,15 @@ write_cmd(atkbd_t *dev, uint8_t val) The AMIKEY firmware apparently uses this bit for something else. */ if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->p2); kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); } + if (!(dev->flags & KBC_FLAG_PS2)) { + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + } + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); @@ -2058,6 +2061,8 @@ write64_generic(void *priv, uint8_t val) P6RP4: Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); + kbc_transmit(dev, 0b10011100); + return 0; fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ if (kbc_ven == KBC_VEN_INTEL_AMI) @@ -2879,10 +2884,11 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbc_send_to_ob(dev, 'H', 0, 0x00); } #else - if (val == 0xa1) { + /* if (val == 0xa1) { dev->status &= ~STAT_IFULL; kbc_send_to_ob(dev, 'H', 0, 0x00); - } + } */ + kbc_process(dev); #endif break; } From c26811308a11f7acf3b60a4e3c56c4016d4508f0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 9 Aug 2021 07:51:23 +0200 Subject: [PATCH 038/140] Removed excess logging. --- src/device/keyboard_at.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index eebfd2c63..31118bdc4 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -673,7 +673,6 @@ kbd_status(const char *fmt, ...) } -#define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; From d0cebfdc30f87e9b6f3d46ffcd9e97f47f43fef0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 9 Aug 2021 09:54:49 +0200 Subject: [PATCH 039/140] Reverted a KBC change that should not have been there. --- src/device/keyboard_at.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 31118bdc4..7f5ee51db 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2060,8 +2060,6 @@ write64_generic(void *priv, uint8_t val) P6RP4: Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); - kbc_transmit(dev, 0b10011100); - return 0; fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ if (kbc_ven == KBC_VEN_INTEL_AMI) From 80b75ee433a97eb78f9def63a2d2f023ba9a717e Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 9 Aug 2021 09:58:01 +0200 Subject: [PATCH 040/140] CPU changes. --- src/cpu/386_ops.h | 91 +++++++++++++++++++++++++++++++++++++++++++ src/cpu/cpu.c | 14 ++++++- src/cpu/cpu.h | 1 + src/cpu/cpu_table.c | 6 +-- src/cpu/x86.c | 11 ++---- src/cpu/x86_ops.h | 2 + src/cpu/x86_ops_msr.h | 2 - 7 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 613d8842e..5b472298b 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -641,6 +641,97 @@ const OpFn OP_TABLE(c486_0f)[1024] = /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(stpc_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 290c14a86..b8709254a 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -809,10 +809,17 @@ cpu_set(void) case CPU_Cx486S: case CPU_Cx486DX: + case CPU_STPC: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f); + if (cpu_s->cpu_type == CPU_STPC) + x86_setopcodes(ops_386, ops_stpc_0f, dynarec_ops_386, dynarec_ops_stpc_0f); + else + x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f); #else - x86_setopcodes(ops_386, ops_c486_0f); + if (cpu_s->cpu_type == CPU_STPC) + x86_setopcodes(ops_386, ops_stpc_0f); + else + x86_setopcodes(ops_386, ops_c486_0f); #endif timing_rr = 1; /* register dest - register src */ @@ -846,6 +853,9 @@ cpu_set(void) timing_jmp_pm_gate = 37; timing_misaligned = 3; + + if (cpu_s->cpu_type == CPU_STPC) + cpu_features = CPU_FEATURE_RDTSC; break; case CPU_Cx5x86: diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 2aecdf13e..e4bf676bb 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -54,6 +54,7 @@ enum { CPU_Am486DX, CPU_Am486DXL, CPU_Cx486DX, + CPU_STPC, CPU_i486SX_SLENH, CPU_i486DX_SLENH, CPU_ENH_Am486DX, diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 57aa3f7ca..707c9299b 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -576,8 +576,8 @@ const cpu_family_t cpu_families[] = { .name = "STPC-DX", .internal_name = "stpc_dx", .cpus = (const CPU[]) { - {"66", CPU_Cx486DX, fpus_internal, 66666666, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"75", CPU_Cx486DX, fpus_internal, 75000000, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"66", CPU_STPC, fpus_internal, 66666666, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"75", CPU_STPC, fpus_internal, 75000000, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, {"", 0} } }, { @@ -586,7 +586,7 @@ const cpu_family_t cpu_families[] = { .name = "STPC-DX2", .internal_name = "stpc_dx2", .cpus = (const CPU[]) { - {"133", CPU_Cx486DX, fpus_internal, 133333333, 2.0, 3300, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"133", CPU_STPC, fpus_internal, 133333333, 2.0, 3300, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, {"", 0} } }, { diff --git a/src/cpu/x86.c b/src/cpu/x86.c index a80eb2d21..e652c5d27 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -26,7 +26,6 @@ #include "cpu.h" #include "x86.h" #include <86box/machine.h> -#include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/rom.h> @@ -240,10 +239,8 @@ reset_common(int hard) leave_smm(); /* Needed for the ALi M1533. */ - if (soft_reset_pci && !hard) { + if (soft_reset_pci && !hard) pci_reset(); - device_reset_all_pci(); - } use32 = 0; cpu_cur_status = 0; @@ -267,7 +264,7 @@ reset_common(int hard) } else { loadcs(0xFFFF); cpu_state.pc = 0; - rammask = is286 ? 0xffffff : 0xfffff; + rammask = 0xfffff; } } idt.base = 0; @@ -310,10 +307,8 @@ reset_common(int hard) shadowbios = shadowbios_write = 0; alt_access = cpu_end_block_after_ins = 0; - if (hard) { + if (hard) reset_on_hlt = hlt_reset_pending = 0; - soft_reset_pci = 0; - } if (!is286) reset_808x(hard); diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index dc0d62782..2c8812570 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -80,6 +80,7 @@ extern const OpFn dynarec_ops_386_0f[1024]; extern const OpFn dynarec_ops_486_0f[1024]; extern const OpFn dynarec_ops_c486_0f[1024]; +extern const OpFn dynarec_ops_stpc_0f[1024]; extern const OpFn dynarec_ops_ibm486_0f[1024]; extern const OpFn dynarec_ops_winchip_0f[1024]; @@ -178,6 +179,7 @@ extern const OpFn ops_386_0f[1024]; extern const OpFn ops_486_0f[1024]; extern const OpFn ops_c486_0f[1024]; +extern const OpFn ops_stpc_0f[1024]; extern const OpFn ops_ibm486_0f[1024]; extern const OpFn ops_winchip_0f[1024]; diff --git a/src/cpu/x86_ops_msr.h b/src/cpu/x86_ops_msr.h index 227677268..6624218e4 100644 --- a/src/cpu/x86_ops_msr.h +++ b/src/cpu/x86_ops_msr.h @@ -1,13 +1,11 @@ static int opRDTSC(uint32_t fetchdat) { -#if 0 if (!cpu_has_feature(CPU_FEATURE_RDTSC)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); return 1; } -#endif if ((cr4 & CR4_TSD) && CPL) { x86gpf("RDTSC when TSD set and CPL != 0", 0); From ee4b86065f08c5acce8ca3382ac700c6c15fbd00 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 10 Aug 2021 15:45:49 +0200 Subject: [PATCH 041/140] More CPU changes. --- src/cpu/386_common.c | 1 + src/cpu/cpu.c | 7 ++++--- src/cpu/cpu_table.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index fbb67df1c..099e6d72e 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -306,6 +306,7 @@ enum SMMRAM_Fields_AMD_K { }; +#define ENABLE_386_COMMON_LOG 1 #ifdef ENABLE_386_COMMON_LOG int x386_common_do_log = ENABLE_386_COMMON_LOG; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index b8709254a..5da0778ab 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -375,7 +375,7 @@ cpu_set(void) is_am486dxl = (cpu_s->cpu_type == CPU_Am486DXL); cpu_isintel = !strcmp(cpu_f->manufacturer, "Intel"); - cpu_iscyrix = !strcmp(cpu_f->manufacturer, "Cyrix"); + cpu_iscyrix = !strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST"); /* SL-Enhanced Intel 486s have the same SMM save state table layout as Pentiums, and the WinChip datasheet claims those are Pentium-compatible as well. AMD Am486DXL/DXL2 also has compatible SMM, or would if not for it's different SMBase*/ @@ -385,7 +385,8 @@ cpu_set(void) is_k6 = (cpu_s->cpu_type >= CPU_K6) && !strcmp(cpu_f->manufacturer, "AMD"); /* The Samuel 2 datasheet claims it's Celeron-compatible. */ is_p6 = (cpu_isintel && (cpu_s->cpu_type >= CPU_PENTIUMPRO)) || !strcmp(cpu_f->manufacturer, "VIA"); - is_cxsmm = !strcmp(cpu_f->manufacturer, "Cyrix") && (cpu_s->cpu_type >= CPU_Cx486S); + is_cxsmm = (!strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST")) && + (cpu_s->cpu_type >= CPU_Cx486S); hasfpu = (fpu_type != FPU_NONE); hascache = (cpu_s->cpu_type >= CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || @@ -2962,7 +2963,7 @@ cpu_read(uint16_t addr, void *priv) if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; - if (cyrix_addr == 0x20 && cpu_s->cpu_type == CPU_Cx5x86) + if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86)) return 0xff; } diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 707c9299b..e40d64400 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -586,7 +586,7 @@ const cpu_family_t cpu_families[] = { .name = "STPC-DX2", .internal_name = "stpc_dx2", .cpus = (const CPU[]) { - {"133", CPU_STPC, fpus_internal, 133333333, 2.0, 3300, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"133", CPU_STPC, fpus_internal, 133333333, 2.0, 3300, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, {"", 0} } }, { From ed89a93fe2a241d7200212c941ba622f57f27854 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 10 Aug 2021 15:47:02 +0200 Subject: [PATCH 042/140] Removed the M6117 CPU's from the Dev branch. --- src/cpu/cpu_table.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index e40d64400..a3417c920 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -184,7 +184,6 @@ const cpu_family_t cpu_families[] = { {"", 0} } }, -#if defined(DEV_BRANCH) && defined(USE_M6117) { .package = CPU_PKG_M6117, .manufacturer = "ALi", @@ -196,7 +195,6 @@ const cpu_family_t cpu_families[] = { {"", 0} } }, -#endif { .package = CPU_PKG_386SLC_IBM, .manufacturer = "IBM", From 5c8d06ab356257182ca4798926e27774d19975da Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 10 Aug 2021 15:48:58 +0200 Subject: [PATCH 043/140] Temporary revert of keyboard_at.c. --- src/device/keyboard_at.c | 2796 ++++++++++++++------------------------ 1 file changed, 1042 insertions(+), 1754 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 7f5ee51db..1c44880a3 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,7 +57,9 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define RESET_DELAY_TIME 1000 /* 100 ms */ +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + +#define RESET_DELAY_TIME (100 * 10) /* 600ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -72,136 +74,49 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ -/* This only differs in that translation is forced off. */ -#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x07 +#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ +#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x03 -#define KBC_FLAG_PS2 0x04 - -/* We need to redefine this: - Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 - for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling - controller mode, normally set according to the flags, but togglable on - AMIKey: - 0000 0000 0x00 IBM, AT - 0000 0001 0x01 MR - 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 - 0001 0000 0x10 Olivetti - 0010 0000 0x20 Toshiba - 0011 0000 0x30 Quadtel - 0100 0000 0x40 Phoenix MultiKey/42 - 0101 0000 0x50 AMI KF - 0101 0001 0x51 AMI KH - 0101 0010 0x52 AMIKey - 0101 0011 0x53 AMIKey-2 - 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) - 0110 0000 0x60 Award - 0110 0001 0x61 Award 286 (has some AMI commands apparently) - 0111 0000 0x70 Siemens -*/ - -/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -/* All commands are standard PS/2 */ +#define KBC_VEN_AMI 0x04 #define KBC_VEN_IBM_MCA 0x08 -/* Standard IBM commands, differs in input port bits */ -#define KBC_VEN_IBM_PS1 0x10 -/* Olivetti - proprietary commands and port 62h with switches - readout */ -#define KBC_VEN_OLIVETTI 0x20 -/* Toshiba T3100e - has a bunch of proprietary commands, also sets - IFULL on command AA */ -#define KBC_VEN_TOSHIBA 0x28 -/* Standard IBM commands, uses input port as a switches readout */ -#define KBC_VEN_NCR 0x30 -/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the - polarity of the video type bit in the input port is inverted */ -#define KBC_VEN_XI8088 0x38 -/* QuadtelKey - currently guesswork */ -#define KBC_VEN_QUADTEL 0x40 -/* Phoenix MultiKey/42 - not yet implemented */ -#define KBC_VEN_PHOENIX 0x48 -/* Generic commands, XI8088-like input port handling of video type, - maybe we just need a flag for that? */ -#define KBC_VEN_ACER 0x50 -/* AMI KF/KH/AMIKey/AMIKey-2 */ -#define KBC_VEN_AMI 0xf0 -/* Standard AMI commands, differs in input port bits */ -#define KBC_VEN_INTEL_AMI 0xf8 -#define KBC_VEN_MASK 0xf8 - - -/* Flags should be fully 32-bit: - Bits 7- 0: Vendor and revision/variant; - Bits 15- 8: Input port mask; - Bits 23-16: Input port bits that are always on; - Bits 31-24: Flags: - Bit 0: Invert P1 video type bit polarity; - Bit 1: Is PS/2; - Bit 2: Translation forced always off. - - So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ +#define KBC_VEN_QUADTEL 0x0c +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_XI8088 0x14 +#define KBC_VEN_IBM_PS1 0x18 +#define KBC_VEN_ACER 0x1c +#define KBC_VEN_INTEL_AMI 0x20 +#define KBC_VEN_OLIVETTI 0x24 +#define KBC_VEN_NCR 0x28 +#define KBC_VEN_SAMSUNG 0x2c +#define KBC_VEN_MASK 0x3c typedef struct { - uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, - secr_phase, mem_index, ami_stat, ami_mode, - kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, - kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, - kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, - mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, - kbc_written[3], kbc_data[3]; + uint8_t command, status, old_status, out, old_out, secr_phase, + mem_addr, input_port, output_port, old_output_port, + key_command, output_locked, ami_stat, want60, + wantirq, key_wantdata, refresh, first_write; - uint8_t mem_int[0x40], mem[0x240]; + uint8_t mem[0x100]; - uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; + int last_irq, old_last_irq, + reset_delay, + out_new, out_delayed; uint32_t flags; - pc_timer_t pulse_cb, send_delay_timer; + pc_timer_t refresh_time, pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); + + pc_timer_t send_delay_timer; } atkbd_t; -enum -{ - CHANNEL_KBC = 0, - CHANNEL_KBD, - CHANNEL_MOUSE -}; - -enum -{ - KBD_MAIN_LOOP = 0, - KBD_CMD_PROCESS -}; - -enum -{ - MOUSE_MAIN_LOOP_1 = 0, - MOUSE_CMD_PROCESS, - MOUSE_CMD_END, - MOUSE_MAIN_LOOP_2 -}; - -enum { - KBC_MAIN_LOOP = 0, - KBC_RESET = 1, - KBC_WAIT = 4, - KBC_WAIT_FOR_KBD, - KBC_WAIT_FOR_MOUSE, - KBC_WAIT_FOR_BOTH -}; - - -static void kbd_cmd_process(atkbd_t *dev); - -static void kbc_wait(atkbd_t *dev, uint8_t flags); - - /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -210,9 +125,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; -uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; - +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -653,26 +568,9 @@ static const scancode scancode_set3[512] = { }; -#define UISTR_LEN 256 -static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); -extern void ui_sb_bugui(char *__str); - - -static void -kbd_status(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsprintf(kbd_str, fmt, ap); - ui_sb_bugui(kbd_str); - va_end(ap); -} - - #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -733,6 +631,9 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); + } else { + key_ctrl_queue_start = key_ctrl_queue_end = 0; + memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -740,6 +641,15 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + dev->status = (dev->status & 0x0f) | stat_hi; + if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -748,1045 +658,83 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else - fatal("Adding %02X to invalid channel %02X\n", val, channel); + } else { + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + } +} + + +static void +add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + kbd_log("ATkbc: Adding %02X to front...\n", val); + dev->wantirq = 0; + if (channel == 2) { + if (dev->mem[0] & 0x02) + picint(0x1000); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + dev->last_irq = 2; + } + dev->out = val; + if (channel == 2) + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; + else + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); return; } - - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } -static void -kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) -{ - dev->kbc_written[channel] = 1; - dev->kbc_data[channel] = val; -} - static void -kbd_send_to_host(atkbd_t *dev, uint8_t val) +add_data_kbd_direct(atkbd_t *dev, uint8_t val) { - kbc_send(dev, val, CHANNEL_KBD); -} + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); + uint8_t send; - -static void -kbd_chip_reset(atkbd_t *dev) -{ - kbc_queue_reset(1); - dev->kbc_written[1] = 0x00; - kbd_last_scan_code = 0x00; - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->kbd_phase = 0; - dev->kbd_in = 0; -} - - -static void -kbd_command(atkbd_t *dev) -{ - uint8_t val = dev->kbd_data; - - if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { - dev->kbd_phase++; - if (dev->kbd_phase == RESET_DELAY_TIME) { - kbd_send_to_host(dev, 0xaa); - dev->kbd_phase = 0; - dev->kbd_cmd = 0x00; - } - return; - } - - if (dev->kbd_phase == 2) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf2: - kbd_send_to_host(dev, 0x83); - break; - default: - fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } else if (dev->kbd_phase == 1) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf0: - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - kbd_send_to_host(dev, keyboard_mode & 3); - break; - case 0xf2: - kbd_send_to_host(dev, 0xab); - dev->kbd_phase = 2; - break; - default: - fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } - - if (dev->kbd_in && (val < 0xed)) { - dev->kbd_in = 0; - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set LEDs [%02x]\n", val); - kbd_send_to_host(dev, 0xfa); - break; - - case 0xf0: /* get/set scancode set */ - kbd_send_to_host(dev, 0xfa); - if (val == 0) - dev->kbd_phase = 1; - else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_send_to_host(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); - kbd_send_to_host(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - } else { - /* No keyboard command in progress. */ - dev->kbd_in = 0; - dev->kbd_cmd = 0x00; - dev->kbd_phase = 0; - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - kbd_send_to_host(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - kbd_send_to_host(dev, 0xfe); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - kbd_send_to_host(dev, 0xfa); - - dev->kbd_in = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - kbd_send_to_host(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", - val, keyboard_scan, dev->mem[0x20]); - kbd_send_to_host(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - kbd_send_to_host(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbd_chip_reset(dev); - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - kbd_send_to_host(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) - dev->kbd_cmd = val; - } -} - - -static void -kbd_do_command(atkbd_t *dev) -{ - kbd_command(dev); - if (dev->kbd_written) - dev->kbd_poll_phase = KBD_CMD_PROCESS; - else if ((dev->kbd_phase == 0) && !dev->kbd_in) { - dev->kbd_in_cmd = 0; - if (dev->kbd_data != 0xf5) - keyboard_scan = 1; - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else { - keyboard_scan = 0; - dev->kbd_in_cmd = 1; - dev->kbd_poll_phase = KBD_CMD_PROCESS; - } -} - - -static void -kbd_nack(atkbd_t *dev) -{ - kbd_send_to_host(dev, 0xfe); - dev->kbd_poll_phase = KBD_MAIN_LOOP; -} - - -static void -kbd_main_loop(atkbd_t *dev) -{ - uint8_t scan = !dev->kbd_inhibit && keyboard_scan; - - if (dev->kbd_written) { - dev->kbd_written = 0; - kbd_cmd_process(dev); - } else if (scan && (key_queue_start != key_queue_end)) { - /* Scan here. */ - kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); - kbd_send_to_host(dev, key_queue[key_queue_start]); - key_queue_start = (key_queue_start + 1) & 0xf; - } -} - - -static void -kbd_cmd_process(atkbd_t *dev) -{ - uint8_t written = dev->kbd_written; - - /* We want data, nothing has been written yet, return. */ - if (dev->kbd_in && !dev->kbd_written) + if (dev->reset_delay) return; - dev->kbd_written = 0; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { - kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); - kbd_do_command(dev); - } else if (dev->kbd_data == 0xfe) { - kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); - kbd_send_to_host(dev, kbd_last_scan_code); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data == 0xee) { - kbd_log("ATkbd: Echo EE\n"); - kbd_send_to_host(dev, 0xee); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data >= 0xed) { - kbd_log("ATkbd: Command %02X\n", dev->kbd_data); - if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { - kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); - keyboard_scan = 1; - dev->kbd_in_cmd = 0; - } - kbd_do_command(dev); - } else { - if (!keyboard_scan && dev->kbd_in_cmd) { - if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { - kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); - kbd_nack(dev); - } else { - kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); - kbd_do_command(dev); - } - } else { - kbd_log("ATkbd: Scanning or not in command, NACK\n"); - kbd_nack(dev); - } - } -} + if (translate) + send = nont_to_t[val]; + else + send = val; - -/* Keyboard processing */ -static void -kbd_process(atkbd_t *dev) -{ - /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ - if (dev->kbc_written[1] && dev->kbd_written) - dev->kbc_written[1] = 0; - - /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ - if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { - case KBD_MAIN_LOOP: - kbd_main_loop(dev); - break; - case KBD_CMD_PROCESS: - kbd_cmd_process(dev); - break; - } + add_data_kbd_queue(dev, 1, send); } static void -kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +add_data_kbd_raw(atkbd_t *dev, uint8_t val) { - uint8_t ch = (channel > 0) ? channel : 1; - uint8_t do_irq = (dev->mem[0x20] & ch); - int translate = (channel == 1) && (keyboard_mode & 0x60); - - if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) - return; - - stat_hi |= dev->inhibit; - - if (!dev->kbc_send_pending) { - dev->kbc_send_pending = 1; - dev->kbc_to_send = val; - dev->kbc_channel = channel; - dev->kbc_stat_hi = stat_hi; - return; - } - - if (translate) { - /* Allow for scan code translation. */ - if (val == 0xf0) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if ((sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - } - - dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; - if (do_irq) { - kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); - picint(dev->last_irq); - } - kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); - dev->ob = translate ? (nont_to_t[val] | sc_or) : val; - - dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); - if (ch == 2) - dev->status |= STAT_MFULL; - - if (translate && (sc_or == 0x80)) - sc_or = 0; -} - - -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); - - if (!(dev->flags & KBC_FLAG_PS2)) - val |= ((dev->mem[0x20] << 4) & 0x30); - - dev->kbd_inhibit = (val & 0x40); - dev->mouse_inhibit = (val & 0x08); - - if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) { - kbd_log("ATkbc: write_output(): IRQ 12\n"); - picint(1 << 12); - } else - picintc(1 << 12); - } - if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) { - kbd_log("ATkbc: write_output(): IRQ 1\n"); - picint(1 << 1); - } else - picintc(1 << 1); - } - if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->p2 ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->p2 = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) - val &= ~CCB_TRANSLATE; - - dev->mem[0x20] = val; - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { - keyboard_mode &= ~CCB_PCMODE; - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - if (!(dev->flags & KBC_FLAG_PS2)) { - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->p2); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_p2 = dev->p2 & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xef; - dev->mem[0x20] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xdf; - dev->mem[0x20] |= (enable ? 0x00 : 0x20); -} - - -static void -kbc_transmit(atkbd_t *dev, uint8_t val) -{ - kbc_send_to_ob(dev, val, 0, 0x00); -} - - -static void -kbc_command(atkbd_t *dev) -{ - uint8_t mask, val = dev->ib; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - int bad = 1; - - if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { - if (dev-> kbc_phase < 16) - kbc_transmit(dev, dev->mem[dev->kbc_phase]); - else if (dev-> kbc_phase == 16) - kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); - else if (dev-> kbc_phase == 17) - kbc_transmit(dev, dev->p2); - else if (dev-> kbc_phase == 18) - kbc_transmit(dev, dev->status); - - dev->kbc_phase++; - if (dev->kbc_phase == 19) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } - return; - } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { - val = ami_copr[dev->kbc_phase]; - kbc_transmit(dev, val); - if (val == 0x00) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } else - dev->kbc_phase++; - return; - } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { - /* load security */ - kbd_log("ATkbc: load security\n"); - dev->mem[0x50 + dev->kbc_in - 0x01] = val; - if ((dev->kbc_in == 0x80) && (val != 0x00)) { - /* Security string too long, set it to 0x00. */ - dev->mem[0x50] = 0x00; - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else if (val == 0x00) { - /* Security string finished. */ - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else /* Increase pointer and request another byte. */ - dev->kbc_in++; - return; - } - - /* If the written port is 64, go straight to the beginning of the command. */ - if (!(dev->status & STAT_CD) && dev->kbc_in) { - /* Write data to controller. */ - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (dev->kbc_cmd) { - case 0x60 ... 0x7f: - if (dev->kbc_cmd == 0x60) - write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; - break; - - case 0xc7: /* or input port with system data */ - dev->p1 |= val; - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("New AMIKey mode: %02X\n", val); - dev->ami_mode = val; - dev->flags &= ~KBC_FLAG_PS2; - if (val & 1) - dev->flags |= KBC_FLAG_PS2; - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->p2_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->p2 & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - // kbc_send_to_ob(dev, val, 1, 0x00); - /* Should be channel 1, but we send to 0 to avoid translation, - since bytes output using this command do *NOT* get translated. */ - kbc_send_to_ob(dev, val, 0, 0x00); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - kbc_send_to_ob(dev, val, 2, 0x00); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (dev->flags & KBC_FLAG_PS2) { - set_enable_mouse(dev, 1); - dev->mem[0x20] &= ~0x20; - if (mouse_write && !dev->kbc_written[2]) { - kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); - dev->mouse_data = val; - dev->mouse_written = 1; - dev->kbc_wait_for_response = 2; - } else - kbc_send_to_ob(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - -#ifdef ENABLE_KEYBOARD_AT_LOG - if (bad) - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); -#endif - } - } else { - /* Controller command. */ - kbd_log("ATkbc: Controller command: %02X\n", val); - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (val) { - /* Read data from KBC memory. */ - case 0x20 ... 0x3f: - kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); - break; - - /* Write data to KBC memory. */ - case 0x60 ... 0x7f: - dev->kbc_in = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->kbd_in_cmd = dev->mouse_in_cmd = 0; - dev->status &= ~STAT_OFULL; - dev->last_irq = 0; - dev->kbc_phase = 0; - - /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ - if (dev->flags & KBC_FLAG_PS2) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - kbc_transmit(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - /* No error. */ - kbc_transmit(dev, 0x00); - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - kbc_transmit(dev, dev->mem[0x20]); - dev->kbc_phase = 1; - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xc7: /* or input port with system data */ - kbd_log("ATkbc: Phoenix - or input port with system data\n"); - dev->kbc_in = 1; - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - kbc_transmit(dev, dev->ami_mode); - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->kbc_in = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (dev->mem[0x20] & 0x10) - mask &= 0xbf; - if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) - mask &= 0xf7; - kbc_transmit(dev, dev->p2 & mask); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->kbc_in = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - dev->kbc_in = 1; - else - kbc_transmit(dev, 0x00); /* NCR */ - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - kbc_transmit(dev, 0x00); - break; - - case 0xe1: case 0xea: - kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); - write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); - } - - /* If the command needs data, remember the command. */ - if (dev->kbc_in || (dev->kbc_phase > 0)) - dev->kbc_cmd = val; - } -} - - -static void -kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) -{ - dev->kbc_written[channel] = 0; - kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); - kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); -} - - -static void -kbc_main_loop_scan(atkbd_t *dev) -{ - uint8_t port_dis = dev->mem[0x20] & 0x30; - uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); - - if (!ps2) - port_dis |= 0x20; - - if (!(dev->status & STAT_OFULL)) { - if (port_dis & 0x20) { - if (!(port_dis & 0x10)) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); - /* Enable communication with keyboard. */ - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 1); - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); - } -#endif - } else { - /* Enable communication with mouse. */ - dev->p2 &= 0xf7; - dev->mouse_inhibit = 0; - if (dev->mem[0x20] & 0x10) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); - kbc_wait(dev, 2); - } else { - /* Enable communication with keyboard. */ - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 3); - } - } - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - } -#endif -} - - -static void -kbc_process_ib(atkbd_t *dev) -{ - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - } else { - dev->mem[0x20] &= ~0x10; - dev->kbd_data = dev->ib; - dev->kbd_written = 1; - dev->kbc_wait_for_response = 1; - } - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - if (!dev->kbc_wait_for_response) - kbc_main_loop_scan(dev); -} - - -static void -kbc_wait(atkbd_t *dev, uint8_t flags) -{ - if ((flags & 1) && dev->kbc_written[1]) { - /* Disable communication with mouse. */ - dev->p2 |= 0x08; - dev->mouse_inhibit = 1; - /* Send keyboard byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_KBD); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if ((flags & 2) && dev->kbc_written[2]) { - /* Disable communication with keyboard. */ - dev->p2 |= 0x40; - dev->kbd_inhibit = 1; - /* Send mouse byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if (dev->status & STAT_IFULL) { - /* Disable communication with keyboard and mouse. */ - dev->p2 |= 0x48; - dev->kbd_inhibit = dev->mouse_inhibit = 1; - kbc_process_ib(dev); - } else - dev->kbc_poll_phase = KBC_WAIT | flags; -} - - -/* Controller processing */ -static void -kbc_process(atkbd_t *dev) -{ - // kbd_log("ATkbc: kbc_process()\n"); - - /* If we're waiting for the response from the keyboard or mouse, do nothing - until the device has repsonded back. */ - if (dev->kbc_wait_for_response > 0) { - if (dev->kbc_written[dev->kbc_wait_for_response]) - dev->kbc_wait_for_response = 0; - else - return; - } - - if (dev->kbc_send_pending) { - kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", - dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - dev->kbc_send_pending = 0; - } - - if (dev->kbc_poll_phase == KBC_RESET) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Reset loop()\n"); - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } - } - - return; - } - - if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: In a command\n"); - if (!dev->kbc_in && (dev->status & STAT_OFULL)) { - kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); - return; /* We do not want input and we're waiting for the host to read the data - we transmitted, but it has not done that yet, do nothing. */ - } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { - kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); - return; /* We want input and the host has not provided us with any yet, do nothing. */ - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbc: Normal condition\n"); -#endif - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - kbd_log("ATkbc: Resetting command\n"); - dev->kbc_phase = 0; - dev->kbc_in = 0; - } - } - - /* Process command. */ - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - - if (!(dev->status & STAT_OFULL)) - kbc_main_loop_scan(dev); - /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ - } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { - case KBC_MAIN_LOOP: - // kbd_log("ATkbc: Main loop\n"); - if (dev->status & STAT_IFULL) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: IBF full, process\n"); - kbc_process_ib(dev); - } else - kbc_main_loop_scan(dev); - break; - case KBC_WAIT_FOR_KBD: - case KBC_WAIT_FOR_MOUSE: - case KBC_WAIT_FOR_BOTH: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); - kbc_wait(dev, dev->kbc_poll_phase & 3); - break; - default: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); - break; - } + add_data_kbd_queue(dev, 1, val); } @@ -1794,29 +742,105 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; +#ifdef ENABLE_KEYBOARD_AT_LOG + const uint8_t channels[4] = { 1, 2, 0, 0 }; +#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - /* We process all three devices at the same time, in an arbitrary order. */ + if (dev->out_new != -1 && !dev->last_irq) { + dev->wantirq = 0; + if (dev->out_new & 0x100) { + if (dev->mem[0] & 0x02) + picint(0x1000); + kbd_log("ATkbc: %02X coming from channel 2\n"); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; + dev->last_irq = 2; + } + } - /* Keyboard processing */ - kbd_process(dev); + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); + dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { + kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); + dev->out_new = mouse_queue[mouse_queue_start] | 0x100; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { + kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); + dev->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } - /* TODO: Mouse processing */ - // mouse_process(dev); + if (dev->reset_delay) { + dev->reset_delay--; + if (!dev->reset_delay) { + kbd_log("ATkbc: Sending AA on keyboard reset...\n"); + add_data_kbd_direct(dev, 0xaa); + } + } +} - /* Controller processing */ - kbc_process(dev); + +static void +add_data(atkbd_t *dev, uint8_t val) +{ + kbd_log("ATkbc: add to queue\n"); + + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + kbc_queue_add(dev, val, 0, 0x00); + + if (!(dev->out_new & 0x300)) { + dev->out_delayed = dev->out_new; + dev->out_new = -1; + } } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); int i; + uint8_t or = 0; + uint8_t send; - for (i = 0; i < len; i++) - add_data_kbd_queue(dev, 0, val[i]); + if (dev->reset_delay) + return; + + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + + add_data_kbd_queue(dev, 0, send); + } } @@ -1824,21 +848,56 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->kbd_in || (dev->kbd_phase > 0)) + if (dev->reset_delay) return; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && - (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) - t3100e_notify_set((val + 2) & 0x0f); + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && + (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0a); break; /* Up */ + case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ + } + + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1971,7 +1030,18 @@ add_data_kbd(uint16_t val) break; default: - add_data_kbd_queue(dev, 0, val); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); + if (translate) { + kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbd_log("F0 "); + kbd_log("%02X)\n", val); + } else + kbd_log("%02X\n", val); +#endif + + add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); break; } @@ -1980,13 +1050,124 @@ add_data_kbd(uint16_t val) } +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) + val |= ((dev->mem[0] << 4) & 0x10); + + if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->output_port = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); + + if ((val & 1) && (dev->status & STAT_OFULL)) + dev->wantirq = 1; + if (!(val & 1) && dev->wantirq) + dev->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + dev->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || + ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { + keyboard_mode &= ~CCB_PCMODE; + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->output_port); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_output_port = dev->output_port & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); + write_output(dev, dev->output_port & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); - write_output(dev, dev->p2 | dev->old_p2); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); + write_output(dev, dev->output_port | dev->old_output_port); +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xef; + dev->mem[0] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xdf; + dev->mem[0] |= (enable ? 0x00 : 0x20); } @@ -1995,70 +1176,49 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + switch (val) { case 0xa4: /* check if password installed */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: check if password installed\n"); - kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); - return 0; - } - break; - - case 0xa5: /* load security */ - if (dev->flags & KBC_FLAG_PS2) { - kbd_log("ATkbc: load security\n"); - dev->kbc_in = 1; + add_data(dev, 0xf1); return 0; } break; case 0xa7: /* disable mouse port */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: disable mouse port\n"); - // kbc_transmit(dev, 0); + set_enable_mouse(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: enable mouse port\n"); - // kbc_transmit(dev, 1); + set_enable_mouse(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if (dev->flags & KBC_FLAG_PS2) { - /* No error, this is testing the channel 2 interface. */ - kbc_transmit(dev, 0x00); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - kbc_transmit(dev, 0x00); + add_data(dev, 0x00); return 0; case 0xc0: /* read input port */ - /* IBM PS/1: - Bit 2 and 4 ignored (we return always 0), - Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". - Intel AMI: - Bit 2 ignored (we return always 1), - Bit 4 must be 1, - Bit 6 must be 1 or else error in SMM. - Acer: - Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), - Bit 4 must be 0, - Bit 6 ignored. - P6RP4: - Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -2066,8 +1226,11 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc) | + (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -2079,34 +1242,39 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } else { - pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); - // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); else - kbc_transmit(dev, dev->p1 | fixed_bits); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -2121,168 +1289,35 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; - switch(dev->kbc_cmd) { - /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - if (dev->kbc_cmd == 0x40) + switch(dev->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); - if (dev->secr_phase == 0) { - dev->mem_index = val; - dev->kbc_in = 1; - dev->secr_phase++; - } else if (dev->secr_phase == 1) { - if (dev->mem_index == 0x20) - write_cmd(dev, val); - else - dev->mem[dev->mem_index] = val; + kbd_log("ATkbc: AMI - set extended controller RAM\n"); + if (dev->secr_phase == 1) { + dev->mem_addr = val; + dev->want60 = 1; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; dev->secr_phase = 0; } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); - dev->mem_index = val; - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - dev->mem[index + dev->mem_index] = val; - } else if (dev->mem_index == 0x60) - write_cmd(dev, val); - else if (dev->mem_index == 0x42) - dev->status = val; - else if (dev->mem_index >= 0x40) - dev->mem[dev->mem_index - 0x40] = val; - else - dev->mem_int[dev->mem_index] = val; - return 0; - - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - dev->status = val; - break; - case 0x01: /* Password_ptr */ - dev->mem[0x1c] = val; - break; - case 0x02: /* Wakeup_Tsk_Reg */ - dev->mem[0x1e] = val; - break; - case 0x03: /* CCB */ - write_cmd(dev, val); - break; - case 0x04: /* Debounce_time */ - dev->mem[0x4d] = val; - break; - case 0x05: /* Pulse_Width */ - dev->mem[0x4e] = val; - break; - case 0x06: /* Pk_sel_byte */ - dev->mem[0x4c] = val; - break; - case 0x07: /* Func_Tsk_Reg */ - dev->mem[0x7e] = val; - break; - case 0x08: /* TypematicRate */ - dev->mem[0x80] = val; - break; - case 0x09: /* Led_Flag_Byte */ - dev->mem[0x81] = val; - break; - case 0x0a: /* Kbms_Command_St */ - dev->mem[0x87] = val; - break; - case 0x0b: /* Delay_Count_Byte */ - dev->mem[0x86] = val; - break; - case 0x0c: /* KBC_Flags */ - dev->mem[0x9b] = val; - break; - case 0x0d: /* SCODE_HK1 */ - dev->mem[0x50] = val; - break; - case 0x0e: /* SCODE_HK2 */ - dev->mem[0x51] = val; - break; - case 0x0f: /* SCODE_HK3 */ - dev->mem[0x52] = val; - break; - case 0x10: /* SCODE_HK4 */ - dev->mem[0x53] = val; - break; - case 0x11: /* SCODE_HK5 */ - dev->mem[0x54] = val; - break; - case 0x12: /* SCODE_HK6 */ - dev->mem[0x55] = val; - break; - case 0x13: /* TASK_HK1 */ - dev->mem[0x56] = val; - break; - case 0x14: /* TASK_HK2 */ - dev->mem[0x57] = val; - break; - case 0x15: /* TASK_HK3 */ - dev->mem[0x58] = val; - break; - case 0x16: /* TASK_HK4 */ - dev->mem[0x59] = val; - break; - case 0x17: /* TASK_HK5 */ - dev->mem[0x5a] = val; - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - dev->mem[0x5b] = val; - break; - case 0x19: /* Batt_Alarm_Reg1 */ - dev->mem[0x5c] = val; - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - dev->mem[0x5d] = val; - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - dev->mem[0x5e] = val; - break; - case 0x1c: /* Kbc_State1 */ - dev->mem[0x9d] = val; - break; - case 0x1d: /* Aux_Config */ - dev->mem[0x75] = val; - break; - case 0x1e: /* Kbc_State3 */ - dev->mem[0x73] = val; - break; - } - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); - dev->p1 = val; - return 0; - case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -2296,50 +1331,62 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; switch (val) { - case 0x00 ... 0x1f: + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - kbc_transmit(dev, dev->mem[val + 0x20]); + add_data(dev, dev->mem[val]); return 0; - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - dev->kbc_in = 1; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; return 0; case 0xa0: /* copyright message */ - kbc_transmit(dev, ami_copr[0]); - dev->kbc_phase = 1; - return 0; + add_data(dev, 0x28); + add_data(dev, 0x00); + break; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - // kbc_transmit(dev, 'H'); - kbc_transmit(dev, 'Z'); + add_data(dev, 'H'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->p2 & 0xf3); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port & 0xf3); + add_data(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->p2 | 0x0c); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port | 0x0c); + add_data(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -2347,7 +1394,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -2355,15 +1402,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read clock\n"); - kbc_transmit(dev, !!(dev->ami_stat & 1)); + add_data(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -2371,7 +1418,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -2379,237 +1426,68 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read cache\n"); - kbc_transmit(dev, !!(dev->ami_stat & 2)); + add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->kbc_in = 1; + dev->want60 = 1; + dev->secr_phase = 1; return 0; - case 0xb0 ... 0xb3: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { - dev->p1 &= ~(1 << (val & 0x03)); - } - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb1)) + dev->input_port &= ~(1 << (val & 0x03)); + add_data(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 & ~(4 << (val & 0x01))); - kbc_transmit(dev, 0x00); + if (! PCI) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_data(dev, 0x00); return 0; -#if 0 - case 0xb8 ... 0xbb: -#else - case 0xb9: -#endif + case 0xb8: case 0xb9: case 0xba: case 0xbb: /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { - dev->p1 |= (1 << (val & 0x03)); - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb9)) { + dev->input_port |= (1 << (val & 0x03)); + add_data(dev, 0x00); } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index\n"); - dev->kbc_in = 1; - return 0; - - case 0xba: - kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - kbc_transmit(dev, dev->mem[index + dev->mem_index]); - } else if (dev->mem_index == 0x42) - kbc_transmit(dev, dev->status); - else if (dev->mem_index >= 0x40) - kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); - else - kbc_transmit(dev, dev->mem_int[dev->mem_index]); - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - -#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 | (4 << (val & 0x01))); - kbc_transmit(dev, 0x00); - return 0; -#endif - - case 0xbc: - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - kbc_transmit(dev, dev->status); - break; - case 0x01: /* Password_ptr */ - kbc_transmit(dev, dev->mem[0x1c]); - break; - case 0x02: /* Wakeup_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x1e]); - break; - case 0x03: /* CCB */ - kbc_transmit(dev, dev->mem[0x20]); - break; - case 0x04: /* Debounce_time */ - kbc_transmit(dev, dev->mem[0x4d]); - break; - case 0x05: /* Pulse_Width */ - kbc_transmit(dev, dev->mem[0x4e]); - break; - case 0x06: /* Pk_sel_byte */ - kbc_transmit(dev, dev->mem[0x4c]); - break; - case 0x07: /* Func_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x7e]); - break; - case 0x08: /* TypematicRate */ - kbc_transmit(dev, dev->mem[0x80]); - break; - case 0x09: /* Led_Flag_Byte */ - kbc_transmit(dev, dev->mem[0x81]); - break; - case 0x0a: /* Kbms_Command_St */ - kbc_transmit(dev, dev->mem[0x87]); - break; - case 0x0b: /* Delay_Count_Byte */ - kbc_transmit(dev, dev->mem[0x86]); - break; - case 0x0c: /* KBC_Flags */ - kbc_transmit(dev, dev->mem[0x9b]); - break; - case 0x0d: /* SCODE_HK1 */ - kbc_transmit(dev, dev->mem[0x50]); - break; - case 0x0e: /* SCODE_HK2 */ - kbc_transmit(dev, dev->mem[0x51]); - break; - case 0x0f: /* SCODE_HK3 */ - kbc_transmit(dev, dev->mem[0x52]); - break; - case 0x10: /* SCODE_HK4 */ - kbc_transmit(dev, dev->mem[0x53]); - break; - case 0x11: /* SCODE_HK5 */ - kbc_transmit(dev, dev->mem[0x54]); - break; - case 0x12: /* SCODE_HK6 */ - kbc_transmit(dev, dev->mem[0x55]); - break; - case 0x13: /* TASK_HK1 */ - kbc_transmit(dev, dev->mem[0x56]); - break; - case 0x14: /* TASK_HK2 */ - kbc_transmit(dev, dev->mem[0x57]); - break; - case 0x15: /* TASK_HK3 */ - kbc_transmit(dev, dev->mem[0x58]); - break; - case 0x16: /* TASK_HK4 */ - kbc_transmit(dev, dev->mem[0x59]); - break; - case 0x17: /* TASK_HK5 */ - kbc_transmit(dev, dev->mem[0x5a]); - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - kbc_transmit(dev, dev->mem[0x5b]); - break; - case 0x19: /* Batt_Alarm_Reg1 */ - kbc_transmit(dev, dev->mem[0x5c]); - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - kbc_transmit(dev, dev->mem[0x5d]); - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x5e]); - break; - case 0x1c: /* Kbc_State1 */ - kbc_transmit(dev, dev->mem[0x9d]); - break; - case 0x1d: /* Aux_Config */ - kbc_transmit(dev, dev->mem[0x75]); - break; - case 0x1e: /* Kbc_State3 */ - kbc_transmit(dev, dev->mem[0x73]); - break; - default: - kbc_transmit(dev, 0x00); - break; - } - kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); + if (! PCI) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_data(dev, 0x00); return 0; - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write input port\n"); - dev->kbc_in = 1; - return 0; - - case 0xc4: - /* set KBC line P14 low */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); - dev->p1 &= 0xef; - kbc_transmit(dev, 0x00); - return 0; - case 0xc5: - /* set KBC line P15 low */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); - dev->p1 &= 0xdf; - kbc_transmit(dev, 0x00); - return 0; - - case 0xc8: case 0xc9: + case 0xc8: /* - * (un)block KBC lines P22/P23 + * unblock KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); - dev->p2_locked = (val & 1); + kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; - case 0xcc: - /* set KBC line P14 high */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); - dev->p1 |= 0x10; - kbc_transmit(dev, 0x00); - return 0; - case 0xcd: - /* set KBC line P15 high */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); - dev->p1 |= 0x20; - kbc_transmit(dev, 0x00); + case 0xc9: + /* + * block KBC lines P22/P23 + * (disallow command D1 from changing bits 2/3 of the port) + */ + kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -2630,20 +1508,23 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -2658,7 +1539,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -2667,34 +1548,12 @@ write60_quadtel(void *priv, uint8_t val) return 1; } - static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { - /* This appears to be a clone of "Read input port", in which case, the bis would be: - 7: M290 (AT KBC): - Keyboard lock (1 = unlocked, 0 = locked); - M300 (PS/2 KBC): - Bus expansion board present (1 = present, 0 = not present); - 6: Usually: - Display (1 = MDA, 0 = CGA, but can have its polarity inverted); - 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); - 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); - 3: Fast Ram check (if inactive keyboard works erratically); - 2: Keyboard fuse present - This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; - 1: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Mouse data in; - 0: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Key data in. - */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -2703,9 +1562,11 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); + add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); return 0; - } + } return write64_generic(dev, val); } @@ -2723,7 +1584,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } @@ -2736,7 +1597,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -2779,30 +1640,29 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - kbc_transmit(dev, t3100e_config_get()); + add_data(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - kbc_transmit(dev, t3100e_mono_get()); + add_data(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_FLAG_PS2; + dev->flags &= ~KBC_TYPE_MASK; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_FLAG_PS2; - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else + dev->flags |= KBC_TYPE_PS2_NOREF; + } else { kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); -#endif + dev->flags |= KBC_TYPE_ISA; + } return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -2812,9 +1672,8 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - kbc_transmit(dev, 0x04); - else - kbc_transmit(dev, 0x00); + add_data(dev, 0x04); + else add_data(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -2827,8 +1686,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbc_transmit(dev, dev->p1); + dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_data(dev, dev->input_port); return 0; } @@ -2841,52 +1700,423 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; + int i = 0, bad = 1; + uint8_t mask, kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; + + kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); switch (port) { case 0x60: - dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); + dev->status &= ~STAT_CD; + if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; -#if 0 - if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { - dev->status &= ~STAT_IFULL; - write_output(dev, val); - dev->fast_a20_phase = 0; + switch (dev->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->output_port & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + add_to_kbc_queue_front(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (val == 0xbb) + break; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_mouse(dev, 1); + if (mouse_write) + mouse_write(val, mouse_p); + else + add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + + if (bad) { + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); + add_data_kbd(0xfe); + } + } + } else { + /* Write data to keyboard. */ + dev->mem[0] &= ~0x10; + + if (dev->key_wantdata) { + dev->key_wantdata = 0; + + /* + * Several system BIOSes and OS device drivers + * mess up with this, and repeat the command + * code many times. Fun! + */ + if (val == dev->key_command) { + /* Respond NAK and ignore it. */ + add_data_kbd(0xfe); + dev->key_command = 0x00; + break; + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd_direct(dev, 0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", val); + break; + + case 0xf0: /* get/set scancode set */ + add_data_kbd_direct(dev, 0xfa); + if (val == 0) { + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + add_data_kbd_direct(dev, keyboard_mode & 3); + } else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + add_data_kbd_direct(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); + add_data_kbd_direct(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + dev->key_command = 0x00; + } else { + /* No keyboard command in progress. */ + dev->key_command = 0x00; + + set_enable_kbd(dev, 1); + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + add_data_kbd_direct(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + add_data_kbd_direct(dev, 0xfe); + break; + + /* Sent by Pentium-era AMI BIOS'es.*/ + case 0x71: case 0x82: + kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + add_data_kbd_direct(dev, 0xfa); + + dev->key_wantdata = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + add_data_kbd_direct(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + add_data_kbd_direct(dev, 0xfa); + add_data_kbd_direct(dev, 0xab); + add_data_kbd_direct(dev, 0x83); + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", + val, keyboard_scan, dev->mem[0]); + add_data_kbd_direct(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + add_data_kbd_raw(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbc_queue_reset(1); + kbd_last_scan_code = 0x00; + add_data_kbd_direct(dev, 0xfa); + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->reset_delay = RESET_DELAY_TIME; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + add_data_kbd_direct(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = val; + } } -#endif break; - case 0x64: - dev->status |= (STAT_CD | STAT_IFULL); - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); -#if 0 - if (val == 0xd1) { - dev->status &= ~STAT_IFULL; - dev->fast_a20_phase = 1; - } else if (val == 0xfe) { - dev->status &= ~STAT_IFULL; - pulse_output(dev, 0x0e); - } else if ((val == 0xad) || (val == 0xae)) { - dev->status &= ~STAT_IFULL; - if (val & 0x01) - dev->mem[0x20] |= 0x10; - else - dev->mem[0x20] &= ~0x10; - } else if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); + case 0x61: + ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 1); + + if (kbc_ven == KBC_VEN_XI8088) + xi8088_turbo_set(!!(val & 0x04)); + break; + + case 0x64: + /* Controller command. */ + dev->want60 = 0; + dev->status |= STAT_CD; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + add_data(dev, dev->mem[val & 0x1f]); + break; + + /* Write data to KBC memory. */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->want60 = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) + dev->status |= STAT_IFULL; + write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0x00; + dev->status &= ~STAT_OFULL; + dev->last_irq = dev->old_last_irq = 0; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + add_data(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + add_data(dev, 0x00); /*no error*/ + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + for (i = 0; i < 16; i++) + add_data(dev, dev->mem[i]); + add_data(dev, (dev->input_port & 0xf0) | 0x80); + add_data(dev, dev->output_port); + add_data(dev, dev->status); + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->want60 = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) + mask &= 0xbf; + add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->want60 = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + dev->want60 = 1; + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + add_data(dev, 0x00); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); } -#else - /* if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); - } */ - kbc_process(dev); -#endif + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = val; break; } } @@ -2897,20 +2127,83 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - // if (dev->flags & KBC_FLAG_PS2) - // cycles -= ISA_CYCLES(8); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + cycles -= ISA_CYCLES(8); + + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; switch (port) { case 0x60: - ret = dev->ob; + ret = dev->out; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + if (dev->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (kbc_ven == KBC_VEN_XI8088) { + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x62: + ret = 0xff; + if (kbc_ven == KBC_VEN_OLIVETTI) { + /* SWA on Olivetti M240 mainboard (off=1) */ + ret = 0x00; + if (ppi.pb & 0x8) { + /* Switches 4, 5 - floppy drives (number) */ + int i, fdd_count = 0; + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 2); + /* Switches 6, 7 - monitor type */ + if (video_is_mda()) + ret |= 0x3; + else if (video_is_cga()) + ret |= 0x2; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + } else { + /* bit 2 always on */ + ret |= 0x4; + /* Switch 8 - 8087 FPU. */ + if (hasfpu) + ret |= 0x02; + } + } + break; case 0x64: - ret = dev->status; + ret = (dev->status & 0xfb); + if (dev->mem[0] & STAT_SYSFLAG) + ret |= STAT_SYSFLAG; + /* Only clear the transmit timeout flag on non-PS/2 controllers, as on + PS/2 controller, it is the keyboard/mouse output source bit. */ + // dev->status &= ~STAT_RTIMEOUT; + if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && + (kbc_ven != KBC_VEN_IBM_MCA)) + dev->status &= ~STAT_TTIMEOUT; break; default: @@ -2918,12 +2211,22 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); + kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); return(ret); } +static void +kbd_refresh(void *priv) +{ + atkbd_t *dev = (atkbd_t *)priv; + + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); +} + + static void kbd_reset(void *priv) { @@ -2932,26 +2235,25 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; + dev->first_write = 1; + // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; + dev->mem[0] = 0x01; + dev->mem[0] |= CCB_TRANSLATE; + dev->wantirq = 0; write_output(dev, 0xcf); - dev->last_irq = 0; + dev->last_irq = dev->old_last_irq = 0; dev->secr_phase = 0; - dev->kbd_in = 0; - dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); + dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->p1 ^= 0x40; - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - dev->inhibit = ((dev->p1 & 0x80) >> 3); + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else - dev->inhibit = 0x10; - kbd_log("ATkbc: input port = %02x\n", dev->p1); + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbc: input port = %02x\n", dev->input_port); - keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2959,18 +2261,16 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->ob = 0xff; + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0; sc_or = 0; - for (i = 1; i <= 2; i++) - kbc_queue_reset(i); - memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); - - dev->mem[0x31] = 0xfe; } @@ -2992,6 +2292,7 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); + timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -3015,14 +2316,17 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - dev->kbc_poll_phase = KBC_RESET; - kbd_send_to_host(dev, 0xaa); + kbd_reset(dev); - io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); - io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + timer_add(&dev->refresh_time, kbd_refresh, dev, 1); + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -3038,14 +2342,12 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: - /* The Olivetti controller is a special case - starts directly in the - main loop instead of the reset loop. */ - dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: + case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -3065,8 +2367,6 @@ kbd_init(const device_t *info) break; } - kbd_reset(dev); - /* We need this, sadly. */ SavedKbd = dev; @@ -3094,6 +2394,16 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; +const device_t keyboard_at_samsung_device = { + "PC/AT Keyboard (Samsung)", + 0, + KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -3125,6 +2435,16 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -3137,7 +2457,7 @@ const device_t keyboard_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3147,7 +2467,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3167,7 +2487,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3177,7 +2497,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -3207,7 +2527,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -3217,7 +2537,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -3227,7 +2547,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3237,7 +2557,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -3247,7 +2567,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_ACER, + KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -3258,8 +2578,17 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - // mouse_write = func; - // mouse_p = priv; + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + + add_data_kbd_queue(dev, 0, val); } @@ -3272,30 +2601,10 @@ keyboard_at_adddata_mouse(uint8_t val) } -void -keyboard_at_adddata_mouse_direct(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - -void -keyboard_at_adddata_mouse_cmd(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - void keyboard_at_mouse_reset(void) { - // atkbd_t *dev = SavedKbd; - - return; + kbc_queue_reset(2); } @@ -3306,22 +2615,13 @@ keyboard_at_mouse_pos(void) } -int -keyboard_at_fixed_channel(void) -{ - // atkbd_t *dev = SavedKbd; - - return 0x000; -} - - void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -3335,7 +2635,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0] & 0x20) ? 0x00 : 0x10); } @@ -3344,17 +2644,5 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); -} - - -void -keyboard_at_set_mode(int ps2) -{ - atkbd_t *dev = SavedKbd; - - if (ps2) - dev->flags |= KBC_FLAG_PS2; - else - dev->flags &= ~KBC_FLAG_PS2; + write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); } From 4b1c0a1597800b29cad69099c1226c2cb37a032a Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 10 Aug 2021 15:49:50 +0200 Subject: [PATCH 044/140] And back. --- src/device/keyboard_at.c | 2805 ++++++++++++++++++++++++-------------- 1 file changed, 1759 insertions(+), 1046 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 1c44880a3..c0507ffb5 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,9 +57,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - -#define RESET_DELAY_TIME (100 * 10) /* 600ms */ +#define RESET_DELAY_TIME 1000 /* 100 ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -74,49 +72,136 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ -#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ -#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x03 +#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ +/* This only differs in that translation is forced off. */ +#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x07 +#define KBC_FLAG_PS2 0x04 + +/* We need to redefine this: + Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 + for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling + controller mode, normally set according to the flags, but togglable on + AMIKey: + 0000 0000 0x00 IBM, AT + 0000 0001 0x01 MR + 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 + 0001 0000 0x10 Olivetti + 0010 0000 0x20 Toshiba + 0011 0000 0x30 Quadtel + 0100 0000 0x40 Phoenix MultiKey/42 + 0101 0000 0x50 AMI KF + 0101 0001 0x51 AMI KH + 0101 0010 0x52 AMIKey + 0101 0011 0x53 AMIKey-2 + 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) + 0110 0000 0x60 Award + 0110 0001 0x61 Award 286 (has some AMI commands apparently) + 0111 0000 0x70 Siemens +*/ + +/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -#define KBC_VEN_AMI 0x04 +/* All commands are standard PS/2 */ #define KBC_VEN_IBM_MCA 0x08 -#define KBC_VEN_QUADTEL 0x0c -#define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_MASK 0x3c +/* Standard IBM commands, differs in input port bits */ +#define KBC_VEN_IBM_PS1 0x10 +/* Olivetti - proprietary commands and port 62h with switches + readout */ +#define KBC_VEN_OLIVETTI 0x20 +/* Toshiba T3100e - has a bunch of proprietary commands, also sets + IFULL on command AA */ +#define KBC_VEN_TOSHIBA 0x28 +/* Standard IBM commands, uses input port as a switches readout */ +#define KBC_VEN_NCR 0x30 +/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the + polarity of the video type bit in the input port is inverted */ +#define KBC_VEN_XI8088 0x38 +/* QuadtelKey - currently guesswork */ +#define KBC_VEN_QUADTEL 0x40 +/* Phoenix MultiKey/42 - not yet implemented */ +#define KBC_VEN_PHOENIX 0x48 +/* Generic commands, XI8088-like input port handling of video type, + maybe we just need a flag for that? */ +#define KBC_VEN_ACER 0x50 +/* AMI KF/KH/AMIKey/AMIKey-2 */ +#define KBC_VEN_AMI 0xf0 +/* Standard AMI commands, differs in input port bits */ +#define KBC_VEN_INTEL_AMI 0xf8 +#define KBC_VEN_MASK 0xf8 + + +/* Flags should be fully 32-bit: + Bits 7- 0: Vendor and revision/variant; + Bits 15- 8: Input port mask; + Bits 23-16: Input port bits that are always on; + Bits 31-24: Flags: + Bit 0: Invert P1 video type bit polarity; + Bit 1: Is PS/2; + Bit 2: Translation forced always off. + + So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ typedef struct { - uint8_t command, status, old_status, out, old_out, secr_phase, - mem_addr, input_port, output_port, old_output_port, - key_command, output_locked, ami_stat, want60, - wantirq, key_wantdata, refresh, first_write; + uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, + secr_phase, mem_index, ami_stat, ami_mode, + kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, + kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, + kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, + mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, + kbc_written[3], kbc_data[3]; - uint8_t mem[0x100]; + uint8_t mem_int[0x40], mem[0x240]; - int last_irq, old_last_irq, - reset_delay, - out_new, out_delayed; + uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb, send_delay_timer; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - - pc_timer_t send_delay_timer; } atkbd_t; +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbd_cmd_process(atkbd_t *dev); + +static void kbc_wait(atkbd_t *dev, uint8_t flags); + + /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -125,9 +210,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; +uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; + -static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -568,9 +653,27 @@ static const scancode scancode_set3[512] = { }; +#define UISTR_LEN 256 +static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); +extern void ui_sb_bugui(char *__str); + + +static void +kbd_status(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(kbd_str, fmt, ap); + ui_sb_bugui(kbd_str); + va_end(ap); +} + + +#define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -631,9 +734,6 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); - } else { - key_ctrl_queue_start = key_ctrl_queue_end = 0; - memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -641,15 +741,6 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - dev->status = (dev->status & 0x0f) | stat_hi; - if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -658,83 +749,1045 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else { - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - } -} - - -static void -add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - kbd_log("ATkbc: Adding %02X to front...\n", val); - dev->wantirq = 0; - if (channel == 2) { - if (dev->mem[0] & 0x02) - picint(0x1000); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - dev->last_irq = 2; - } - dev->out = val; - if (channel == 2) - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; - else - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; + } else + fatal("Adding %02X to invalid channel %02X\n", val, channel); } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); return; } - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } - static void -add_data_kbd_direct(atkbd_t *dev, uint8_t val) +kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); - uint8_t send; - - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - if (translate) - send = nont_to_t[val]; - else - send = val; - - add_data_kbd_queue(dev, 1, send); + dev->kbc_written[channel] = 1; + dev->kbc_data[channel] = val; } static void -add_data_kbd_raw(atkbd_t *dev, uint8_t val) +kbd_send_to_host(atkbd_t *dev, uint8_t val) { - add_data_kbd_queue(dev, 1, val); + kbc_send(dev, val, CHANNEL_KBD); +} + + +static void +kbd_chip_reset(atkbd_t *dev) +{ + kbc_queue_reset(1); + dev->kbc_written[1] = 0x00; + kbd_last_scan_code = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->kbd_phase = 0; + dev->kbd_in = 0; +} + + +static void +kbd_command(atkbd_t *dev) +{ + uint8_t val = dev->kbd_data; + + if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { + dev->kbd_phase++; + if (dev->kbd_phase == RESET_DELAY_TIME) { + kbd_send_to_host(dev, 0xaa); + dev->kbd_phase = 0; + dev->kbd_cmd = 0x00; + } + return; + } + + if (dev->kbd_phase == 2) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf2: + kbd_send_to_host(dev, 0x83); + break; + default: + fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } else if (dev->kbd_phase == 1) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf0: + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + kbd_send_to_host(dev, keyboard_mode & 3); + break; + case 0xf2: + kbd_send_to_host(dev, 0xab); + dev->kbd_phase = 2; + break; + default: + fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } + + if (dev->kbd_in && (val < 0xed)) { + dev->kbd_in = 0; + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set LEDs [%02x]\n", val); + kbd_send_to_host(dev, 0xfa); + break; + + case 0xf0: /* get/set scancode set */ + kbd_send_to_host(dev, 0xfa); + if (val == 0) + dev->kbd_phase = 1; + else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_send_to_host(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); + kbd_send_to_host(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + } else { + /* No keyboard command in progress. */ + dev->kbd_in = 0; + dev->kbd_cmd = 0x00; + dev->kbd_phase = 0; + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + kbd_send_to_host(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + kbd_send_to_host(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + kbd_send_to_host(dev, 0xfa); + + dev->kbd_in = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + kbd_send_to_host(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + val, keyboard_scan, dev->mem[0x20]); + kbd_send_to_host(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + kbd_send_to_host(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbd_chip_reset(dev); + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + kbd_send_to_host(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) + dev->kbd_cmd = val; + } +} + + +static void +kbd_do_command(atkbd_t *dev) +{ + kbd_command(dev); + if (dev->kbd_written) + dev->kbd_poll_phase = KBD_CMD_PROCESS; + else if ((dev->kbd_phase == 0) && !dev->kbd_in) { + dev->kbd_in_cmd = 0; + if (dev->kbd_data != 0xf5) + keyboard_scan = 1; + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else { + keyboard_scan = 0; + dev->kbd_in_cmd = 1; + dev->kbd_poll_phase = KBD_CMD_PROCESS; + } +} + + +static void +kbd_nack(atkbd_t *dev) +{ + kbd_send_to_host(dev, 0xfe); + dev->kbd_poll_phase = KBD_MAIN_LOOP; +} + + +static void +kbd_main_loop(atkbd_t *dev) +{ + uint8_t scan = !dev->kbd_inhibit && keyboard_scan; + + if (dev->kbd_written) { + dev->kbd_written = 0; + kbd_cmd_process(dev); + } else if (scan && (key_queue_start != key_queue_end)) { + /* Scan here. */ + kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); + kbd_send_to_host(dev, key_queue[key_queue_start]); + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +kbd_cmd_process(atkbd_t *dev) +{ + uint8_t written = dev->kbd_written; + + /* We want data, nothing has been written yet, return. */ + if (dev->kbd_in && !dev->kbd_written) + return; + + dev->kbd_written = 0; + + if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { + kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); + kbd_do_command(dev); + } else if (dev->kbd_data == 0xfe) { + kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); + kbd_send_to_host(dev, kbd_last_scan_code); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data == 0xee) { + kbd_log("ATkbd: Echo EE\n"); + kbd_send_to_host(dev, 0xee); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data >= 0xed) { + kbd_log("ATkbd: Command %02X\n", dev->kbd_data); + if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { + kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); + keyboard_scan = 1; + dev->kbd_in_cmd = 0; + } + kbd_do_command(dev); + } else { + if (!keyboard_scan && dev->kbd_in_cmd) { + if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { + kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); + kbd_nack(dev); + } else { + kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); + kbd_do_command(dev); + } + } else { + kbd_log("ATkbd: Scanning or not in command, NACK\n"); + kbd_nack(dev); + } + } +} + + +/* Keyboard processing */ +static void +kbd_process(atkbd_t *dev) +{ + /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ + if (dev->kbc_written[1] && dev->kbd_written) + dev->kbc_written[1] = 0; + + /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ + if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { + case KBD_MAIN_LOOP: + kbd_main_loop(dev); + break; + case KBD_CMD_PROCESS: + kbd_cmd_process(dev); + break; + } +} + + +static void +kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t ch = (channel > 0) ? channel : 1; + uint8_t do_irq = (dev->mem[0x20] & ch); + int translate = (channel == 1) && (keyboard_mode & 0x60); + + if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) + return; + + stat_hi |= dev->inhibit; + + if (!dev->kbc_send_pending) { + dev->kbc_send_pending = 1; + dev->kbc_to_send = val; + dev->kbc_channel = channel; + dev->kbc_stat_hi = stat_hi; + return; + } + + if (translate) { + /* Allow for scan code translation. */ + if (val == 0xf0) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if ((sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + } + + dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; + if (do_irq) { + kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); + picint(dev->last_irq); + } + kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); + dev->ob = translate ? (nont_to_t[val] | sc_or) : val; + + dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); + if (ch == 2) + dev->status |= STAT_MFULL; + + if (translate && (sc_or == 0x80)) + sc_or = 0; +} + + +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); + + if (!(dev->flags & KBC_FLAG_PS2)) + val |= ((dev->mem[0x20] << 4) & 0x30); + + dev->kbd_inhibit = (val & 0x40); + dev->mouse_inhibit = (val & 0x08); + + if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) { + kbd_log("ATkbc: write_output(): IRQ 12\n"); + picint(1 << 12); + } else + picintc(1 << 12); + } + if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) { + kbd_log("ATkbc: write_output(): IRQ 1\n"); + picint(1 << 1); + } else + picintc(1 << 1); + } + if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->p2 ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->p2 = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + val &= ~CCB_TRANSLATE; + + dev->mem[0x20] = val; + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { + keyboard_mode &= ~CCB_PCMODE; + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + if (!(dev->flags & KBC_FLAG_PS2)) { + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + + +static void +kbc_transmit(atkbd_t *dev, uint8_t val) +{ + kbc_send_to_ob(dev, val, 0, 0x00); +} + + +static void +kbc_command(atkbd_t *dev) +{ + uint8_t mask, val = dev->ib; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int bad = 1; + + if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { + if (dev-> kbc_phase < 16) + kbc_transmit(dev, dev->mem[dev->kbc_phase]); + else if (dev-> kbc_phase == 16) + kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); + else if (dev-> kbc_phase == 17) + kbc_transmit(dev, dev->p2); + else if (dev-> kbc_phase == 18) + kbc_transmit(dev, dev->status); + + dev->kbc_phase++; + if (dev->kbc_phase == 19) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } + return; + } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { + val = ami_copr[dev->kbc_phase]; + kbc_transmit(dev, val); + if (val == 0x00) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } else + dev->kbc_phase++; + return; + } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { + /* load security */ + kbd_log("ATkbc: load security\n"); + dev->mem[0x50 + dev->kbc_in - 0x01] = val; + if ((dev->kbc_in == 0x80) && (val != 0x00)) { + /* Security string too long, set it to 0x00. */ + dev->mem[0x50] = 0x00; + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else if (val == 0x00) { + /* Security string finished. */ + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else /* Increase pointer and request another byte. */ + dev->kbc_in++; + return; + } + + /* If the written port is 64, go straight to the beginning of the command. */ + if (!(dev->status & STAT_CD) && dev->kbc_in) { + /* Write data to controller. */ + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (dev->kbc_cmd) { + case 0x60 ... 0x7f: + if (dev->kbc_cmd == 0x60) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + break; + + case 0xc7: /* or input port with system data */ + dev->p1 |= val; + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("New AMIKey mode: %02X\n", val); + dev->ami_mode = val; + dev->flags &= ~KBC_FLAG_PS2; + if (val & 1) + dev->flags |= KBC_FLAG_PS2; + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->p2_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->p2 & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + // kbc_send_to_ob(dev, val, 1, 0x00); + /* Should be channel 1, but we send to 0 to avoid translation, + since bytes output using this command do *NOT* get translated. */ + kbc_send_to_ob(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + kbc_send_to_ob(dev, val, 2, 0x00); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (dev->flags & KBC_FLAG_PS2) { + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x20; + if (mouse_write && !dev->kbc_written[2]) { + kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); + dev->mouse_data = val; + dev->mouse_written = 1; + dev->kbc_wait_for_response = 2; + } else + kbc_send_to_ob(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + +#ifdef ENABLE_KEYBOARD_AT_LOG + if (bad) + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); +#endif + } + } else { + /* Controller command. */ + kbd_log("ATkbc: Controller command: %02X\n", val); + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->kbc_in = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->kbd_in_cmd = dev->mouse_in_cmd = 0; + dev->status &= ~STAT_OFULL; + dev->last_irq = 0; + dev->kbc_phase = 0; + + /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ + if (dev->flags & KBC_FLAG_PS2) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + kbc_transmit(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + /* No error. */ + kbc_transmit(dev, 0x00); + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + kbc_transmit(dev, dev->mem[0x20]); + dev->kbc_phase = 1; + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* or input port with system data */ + kbd_log("ATkbc: Phoenix - or input port with system data\n"); + dev->kbc_in = 1; + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + kbc_transmit(dev, dev->ami_mode); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->kbc_in = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (dev->mem[0x20] & 0x10) + mask &= 0xbf; + if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) + mask &= 0xf7; + kbc_transmit(dev, dev->p2 & mask); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->kbc_in = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + dev->kbc_in = 1; + else + kbc_transmit(dev, 0x00); /* NCR */ + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + kbc_transmit(dev, 0x00); + break; + + case 0xe1: case 0xea: + kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); + write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); + } + + /* If the command needs data, remember the command. */ + if (dev->kbc_in || (dev->kbc_phase > 0)) + dev->kbc_cmd = val; + } +} + + +static void +kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) +{ + dev->kbc_written[channel] = 0; + kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); + kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); +} + + +static void +kbc_main_loop_scan(atkbd_t *dev) +{ + uint8_t port_dis = dev->mem[0x20] & 0x30; + uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); + + if (!ps2) + port_dis |= 0x20; + + if (!(dev->status & STAT_OFULL)) { + if (port_dis & 0x20) { + if (!(port_dis & 0x10)) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); + /* Enable communication with keyboard. */ + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 1); + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); + } +#endif + } else { + /* Enable communication with mouse. */ + dev->p2 &= 0xf7; + dev->mouse_inhibit = 0; + if (dev->mem[0x20] & 0x10) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); + kbc_wait(dev, 2); + } else { + /* Enable communication with keyboard. */ + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 3); + } + } + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + } +#endif +} + + +static void +kbc_process_ib(atkbd_t *dev) +{ + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + } else { + dev->mem[0x20] &= ~0x10; + dev->kbd_data = dev->ib; + dev->kbd_written = 1; + dev->kbc_wait_for_response = 1; + } + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response) + kbc_main_loop_scan(dev); +} + + +static void +kbc_wait(atkbd_t *dev, uint8_t flags) +{ + if ((flags & 1) && dev->kbc_written[1]) { + /* Disable communication with mouse. */ + dev->p2 |= 0x08; + dev->mouse_inhibit = 1; + /* Send keyboard byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_KBD); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if ((flags & 2) && dev->kbc_written[2]) { + /* Disable communication with keyboard. */ + dev->p2 |= 0x40; + dev->kbd_inhibit = 1; + /* Send mouse byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if (dev->status & STAT_IFULL) { + /* Disable communication with keyboard and mouse. */ + dev->p2 |= 0x48; + dev->kbd_inhibit = dev->mouse_inhibit = 1; + kbc_process_ib(dev); + } else + dev->kbc_poll_phase = KBC_WAIT | flags; +} + + +/* Controller processing */ +static void +kbc_process(atkbd_t *dev) +{ + // kbd_log("ATkbc: kbc_process()\n"); + + /* If we're waiting for the response from the keyboard or mouse, do nothing + until the device has repsonded back. */ + if (dev->kbc_wait_for_response > 0) { + if (dev->kbc_written[dev->kbc_wait_for_response]) + dev->kbc_wait_for_response = 0; + else + return; + } + + if (dev->kbc_send_pending) { + kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", + dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + dev->kbc_send_pending = 0; + } + + if (dev->kbc_poll_phase == KBC_RESET) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Reset loop()\n"); + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } + } + + return; + } + + if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: In a command\n"); + if (!dev->kbc_in && (dev->status & STAT_OFULL)) { + kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); + return; /* We do not want input and we're waiting for the host to read the data + we transmitted, but it has not done that yet, do nothing. */ + } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { + kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); + return; /* We want input and the host has not provided us with any yet, do nothing. */ + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: Normal condition\n"); +#endif + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + kbd_log("ATkbc: Resetting command\n"); + dev->kbc_phase = 0; + dev->kbc_in = 0; + } + } + + /* Process command. */ + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + + if (!(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ + } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { + case KBC_MAIN_LOOP: + // kbd_log("ATkbc: Main loop\n"); + if (dev->status & STAT_IFULL) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: IBF full, process\n"); + kbc_process_ib(dev); + } else + kbc_main_loop_scan(dev); + break; + case KBC_WAIT_FOR_KBD: + case KBC_WAIT_FOR_MOUSE: + case KBC_WAIT_FOR_BOTH: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); + kbc_wait(dev, dev->kbc_poll_phase & 3); + break; + default: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); + break; + } } @@ -742,105 +1795,29 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; -#ifdef ENABLE_KEYBOARD_AT_LOG - const uint8_t channels[4] = { 1, 2, 0, 0 }; -#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - if (dev->out_new != -1 && !dev->last_irq) { - dev->wantirq = 0; - if (dev->out_new & 0x100) { - if (dev->mem[0] & 0x02) - picint(0x1000); - kbd_log("ATkbc: %02X coming from channel 2\n"); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; - dev->last_irq = 2; - } - } + /* We process all three devices at the same time, in an arbitrary order. */ - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); - dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new = mouse_queue[mouse_queue_start] | 0x100; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { - kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - } + /* Keyboard processing */ + kbd_process(dev); - if (dev->reset_delay) { - dev->reset_delay--; - if (!dev->reset_delay) { - kbd_log("ATkbc: Sending AA on keyboard reset...\n"); - add_data_kbd_direct(dev, 0xaa); - } - } -} + /* TODO: Mouse processing */ + // mouse_process(dev); - -static void -add_data(atkbd_t *dev, uint8_t val) -{ - kbd_log("ATkbc: add to queue\n"); - - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - kbc_queue_add(dev, val, 0, 0x00); - - if (!(dev->out_new & 0x300)) { - dev->out_delayed = dev->out_new; - dev->out_new = -1; - } + /* Controller processing */ + kbc_process(dev); } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); int i; - uint8_t or = 0; - uint8_t send; - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - for (i = 0; i < len; i++) { - if (translate) { - if (val[i] == 0xf0) { - or = 0x80; - continue; - } - send = nont_to_t[val[i]] | or; - if (or == 0x80) - or = 0; - } else - send = val[i]; - - add_data_kbd_queue(dev, 0, send); - } + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, 0, val[i]); } @@ -848,56 +1825,21 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->reset_delay) + if (dev->kbd_in || (dev->kbd_phase > 0)) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Allow for scan code translation. */ - if (translate && (val == 0xf0)) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && - (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { - case 0x4f: t3100e_notify_set(0x01); break; /* End */ - case 0x50: t3100e_notify_set(0x02); break; /* Down */ - case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ - case 0x52: t3100e_notify_set(0x04); break; /* Ins */ - case 0x53: t3100e_notify_set(0x05); break; /* Del */ - case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ - case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ - case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ - case 0x47: t3100e_notify_set(0x09); break; /* Home */ - case 0x48: t3100e_notify_set(0x0a); break; /* Up */ - case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ - case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ - case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ - case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ - case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ - } + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && + (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) + t3100e_notify_set((val + 2) & 0x0f); - kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1030,18 +1972,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("scan code: "); - if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) - kbd_log("F0 "); - kbd_log("%02X)\n", val); - } else - kbd_log("%02X\n", val); -#endif - - add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); + add_data_kbd_queue(dev, 0, val); break; } @@ -1050,124 +1981,13 @@ add_data_kbd(uint16_t val) } -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) - val |= ((dev->mem[0] << 4) & 0x10); - - if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) - picint(1 << 12); - else - picintc(1 << 12); - } - if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) - picint(1 << 1); - else - picintc(1 << 1); - } - if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->output_port ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->output_port = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); - - if ((val & 1) && (dev->status & STAT_OFULL)) - dev->wantirq = 1; - if (!(val & 1) && dev->wantirq) - dev->wantirq = 0; - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { - val &= ~CCB_TRANSLATE; - dev->mem[0] &= ~CCB_TRANSLATE; - } - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || - ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { - keyboard_mode &= ~CCB_PCMODE; - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->output_port); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_output_port = dev->output_port & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); - write_output(dev, dev->output_port & (0xf0 | mask)); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); - write_output(dev, dev->output_port | dev->old_output_port); -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xef; - dev->mem[0] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xdf; - dev->mem[0] |= (enable ? 0x00 : 0x20); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); + write_output(dev, dev->p2 | dev->old_p2); } @@ -1176,49 +1996,70 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; switch (val) { case 0xa4: /* check if password installed */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: check if password installed\n"); - add_data(dev, 0xf1); + kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); + return 0; + } + break; + + case 0xa5: /* load security */ + if (dev->flags & KBC_FLAG_PS2) { + kbd_log("ATkbc: load security\n"); + dev->kbc_in = 1; return 0; } break; case 0xa7: /* disable mouse port */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: disable mouse port\n"); - set_enable_mouse(dev, 0); + // kbc_transmit(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: enable mouse port\n"); - set_enable_mouse(dev, 1); + // kbc_transmit(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ + if (dev->flags & KBC_FLAG_PS2) { + /* No error, this is testing the channel 2 interface. */ + kbc_transmit(dev, 0x00); return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - add_data(dev, 0x00); + kbc_transmit(dev, 0x00); return 0; case 0xc0: /* read input port */ + /* IBM PS/1: + Bit 2 and 4 ignored (we return always 0), + Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". + Intel AMI: + Bit 2 ignored (we return always 1), + Bit 4 must be 1, + Bit 6 must be 1 or else error in SMM. + Acer: + Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), + Bit 4 must be 0, + Bit 6 ignored. + P6RP4: + Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -1226,11 +2067,8 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc) | - (fdd_is_525(current_drive) ? 0x40 : 0x00); + kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -1242,39 +2080,34 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && - ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); + pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); + // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); else - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, dev->p1 | fixed_bits); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -1289,35 +2122,168 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; - switch(dev->command) { - /* 0x40 - 0x5F are aliases for 0x60-0x7F */ - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) + switch(dev->kbc_cmd) { + /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + if (dev->kbc_cmd == 0x40) write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM\n"); - if (dev->secr_phase == 1) { - dev->mem_addr = val; - dev->want60 = 1; - dev->secr_phase = 2; - } else if (dev->secr_phase == 2) { - dev->mem[dev->mem_addr] = val; + kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); + if (dev->secr_phase == 0) { + dev->mem_index = val; + dev->kbc_in = 1; + dev->secr_phase++; + } else if (dev->secr_phase == 1) { + if (dev->mem_index == 0x20) + write_cmd(dev, val); + else + dev->mem[dev->mem_index] = val; dev->secr_phase = 0; } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); + dev->mem_index = val; + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + dev->mem[index + dev->mem_index] = val; + } else if (dev->mem_index == 0x60) + write_cmd(dev, val); + else if (dev->mem_index == 0x42) + dev->status = val; + else if (dev->mem_index >= 0x40) + dev->mem[dev->mem_index - 0x40] = val; + else + dev->mem_int[dev->mem_index] = val; + return 0; + + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + dev->status = val; + break; + case 0x01: /* Password_ptr */ + dev->mem[0x1c] = val; + break; + case 0x02: /* Wakeup_Tsk_Reg */ + dev->mem[0x1e] = val; + break; + case 0x03: /* CCB */ + write_cmd(dev, val); + break; + case 0x04: /* Debounce_time */ + dev->mem[0x4d] = val; + break; + case 0x05: /* Pulse_Width */ + dev->mem[0x4e] = val; + break; + case 0x06: /* Pk_sel_byte */ + dev->mem[0x4c] = val; + break; + case 0x07: /* Func_Tsk_Reg */ + dev->mem[0x7e] = val; + break; + case 0x08: /* TypematicRate */ + dev->mem[0x80] = val; + break; + case 0x09: /* Led_Flag_Byte */ + dev->mem[0x81] = val; + break; + case 0x0a: /* Kbms_Command_St */ + dev->mem[0x87] = val; + break; + case 0x0b: /* Delay_Count_Byte */ + dev->mem[0x86] = val; + break; + case 0x0c: /* KBC_Flags */ + dev->mem[0x9b] = val; + break; + case 0x0d: /* SCODE_HK1 */ + dev->mem[0x50] = val; + break; + case 0x0e: /* SCODE_HK2 */ + dev->mem[0x51] = val; + break; + case 0x0f: /* SCODE_HK3 */ + dev->mem[0x52] = val; + break; + case 0x10: /* SCODE_HK4 */ + dev->mem[0x53] = val; + break; + case 0x11: /* SCODE_HK5 */ + dev->mem[0x54] = val; + break; + case 0x12: /* SCODE_HK6 */ + dev->mem[0x55] = val; + break; + case 0x13: /* TASK_HK1 */ + dev->mem[0x56] = val; + break; + case 0x14: /* TASK_HK2 */ + dev->mem[0x57] = val; + break; + case 0x15: /* TASK_HK3 */ + dev->mem[0x58] = val; + break; + case 0x16: /* TASK_HK4 */ + dev->mem[0x59] = val; + break; + case 0x17: /* TASK_HK5 */ + dev->mem[0x5a] = val; + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + dev->mem[0x5b] = val; + break; + case 0x19: /* Batt_Alarm_Reg1 */ + dev->mem[0x5c] = val; + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + dev->mem[0x5d] = val; + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + dev->mem[0x5e] = val; + break; + case 0x1c: /* Kbc_State1 */ + dev->mem[0x9d] = val; + break; + case 0x1d: /* Aux_Config */ + dev->mem[0x75] = val; + break; + case 0x1e: /* Kbc_State3 */ + dev->mem[0x73] = val; + break; + } + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->p1 = val; + return 0; + case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -1331,62 +2297,50 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; switch (val) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x00 ... 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - add_data(dev, dev->mem[val]); + kbc_transmit(dev, dev->mem[val + 0x20]); return 0; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->want60 = 1; + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + dev->kbc_in = 1; return 0; case 0xa0: /* copyright message */ - add_data(dev, 0x28); - add_data(dev, 0x00); - break; + kbc_transmit(dev, ami_copr[0]); + dev->kbc_phase = 1; + return 0; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - add_data(dev, 'H'); + // kbc_transmit(dev, 'H'); + kbc_transmit(dev, 'Z'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->output_port & 0xf3); - add_data(dev, 0x00); + write_output(dev, dev->p2 & 0xf3); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->output_port | 0x0c); - add_data(dev, 0x00); + write_output(dev, dev->p2 | 0x0c); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -1394,7 +2348,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -1402,15 +2356,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read clock\n"); - add_data(dev, !!(dev->ami_stat & 1)); + kbc_transmit(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -1418,7 +2372,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -1426,68 +2380,237 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read cache\n"); - add_data(dev, !!(dev->ami_stat & 2)); + kbc_transmit(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->want60 = 1; - dev->secr_phase = 1; + dev->kbc_in = 1; return 0; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb0 ... 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!PCI || (val > 0xb1)) - dev->input_port &= ~(1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { + dev->p1 &= ~(1 << (val & 0x03)); + } + kbc_transmit(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (! PCI) - write_output(dev, dev->output_port & ~(4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 & ~(4 << (val & 0x01))); + kbc_transmit(dev, 0x00); return 0; - case 0xb8: case 0xb9: case 0xba: case 0xbb: +#if 0 + case 0xb8 ... 0xbb: +#else + case 0xb9: +#endif /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!PCI || (val > 0xb9)) { - dev->input_port |= (1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + kbc_transmit(dev, 0x00); } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index\n"); + dev->kbc_in = 1; + return 0; + + case 0xba: + kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + kbc_transmit(dev, dev->mem[index + dev->mem_index]); + } else if (dev->mem_index == 0x42) + kbc_transmit(dev, dev->status); + else if (dev->mem_index >= 0x40) + kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); + else + kbc_transmit(dev, dev->mem_int[dev->mem_index]); + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + +#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (! PCI) - write_output(dev, dev->output_port | (4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 | (4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; +#endif + + case 0xbc: + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + kbc_transmit(dev, dev->status); + break; + case 0x01: /* Password_ptr */ + kbc_transmit(dev, dev->mem[0x1c]); + break; + case 0x02: /* Wakeup_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x1e]); + break; + case 0x03: /* CCB */ + kbc_transmit(dev, dev->mem[0x20]); + break; + case 0x04: /* Debounce_time */ + kbc_transmit(dev, dev->mem[0x4d]); + break; + case 0x05: /* Pulse_Width */ + kbc_transmit(dev, dev->mem[0x4e]); + break; + case 0x06: /* Pk_sel_byte */ + kbc_transmit(dev, dev->mem[0x4c]); + break; + case 0x07: /* Func_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x7e]); + break; + case 0x08: /* TypematicRate */ + kbc_transmit(dev, dev->mem[0x80]); + break; + case 0x09: /* Led_Flag_Byte */ + kbc_transmit(dev, dev->mem[0x81]); + break; + case 0x0a: /* Kbms_Command_St */ + kbc_transmit(dev, dev->mem[0x87]); + break; + case 0x0b: /* Delay_Count_Byte */ + kbc_transmit(dev, dev->mem[0x86]); + break; + case 0x0c: /* KBC_Flags */ + kbc_transmit(dev, dev->mem[0x9b]); + break; + case 0x0d: /* SCODE_HK1 */ + kbc_transmit(dev, dev->mem[0x50]); + break; + case 0x0e: /* SCODE_HK2 */ + kbc_transmit(dev, dev->mem[0x51]); + break; + case 0x0f: /* SCODE_HK3 */ + kbc_transmit(dev, dev->mem[0x52]); + break; + case 0x10: /* SCODE_HK4 */ + kbc_transmit(dev, dev->mem[0x53]); + break; + case 0x11: /* SCODE_HK5 */ + kbc_transmit(dev, dev->mem[0x54]); + break; + case 0x12: /* SCODE_HK6 */ + kbc_transmit(dev, dev->mem[0x55]); + break; + case 0x13: /* TASK_HK1 */ + kbc_transmit(dev, dev->mem[0x56]); + break; + case 0x14: /* TASK_HK2 */ + kbc_transmit(dev, dev->mem[0x57]); + break; + case 0x15: /* TASK_HK3 */ + kbc_transmit(dev, dev->mem[0x58]); + break; + case 0x16: /* TASK_HK4 */ + kbc_transmit(dev, dev->mem[0x59]); + break; + case 0x17: /* TASK_HK5 */ + kbc_transmit(dev, dev->mem[0x5a]); + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + kbc_transmit(dev, dev->mem[0x5b]); + break; + case 0x19: /* Batt_Alarm_Reg1 */ + kbc_transmit(dev, dev->mem[0x5c]); + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + kbc_transmit(dev, dev->mem[0x5d]); + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x5e]); + break; + case 0x1c: /* Kbc_State1 */ + kbc_transmit(dev, dev->mem[0x9d]); + break; + case 0x1d: /* Aux_Config */ + kbc_transmit(dev, dev->mem[0x75]); + break; + case 0x1e: /* Kbc_State3 */ + kbc_transmit(dev, dev->mem[0x73]); + break; + default: + kbc_transmit(dev, 0x00); + break; + } + kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); return 0; - case 0xc8: + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->kbc_in = 1; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->p1 &= 0xef; + kbc_transmit(dev, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->p1 &= 0xdf; + kbc_transmit(dev, 0x00); + return 0; + + case 0xc8: case 0xc9: /* - * unblock KBC lines P22/P23 + * (un)block KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); - dev->output_locked = 1; + kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); + dev->p2_locked = (val & 1); return 0; - case 0xc9: - /* - * block KBC lines P22/P23 - * (disallow command D1 from changing bits 2/3 of the port) - */ - kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); - dev->output_locked = 1; + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->p1 |= 0x10; + kbc_transmit(dev, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->p1 |= 0x20; + kbc_transmit(dev, 0x00); return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -1508,23 +2631,20 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -1539,7 +2659,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -1548,12 +2668,34 @@ write60_quadtel(void *priv, uint8_t val) return 1; } + static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { + /* This appears to be a clone of "Read input port", in which case, the bis would be: + 7: M290 (AT KBC): + Keyboard lock (1 = unlocked, 0 = locked); + M300 (PS/2 KBC): + Bus expansion board present (1 = present, 0 = not present); + 6: Usually: + Display (1 = MDA, 0 = CGA, but can have its polarity inverted); + 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); + 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); + 3: Fast Ram check (if inactive keyboard works erratically); + 2: Keyboard fuse present + This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; + 1: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Mouse data in; + 0: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Key data in. + */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -1562,11 +2704,9 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); return 0; - } + } return write64_generic(dev, val); } @@ -1584,7 +2724,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } @@ -1597,7 +2737,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -1640,29 +2780,30 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - add_data(dev, t3100e_config_get()); + kbc_transmit(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - add_data(dev, t3100e_mono_get()); + kbc_transmit(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_TYPE_MASK; + dev->flags &= ~KBC_FLAG_PS2; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_TYPE_PS2_NOREF; - } else { - kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); - dev->flags |= KBC_TYPE_ISA; + dev->flags |= KBC_FLAG_PS2; } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); +#endif return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -1672,8 +2813,9 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - add_data(dev, 0x04); - else add_data(dev, 0x00); + kbc_transmit(dev, 0x04); + else + kbc_transmit(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -1686,8 +2828,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - add_data(dev, dev->input_port); + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + kbc_transmit(dev, dev->p1); return 0; } @@ -1700,423 +2842,52 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i = 0, bad = 1; - uint8_t mask, kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - - kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); + kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); switch (port) { case 0x60: - dev->status &= ~STAT_CD; - if (dev->want60) { - /* Write data to controller. */ - dev->want60 = 0; + dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (dev->command) { - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) - write_cmd(dev, val); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->output_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->output_port & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - add_to_kbc_queue_front(dev, val, 0, 0x00); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - keyboard_at_adddata_mouse(val); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (val == 0xbb) - break; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - set_enable_mouse(dev, 1); - if (mouse_write) - mouse_write(val, mouse_p); - else - add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - - if (bad) { - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); - add_data_kbd(0xfe); - } - } - } else { - /* Write data to keyboard. */ - dev->mem[0] &= ~0x10; - - if (dev->key_wantdata) { - dev->key_wantdata = 0; - - /* - * Several system BIOSes and OS device drivers - * mess up with this, and repeat the command - * code many times. Fun! - */ - if (val == dev->key_command) { - /* Respond NAK and ignore it. */ - add_data_kbd(0xfe); - dev->key_command = 0x00; - break; - } - - switch (dev->key_command) { - case 0xed: /* set/reset LEDs */ - add_data_kbd_direct(dev, 0xfa); - kbd_log("ATkbd: set LEDs [%02x]\n", val); - break; - - case 0xf0: /* get/set scancode set */ - add_data_kbd_direct(dev, 0xfa); - if (val == 0) { - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - add_data_kbd_direct(dev, keyboard_mode & 3); - } else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - add_data_kbd_direct(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); - add_data_kbd_direct(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - dev->key_command = 0x00; - } else { - /* No keyboard command in progress. */ - dev->key_command = 0x00; - - set_enable_kbd(dev, 1); - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - add_data_kbd_direct(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - add_data_kbd_direct(dev, 0xfe); - break; - - /* Sent by Pentium-era AMI BIOS'es.*/ - case 0x71: case 0x82: - kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - add_data_kbd_direct(dev, 0xfa); - - dev->key_wantdata = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - add_data_kbd_direct(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - add_data_kbd_direct(dev, 0xfa); - add_data_kbd_direct(dev, 0xab); - add_data_kbd_direct(dev, 0x83); - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", - val, keyboard_scan, dev->mem[0]); - add_data_kbd_direct(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_raw(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbc_queue_reset(1); - kbd_last_scan_code = 0x00; - add_data_kbd_direct(dev, 0xfa); - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->reset_delay = RESET_DELAY_TIME; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - add_data_kbd_direct(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if (dev->key_wantdata == 1) - dev->key_command = val; - } +#if 0 + if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { + dev->status &= ~STAT_IFULL; + write_output(dev, val); + dev->fast_a20_phase = 0; } +#endif break; - - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if (kbc_ven == KBC_VEN_XI8088) - xi8088_turbo_set(!!(val & 0x04)); - break; - case 0x64: - /* Controller command. */ - dev->want60 = 0; - dev->status |= STAT_CD; + dev->status |= (STAT_CD | STAT_IFULL); + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (val) { - /* Read data from KBC memory. */ - case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - add_data(dev, dev->mem[val & 0x1f]); - break; - - /* Write data to KBC memory. */ - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->want60 = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) - dev->status |= STAT_IFULL; - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - dev->last_irq = dev->old_last_irq = 0; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_data(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - add_data(dev, 0x00); /*no error*/ - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - for (i = 0; i < 16; i++) - add_data(dev, dev->mem[i]); - add_data(dev, (dev->input_port & 0xf0) | 0x80); - add_data(dev, dev->output_port); - add_data(dev, dev->status); - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->want60 = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) - mask &= 0xbf; - add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->want60 = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - dev->want60 = 1; - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - add_data(dev, 0x00); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); +#if 0 + if (val == 0xd1) { + dev->status &= ~STAT_IFULL; + dev->fast_a20_phase = 1; + } else if (val == 0xfe) { + dev->status &= ~STAT_IFULL; + pulse_output(dev, 0x0e); + } else if ((val == 0xad) || (val == 0xae)) { + dev->status &= ~STAT_IFULL; + if (val & 0x01) + dev->mem[0x20] |= 0x10; + else + dev->mem[0x20] &= ~0x10; + } else if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); } - - /* If the command needs data, remember the command. */ - if (dev->want60) - dev->command = val; +#else + /* if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); + } */ + kbc_process(dev); +#endif break; } } @@ -2127,83 +2898,20 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - cycles -= ISA_CYCLES(8); - - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; + // if (dev->flags & KBC_FLAG_PS2) + // cycles -= ISA_CYCLES(8); switch (port) { case 0x60: - ret = dev->out; + ret = dev->ob; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if (kbc_ven == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) - ret |= 0x04; - else - ret &= ~0x04; - } - break; - - case 0x62: - ret = 0xff; - if (kbc_ven == KBC_VEN_OLIVETTI) { - /* SWA on Olivetti M240 mainboard (off=1) */ - ret = 0x00; - if (ppi.pb & 0x8) { - /* Switches 4, 5 - floppy drives (number) */ - int i, fdd_count = 0; - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } - if (!fdd_count) - ret |= 0x00; - else - ret |= ((fdd_count - 1) << 2); - /* Switches 6, 7 - monitor type */ - if (video_is_mda()) - ret |= 0x3; - else if (video_is_cga()) - ret |= 0x2; /* 0x10 would be 40x25 */ - else - ret |= 0x0; - } else { - /* bit 2 always on */ - ret |= 0x4; - /* Switch 8 - 8087 FPU. */ - if (hasfpu) - ret |= 0x02; - } - } - break; case 0x64: - ret = (dev->status & 0xfb); - if (dev->mem[0] & STAT_SYSFLAG) - ret |= STAT_SYSFLAG; - /* Only clear the transmit timeout flag on non-PS/2 controllers, as on - PS/2 controller, it is the keyboard/mouse output source bit. */ - // dev->status &= ~STAT_RTIMEOUT; - if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && - (kbc_ven != KBC_VEN_IBM_MCA)) - dev->status &= ~STAT_TTIMEOUT; + ret = dev->status; break; default: @@ -2211,22 +2919,12 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); + kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); return(ret); } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { @@ -2235,25 +2933,26 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; - dev->first_write = 1; - // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0] = 0x01; - dev->mem[0] |= CCB_TRANSLATE; - dev->wantirq = 0; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; write_output(dev, 0xcf); - dev->last_irq = dev->old_last_irq = 0; + dev->last_irq = 0; dev->secr_phase = 0; - dev->key_wantdata = 0; + dev->kbd_in = 0; + dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); /* Set up the correct Video Type bits. */ + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + dev->p1 ^= 0x40; + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + dev->inhibit = ((dev->p1 & 0x80) >> 3); else - dev->input_port = video_is_mda() ? 0xf0 : 0xb0; - kbd_log("ATkbc: input port = %02x\n", dev->input_port); + dev->inhibit = 0x10; + kbd_log("ATkbc: input port = %02x\n", dev->p1); - keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2261,16 +2960,18 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0; + dev->ob = 0xff; sc_or = 0; + for (i = 1; i <= 2; i++) + kbc_queue_reset(i); + memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->mem[0x31] = 0xfe; } @@ -2292,7 +2993,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2316,17 +3016,14 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - kbd_reset(dev); + dev->kbc_poll_phase = KBC_RESET; + kbd_send_to_host(dev, 0xaa); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -2342,12 +3039,14 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: + /* The Olivetti controller is a special case - starts directly in the + main loop instead of the reset loop. */ + dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2367,6 +3066,8 @@ kbd_init(const device_t *info) break; } + kbd_reset(dev); + /* We need this, sadly. */ SavedKbd = dev; @@ -2394,16 +3095,6 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; -const device_t keyboard_at_samsung_device = { - "PC/AT Keyboard (Samsung)", - 0, - KBC_TYPE_ISA | KBC_VEN_SAMSUNG, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -2435,16 +3126,6 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -2457,7 +3138,7 @@ const device_t keyboard_ps2_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2467,7 +3148,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2487,7 +3168,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2497,7 +3178,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -2527,7 +3208,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -2537,7 +3218,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2547,7 +3228,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2557,7 +3238,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -2567,7 +3248,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + KBC_TYPE_PS2_1 | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -2578,17 +3259,8 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - mouse_write = func; - mouse_p = priv; -} - - -void -keyboard_at_adddata_keyboard_raw(uint8_t val) -{ - atkbd_t *dev = SavedKbd; - - add_data_kbd_queue(dev, 0, val); + // mouse_write = func; + // mouse_p = priv; } @@ -2601,10 +3273,30 @@ keyboard_at_adddata_mouse(uint8_t val) } +void +keyboard_at_adddata_mouse_direct(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + void keyboard_at_mouse_reset(void) { - kbc_queue_reset(2); + // atkbd_t *dev = SavedKbd; + + return; } @@ -2615,13 +3307,22 @@ keyboard_at_mouse_pos(void) } +int +keyboard_at_fixed_channel(void) +{ + // atkbd_t *dev = SavedKbd; + + return 0x000; +} + + void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -2635,7 +3336,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); } @@ -2644,5 +3345,17 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); + write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); +} + + +void +keyboard_at_set_mode(int ps2) +{ + atkbd_t *dev = SavedKbd; + + if (ps2) + dev->flags |= KBC_FLAG_PS2; + else + dev->flags &= ~KBC_FLAG_PS2; } From 4a6f5ed045821ac30411c2aaf23c997cbf4021bc Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 10 Aug 2021 15:55:33 +0200 Subject: [PATCH 045/140] Disabled keyboard logging. --- src/device/keyboard_at.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index c0507ffb5..7f5ee51db 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -673,7 +673,6 @@ kbd_status(const char *fmt, ...) } -#define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; From 80bc644692633cd27f026ab17240fce0328c759e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 12 Aug 2021 11:10:16 +0200 Subject: [PATCH 046/140] ALi and SMC fixes. --- src/chipset/ali1489.c | 10 +++++++--- src/sio/sio_fdc37c66x.c | 15 +++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index 6c90cf7d0..330792b78 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -74,6 +74,9 @@ typedef struct } ali1489_t; +static void ali1489_ide_handler(ali1489_t *dev); + + static void ali1489_shadow_recalc(ali1489_t *dev) { @@ -121,8 +124,7 @@ ali1489_smram_recalc(ali1489_t *dev) smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, (dev->regs[0x19] & 0x08), 1); break; case 0x20: - if ((dev->regs[0x14] & 0x03) == 0x00) - smram_enable(dev->smram, 0xe0000, 0xe0000, 0x10000, (dev->regs[0x19] & 0x08), 1); + smram_enable(dev->smram, 0xe0000, 0xe0000, 0x10000, (dev->regs[0x19] & 0x08), 1); break; case 0x30: if ((dev->regs[0x35] & 0xc0) == 0x80) @@ -203,6 +205,8 @@ ali1489_defaults(ali1489_t *dev) pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + ali1489_ide_handler(dev); } @@ -459,7 +463,7 @@ ali1489_ide_handler(ali1489_t *dev) { ide_pri_disable(); ide_sec_disable(); - if (dev->regs[0x01] & 0x01) { + if (dev->ide_regs[0x01] & 0x01) { ide_pri_enable(); if (!(dev->ide_regs[0x35] & 0x40)) ide_sec_enable(); diff --git a/src/sio/sio_fdc37c66x.c b/src/sio/sio_fdc37c66x.c index 3cda6c206..812bbf91b 100644 --- a/src/sio/sio_fdc37c66x.c +++ b/src/sio/sio_fdc37c66x.c @@ -73,7 +73,7 @@ set_com34_addr(fdc37c66x_t *dev) static void set_serial_addr(fdc37c66x_t *dev, int port) { - uint8_t shift = (port << 4); + uint8_t shift = (port << 2); double clock_src = 24000000.0 / 13.0; if (dev->regs[4] & (1 << (4 + port))) @@ -81,7 +81,7 @@ set_serial_addr(fdc37c66x_t *dev, int port) serial_remove(dev->uart[port]); if (dev->regs[2] & (4 << shift)) { - switch (dev->regs[2] & (3 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { case 0: serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); break; @@ -112,11 +112,11 @@ lpt1_handler(fdc37c66x_t *dev) break; case 2: lpt1_init(0x378); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; case 3: lpt1_init(0x278); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; } } @@ -264,6 +264,13 @@ fdc37c66x_reset(fdc37c66x_t *dev) dev->regs[0xd] = dev->chip_id; dev->regs[0xe] = 0x01; + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + if (dev->has_ide) ide_handler(dev); } From 4e8600e3b1e370687dd6dba5cc560e5552a1db82 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 16:56:17 +0200 Subject: [PATCH 047/140] PS/2 mouse command F6. --- src/device/mouse_ps2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index f8ba676e0..649182ca5 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -194,6 +194,7 @@ ps2_write(uint8_t val, void *priv) keyboard_at_adddata_mouse_cmd(0xfa); break; + case 0xf6: /* set defaults */ case 0xff: /* reset */ mouse_reset: dev->mode = MODE_STREAM; @@ -201,8 +202,10 @@ mouse_reset: mouse_scan = 1; keyboard_at_mouse_reset(); keyboard_at_adddata_mouse_cmd(0xfa); - keyboard_at_adddata_mouse_cmd(0xaa); - keyboard_at_adddata_mouse_cmd(0x00); + if (dev->command == 0xff) { + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); + } break; default: From 19c374c0463231466d283310ba385cb960a28a25 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 16:58:27 +0200 Subject: [PATCH 048/140] Temporary changes to make merger possible. --- src/device/mouse_ps2.c | 61 ++++++++++------------ src/disk/hdc_ide_sff8038i.c | 101 +++++++++--------------------------- 2 files changed, 51 insertions(+), 111 deletions(-) diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 649182ca5..3fe743748 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -93,27 +93,22 @@ ps2_write(uint8_t val, void *priv) mouse_t *dev = (mouse_t *)priv; uint8_t temp; - pclog("ps2_write(%02X)\n", val); - if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; - if (val == 0xff) - goto mouse_reset; - switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf3: /* set sample rate */ dev->sample_rate = val; - keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ + keyboard_at_adddata_mouse(0xfa); /* Command response */ break; default: - keyboard_at_adddata_mouse_cmd(0xfc); + keyboard_at_adddata_mouse(0xfc); } } else { dev->command = val; @@ -121,21 +116,21 @@ ps2_write(uint8_t val, void *priv) switch (dev->command) { case 0xe6: /* set scaling to 1:1 */ dev->flags &= ~FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe7: /* set scaling to 2:1 */ dev->flags |= FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe8: /* set mouse resolution */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe9: /* status request */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); temp = (dev->flags & 0x30); if (mouse_buttons & 0x01) temp |= 0x01; @@ -143,13 +138,13 @@ ps2_write(uint8_t val, void *priv) temp |= 0x02; if (mouse_buttons & 0x04) temp |= 0x03; - keyboard_at_adddata_mouse_cmd(temp); - keyboard_at_adddata_mouse_cmd(dev->resolution); - keyboard_at_adddata_mouse_cmd(dev->sample_rate); + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(dev->resolution); + keyboard_at_adddata_mouse(dev->sample_rate); break; case 0xeb: /* Get mouse data */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); temp = 0; if (dev->x < 0) @@ -162,54 +157,53 @@ ps2_write(uint8_t val, void *priv) temp |= 2; if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI)) temp |= 4; - keyboard_at_adddata_mouse_cmd(temp); - keyboard_at_adddata_mouse_cmd(dev->x & 0xff); - keyboard_at_adddata_mouse_cmd(dev->y & 0xff); + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(dev->x & 0xff); + keyboard_at_adddata_mouse(dev->y & 0xff); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse_cmd(dev->z); + keyboard_at_adddata_mouse(dev->z); break; case 0xf2: /* read ID */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse_cmd(0x03); + keyboard_at_adddata_mouse(0x03); else - keyboard_at_adddata_mouse_cmd(0x00); + keyboard_at_adddata_mouse(0x00); break; case 0xf3: /* set command mode */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */ break; case 0xf4: /* enable */ dev->flags |= FLAG_ENABLED; mouse_scan = 1; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf5: /* disable */ dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf6: /* set defaults */ case 0xff: /* reset */ -mouse_reset: dev->mode = MODE_STREAM; dev->flags &= 0x88; - mouse_scan = 1; + mouse_scan = 0; keyboard_at_mouse_reset(); - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); if (dev->command == 0xff) { - keyboard_at_adddata_mouse_cmd(0xaa); - keyboard_at_adddata_mouse_cmd(0x00); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); } break; default: - keyboard_at_adddata_mouse_cmd(0xfe); + keyboard_at_adddata_mouse(0xfe); } } @@ -241,9 +235,6 @@ ps2_poll(int x, int y, int z, int b, void *priv) return(0xff); #endif - if ((keyboard_at_fixed_channel() & 0xf00) == 0x200) - return(0xff); - if (!mouse_scan) return(0xff); diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 023883720..733868cc3 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -370,49 +370,32 @@ void sff_bus_master_set_irq(int channel, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; - dev->status &= ~0x04; - dev->status |= (channel >> 4); + if (!(dev->status & 0x04) || (channel & 0x40)) { + dev->status &= ~4; + dev->status |= (channel >> 4); + } channel &= 0x01; - - switch (dev->irq_mode[channel]) { - case 0: - default: - /* Legacy IRQ mode. */ - if (dev->status & 0x04) - picint(1 << (14 + channel)); - else - picintc(1 << (14 + channel)); - break; - case 1: - /* Native PCI IRQ mode with interrupt pin. */ - if (dev->status & 0x04) - pci_set_irq(dev->slot, dev->irq_pin); - else - pci_clear_irq(dev->slot, dev->irq_pin); - break; - case 2: - case 5: - /* MIRQ 0 or 1. */ - if (dev->status & 0x04) - pci_set_mirq(dev->irq_mode[channel] & 1, 0); - else - pci_clear_mirq(dev->irq_mode[channel] & 1, 0); - break; - case 3: - /* Native PCI IRQ mode with specified interrupt line. */ - if (dev->status & 0x04) - picintlevel(1 << dev->irq_line); - else - picintc(1 << dev->irq_line); - break; - case 4: - /* ALi Aladdin Native PCI INTAJ mode. */ - if (dev->status & 0x04) - pci_set_mirq(channel + 2, dev->irq_level[channel]); - else - pci_clear_mirq(channel + 2, dev->irq_level[channel]); - break; + if (dev->status & 0x04) { + sff_log("SFF8038i: Channel %i IRQ raise\n", channel); + if (dev->irq_mode[channel] == 3) + picintlevel(1 << dev->irq_line); + else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) + pci_set_mirq(0, 0); + else if (dev->irq_mode[channel] == 1) + pci_set_irq(dev->slot, dev->irq_pin); + else + picint(1 << (14 + channel)); + } else { + sff_log("SFF8038i: Channel %i IRQ lower\n", channel); + if (dev->irq_mode[channel] == 3) + picintc(1 << dev->irq_line); + else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) + pci_clear_mirq(0, 0); + else if (dev->irq_mode[channel] == 1) + pci_clear_irq(dev->slot, dev->irq_pin); + else + picintc(1 << (14 + channel)); } } @@ -485,42 +468,10 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } -void -sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) -{ - dev->irq_level[channel] = 0; -} - - void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; - - switch (dev->irq_mode[channel]) { - case 0: - default: - /* Legacy IRQ mode. */ - sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); - break; - case 1: - /* Native PCI IRQ mode with interrupt pin. */ - sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); - break; - case 2: - case 5: - /* MIRQ 0 or 1. */ - sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); - break; - case 3: - /* Native PCI IRQ mode with specified interrupt line. */ - sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); - break; - case 4: - /* ALi Aladdin Native PCI INTAJ mode. */ - sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); - break; - } } @@ -557,11 +508,9 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ - dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ + dev->irq_mode[0] = dev->irq_mode[1] = 2; dev->irq_pin = PCI_INTA; dev->irq_line = 14; - dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; From 583f84a8b42dbf707df64617291adf61af55745f Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:00:30 +0200 Subject: [PATCH 049/140] And back. --- src/device/mouse_ps2.c | 61 +++++++++++++---------- src/disk/hdc_ide_sff8038i.c | 97 ++++++++++++++++++++++++++++--------- 2 files changed, 110 insertions(+), 48 deletions(-) diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 3fe743748..649182ca5 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -93,22 +93,27 @@ ps2_write(uint8_t val, void *priv) mouse_t *dev = (mouse_t *)priv; uint8_t temp; + pclog("ps2_write(%02X)\n", val); + if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; + if (val == 0xff) + goto mouse_reset; + switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xf3: /* set sample rate */ dev->sample_rate = val; - keyboard_at_adddata_mouse(0xfa); /* Command response */ + keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ break; default: - keyboard_at_adddata_mouse(0xfc); + keyboard_at_adddata_mouse_cmd(0xfc); } } else { dev->command = val; @@ -116,21 +121,21 @@ ps2_write(uint8_t val, void *priv) switch (dev->command) { case 0xe6: /* set scaling to 1:1 */ dev->flags &= ~FLAG_SCALED; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe7: /* set scaling to 2:1 */ dev->flags |= FLAG_SCALED; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe8: /* set mouse resolution */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xe9: /* status request */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); temp = (dev->flags & 0x30); if (mouse_buttons & 0x01) temp |= 0x01; @@ -138,13 +143,13 @@ ps2_write(uint8_t val, void *priv) temp |= 0x02; if (mouse_buttons & 0x04) temp |= 0x03; - keyboard_at_adddata_mouse(temp); - keyboard_at_adddata_mouse(dev->resolution); - keyboard_at_adddata_mouse(dev->sample_rate); + keyboard_at_adddata_mouse_cmd(temp); + keyboard_at_adddata_mouse_cmd(dev->resolution); + keyboard_at_adddata_mouse_cmd(dev->sample_rate); break; case 0xeb: /* Get mouse data */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); temp = 0; if (dev->x < 0) @@ -157,53 +162,54 @@ ps2_write(uint8_t val, void *priv) temp |= 2; if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI)) temp |= 4; - keyboard_at_adddata_mouse(temp); - keyboard_at_adddata_mouse(dev->x & 0xff); - keyboard_at_adddata_mouse(dev->y & 0xff); + keyboard_at_adddata_mouse_cmd(temp); + keyboard_at_adddata_mouse_cmd(dev->x & 0xff); + keyboard_at_adddata_mouse_cmd(dev->y & 0xff); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse(dev->z); + keyboard_at_adddata_mouse_cmd(dev->z); break; case 0xf2: /* read ID */ - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse(0x03); + keyboard_at_adddata_mouse_cmd(0x03); else - keyboard_at_adddata_mouse(0x00); + keyboard_at_adddata_mouse_cmd(0x00); break; case 0xf3: /* set command mode */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */ + keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ break; case 0xf4: /* enable */ dev->flags |= FLAG_ENABLED; mouse_scan = 1; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xf5: /* disable */ dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); break; case 0xf6: /* set defaults */ case 0xff: /* reset */ +mouse_reset: dev->mode = MODE_STREAM; dev->flags &= 0x88; - mouse_scan = 0; + mouse_scan = 1; keyboard_at_mouse_reset(); - keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse_cmd(0xfa); if (dev->command == 0xff) { - keyboard_at_adddata_mouse(0xaa); - keyboard_at_adddata_mouse(0x00); + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); } break; default: - keyboard_at_adddata_mouse(0xfe); + keyboard_at_adddata_mouse_cmd(0xfe); } } @@ -235,6 +241,9 @@ ps2_poll(int x, int y, int z, int b, void *priv) return(0xff); #endif + if ((keyboard_at_fixed_channel() & 0xf00) == 0x200) + return(0xff); + if (!mouse_scan) return(0xff); diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 733868cc3..b5362e6f9 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -371,31 +371,50 @@ sff_bus_master_set_irq(int channel, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; if (!(dev->status & 0x04) || (channel & 0x40)) { - dev->status &= ~4; + dev->status &= ~0x04; dev->status |= (channel >> 4); } channel &= 0x01; - if (dev->status & 0x04) { - sff_log("SFF8038i: Channel %i IRQ raise\n", channel); - if (dev->irq_mode[channel] == 3) - picintlevel(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_set_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_set_irq(dev->slot, dev->irq_pin); - else - picint(1 << (14 + channel)); - } else { - sff_log("SFF8038i: Channel %i IRQ lower\n", channel); - if (dev->irq_mode[channel] == 3) - picintc(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_clear_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_clear_irq(dev->slot, dev->irq_pin); - else - picintc(1 << (14 + channel)); + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + if (dev->status & 0x04) + picint(1 << (14 + channel)); + else + picintc(1 << (14 + channel)); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + if (dev->status & 0x04) + pci_set_irq(dev->slot, dev->irq_pin); + else + pci_clear_irq(dev->slot, dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + if (dev->status & 0x04) + pci_set_mirq(dev->irq_mode[channel] & 1, 0); + else + pci_clear_mirq(dev->irq_mode[channel] & 1, 0); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + if (dev->status & 0x04) + picintlevel(1 << dev->irq_line); + else + picintc(1 << dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + if (dev->status & 0x04) + pci_set_mirq(channel + 2, dev->irq_level[channel]); + else + pci_clear_mirq(channel + 2, dev->irq_level[channel]); + break; } } @@ -468,10 +487,42 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } +void +sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) +{ + dev->irq_level[channel] = 0; +} + + void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); + break; + } } @@ -508,9 +559,11 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = dev->irq_mode[1] = 2; + dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ + dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ dev->irq_pin = PCI_INTA; dev->irq_line = 14; + dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; From d9eb945fafa69b851cc3b4895ae5be2db46009fc Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:18:08 +0200 Subject: [PATCH 050/140] Let's do this again. --- src/disk/hdc_ide_sff8038i.c | 99 +++++++++---------------------------- 1 file changed, 24 insertions(+), 75 deletions(-) diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index b5362e6f9..b00b2a66d 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -370,51 +370,34 @@ void sff_bus_master_set_irq(int channel, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; + uint8_t irq = !!(channel & 0x40); + if (!(dev->status & 0x04) || (channel & 0x40)) { - dev->status &= ~0x04; + dev->status &= ~4; dev->status |= (channel >> 4); } channel &= 0x01; - - switch (dev->irq_mode[channel]) { - case 0: - default: - /* Legacy IRQ mode. */ - if (dev->status & 0x04) - picint(1 << (14 + channel)); - else - picintc(1 << (14 + channel)); - break; - case 1: - /* Native PCI IRQ mode with interrupt pin. */ - if (dev->status & 0x04) - pci_set_irq(dev->slot, dev->irq_pin); - else - pci_clear_irq(dev->slot, dev->irq_pin); - break; - case 2: - case 5: - /* MIRQ 0 or 1. */ - if (dev->status & 0x04) - pci_set_mirq(dev->irq_mode[channel] & 1, 0); - else - pci_clear_mirq(dev->irq_mode[channel] & 1, 0); - break; - case 3: - /* Native PCI IRQ mode with specified interrupt line. */ - if (dev->status & 0x04) - picintlevel(1 << dev->irq_line); - else - picintc(1 << dev->irq_line); - break; - case 4: - /* ALi Aladdin Native PCI INTAJ mode. */ - if (dev->status & 0x04) - pci_set_mirq(channel + 2, dev->irq_level[channel]); - else - pci_clear_mirq(channel + 2, dev->irq_level[channel]); - break; + if (irq) { + sff_log("SFF8038i: Channel %i IRQ raise\n", channel); + if (dev->irq_mode[channel] == 3) + picintlevel(1 << dev->irq_line); + else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) + pci_set_mirq(0, 0); + else if (dev->irq_mode[channel] == 1) + pci_set_irq(dev->slot, dev->irq_pin); + else + picint(1 << (14 + channel)); + } else { + sff_log("SFF8038i: Channel %i IRQ lower\n", channel); + if (dev->irq_mode[channel] == 3) + picintc(1 << dev->irq_line); + else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) + pci_clear_mirq(0, 0); + else if (dev->irq_mode[channel] == 1) + pci_clear_irq(dev->slot, dev->irq_pin); + else + picintc(1 << (14 + channel)); } } @@ -487,42 +470,10 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } -void -sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) -{ - dev->irq_level[channel] = 0; -} - - void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; - - switch (dev->irq_mode[channel]) { - case 0: - default: - /* Legacy IRQ mode. */ - sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); - break; - case 1: - /* Native PCI IRQ mode with interrupt pin. */ - sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); - break; - case 2: - case 5: - /* MIRQ 0 or 1. */ - sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); - break; - case 3: - /* Native PCI IRQ mode with specified interrupt line. */ - sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); - break; - case 4: - /* ALi Aladdin Native PCI INTAJ mode. */ - sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); - break; - } } @@ -559,11 +510,9 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ - dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ + dev->irq_mode[0] = dev->irq_mode[1] = 2; dev->irq_pin = PCI_INTA; dev->irq_line = 14; - dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; From 0cebc8669ae081b093c685775b365ac7a26e8648 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:20:25 +0200 Subject: [PATCH 051/140] And back. --- src/disk/hdc_ide_sff8038i.c | 97 ++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index b00b2a66d..44d9ad545 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -373,31 +373,50 @@ sff_bus_master_set_irq(int channel, void *priv) uint8_t irq = !!(channel & 0x40); if (!(dev->status & 0x04) || (channel & 0x40)) { - dev->status &= ~4; + dev->status &= ~0x04; dev->status |= (channel >> 4); } channel &= 0x01; - if (irq) { - sff_log("SFF8038i: Channel %i IRQ raise\n", channel); - if (dev->irq_mode[channel] == 3) - picintlevel(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_set_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_set_irq(dev->slot, dev->irq_pin); - else - picint(1 << (14 + channel)); - } else { - sff_log("SFF8038i: Channel %i IRQ lower\n", channel); - if (dev->irq_mode[channel] == 3) - picintc(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_clear_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_clear_irq(dev->slot, dev->irq_pin); - else - picintc(1 << (14 + channel)); + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + if (irq) + picint(1 << (14 + channel)); + else + picintc(1 << (14 + channel)); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + if (irq) + pci_set_irq(dev->slot, dev->irq_pin); + else + pci_clear_irq(dev->slot, dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + if (irq) + pci_set_mirq(dev->irq_mode[channel] & 1, 0); + else + pci_clear_mirq(dev->irq_mode[channel] & 1, 0); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + if (irq) + picintlevel(1 << dev->irq_line); + else + picintc(1 << dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + if (irq) + pci_set_mirq(channel + 2, dev->irq_level[channel]); + else + pci_clear_mirq(channel + 2, dev->irq_level[channel]); + break; } } @@ -470,10 +489,42 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } +void +sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) +{ + dev->irq_level[channel] = 0; +} + + void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); + break; + } } @@ -510,9 +561,11 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = dev->irq_mode[1] = 2; + dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ + dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ dev->irq_pin = PCI_INTA; dev->irq_line = 14; + dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; From 70870be9e25b7f1b27a1d4e0f2ec409aae088c6a Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:25:58 +0200 Subject: [PATCH 052/140] CPL is now forced to 0 when switching from real to protected mode. --- src/cpu/x86_ops_mov_ctrl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 16e7aa7fa..17f51b971 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -125,6 +125,9 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) case 0: if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) flushmmucache(); + /* Make sure CPL = 0 when switching from real mode to protected mode. */ + if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) + cpu_state.seg_cs.access &= 0x9f; cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; @@ -181,6 +184,9 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) case 0: if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) flushmmucache(); + /* Make sure CPL = 0 when switching from real mode to protected mode. */ + if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) + cpu_state.seg_cs.access &= 0x9f; cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; From f99f6bcf1808a9ef75e320c18378e9ce55e0993c Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:28:17 +0200 Subject: [PATCH 053/140] The relocated SMBASE read from the SMM saved state now has bits 24-31 cleared. --- src/cpu/386_common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index fbb67df1c..77b5ed373 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -592,7 +592,7 @@ smram_restore_state_p5(uint32_t *saved_state) smm_seg_load(&cpu_state.seg_gs); if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION) - smbase = saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET]; + smbase = saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET] & 0x00ffffff; /* Am486/5x86 stuff */ if (!is_pentium) { @@ -1306,6 +1306,11 @@ leave_smm(void) x386_common_log("EAX = %08X, EBX = %08X, ECX = %08X, EDX = %08X, ESI = %08X, EDI = %08X, ESP = %08X, EBP = %08X\n", EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP); x386_common_log("leave_smm()\n"); + + if (cr0 & 1) + pclog("%s mode\n", (cpu_state.eflags & VM_FLAG) ? "V86" : "Protected"); + else + pclog("Real mode\n"); } From 660956a15dfe05bfa89407fae3b62cdc1367b093 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:29:41 +0200 Subject: [PATCH 054/140] AMD K6 CPU's are no longer treated as K6 for SMM purposes. --- src/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 5da0778ab..e29bca7d5 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -381,7 +381,7 @@ cpu_set(void) and the WinChip datasheet claims those are Pentium-compatible as well. AMD Am486DXL/DXL2 also has compatible SMM, or would if not for it's different SMBase*/ is_pentium = (cpu_isintel && (cpu_s->cpu_type >= CPU_i486SX_SLENH) && (cpu_s->cpu_type < CPU_PENTIUMPRO)) || !strcmp(cpu_f->manufacturer, "IDT") || (cpu_s->cpu_type == CPU_Am486DXL); - is_k5 = !strcmp(cpu_f->manufacturer, "AMD") && (cpu_s->cpu_type > CPU_ENH_Am486DX); + is_k5 = !strcmp(cpu_f->manufacturer, "AMD") && (cpu_s->cpu_type > CPU_ENH_Am486DX) && (cpu_s->cpu_type < CPU_K6); is_k6 = (cpu_s->cpu_type >= CPU_K6) && !strcmp(cpu_f->manufacturer, "AMD"); /* The Samuel 2 datasheet claims it's Celeron-compatible. */ is_p6 = (cpu_isintel && (cpu_s->cpu_type >= CPU_PENTIUMPRO)) || !strcmp(cpu_f->manufacturer, "VIA"); From 66cef5b762c5cea738de59226451fee01eac63d9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:30:52 +0200 Subject: [PATCH 055/140] Removed excess logging from 386_common.c. --- src/cpu/386_common.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 77b5ed373..1c5fa8b3e 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1306,11 +1306,6 @@ leave_smm(void) x386_common_log("EAX = %08X, EBX = %08X, ECX = %08X, EDX = %08X, ESI = %08X, EDI = %08X, ESP = %08X, EBP = %08X\n", EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP); x386_common_log("leave_smm()\n"); - - if (cr0 & 1) - pclog("%s mode\n", (cpu_state.eflags & VM_FLAG) ? "V86" : "Protected"); - else - pclog("Real mode\n"); } From a76fda99d8038a03c78ab9679fc16fcd7c564d37 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 17:50:42 +0200 Subject: [PATCH 056/140] Various Super I/O chip rewrites and fixes (and implemented dual-chip mode for the SMC FDC73C669). --- src/include/86box/sio.h | 1 + src/sio/sio_fdc37c651.c | 344 +++++++++++++++++++++++++++------------- src/sio/sio_fdc37c661.c | 120 ++++++++------ src/sio/sio_fdc37c669.c | 95 +++++++---- src/sio/sio_fdc37c66x.c | 2 +- src/sio/sio_w83977f.c | 28 ++-- 6 files changed, 387 insertions(+), 203 deletions(-) diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 1786a9569..3b90f72c8 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -21,6 +21,7 @@ extern void vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv); extern const device_t acc3221_device; extern const device_t f82c710_device; extern const device_t fdc37c651_device; +extern const device_t fdc37c651_ide_device; extern const device_t fdc37c661_device; extern const device_t fdc37c663_device; extern const device_t fdc37c663_ide_device; diff --git a/src/sio/sio_fdc37c651.c b/src/sio/sio_fdc37c651.c index 2bfd3fd93..a19460d4c 100644 --- a/src/sio/sio_fdc37c651.c +++ b/src/sio/sio_fdc37c651.c @@ -6,10 +6,11 @@ * * This file is part of the 86Box distribution. * - * Emulation of the SMC FDC37C651 Super I/O + * Implementation of the SMC FDC37C651 Super I/O Chip. * - * Authors: Tiseno100 - * Copyright 2020 Tiseno100 + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. */ #include #include @@ -30,15 +31,17 @@ #include <86box/fdc.h> #include <86box/sio.h> + #ifdef ENABLE_FDC37C651_LOG int fdc37c651_do_log = ENABLE_FDC37C651_LOG; + + static void fdc37c651_log(const char *fmt, ...) { va_list ap; - if (fdc37c651_do_log) - { + if (fdc37c651_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); @@ -48,143 +51,264 @@ fdc37c651_log(const char *fmt, ...) #define fdc37c651_log(fmt, ...) #endif -typedef struct -{ - uint8_t configuration_select, regs[3]; - uint16_t com3, com4; - fdc_t *fdc_controller; +typedef struct { + uint8_t tries, has_ide, + regs[16]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; serial_t *uart[2]; - } fdc37c651_t; + static void -fdc37c651_write(uint16_t addr, uint8_t val, void *priv) +set_com34_addr(fdc37c651_t *dev) { - fdc37c651_t *dev = (fdc37c651_t *)priv; - - switch (addr) - { - case 0x3f0: - dev->configuration_select = val; - break; - case 0x3f1: - switch (dev->configuration_select) - { - case 0: /* CR0 */ - dev->regs[dev->configuration_select] = val; - ide_pri_disable(); - fdc_remove(dev->fdc_controller); - - if (val & 1) /* Enable IDE */ - ide_pri_enable(); - - if (val & 0x10) /* Enable FDC */ - fdc_set_base(dev->fdc_controller, 0x3f0); - - break; - - case 1: /* CR1 */ - dev->regs[dev->configuration_select] = val; - lpt1_remove(); - - if ((val & 3) != 0) /* Program LPT if not Disabled */ - lpt1_init((val & 2) ? ((val & 1) ? 0x278 : 0x378) : 0x3f8); - - switch ((val >> 4) & 3) /* COM3 & 4 Select*/ - { - case 0: - dev->com3 = 0x338; - dev->com4 = 0x238; - break; - case 1: - dev->com3 = 0x3e8; - dev->com4 = 0x2e8; - break; - case 2: - dev->com3 = 0x2e8; - dev->com4 = 0x2e0; - break; - case 3: - dev->com3 = 0x220; - dev->com4 = 0x228; - break; - } - - break; - - case 2: /* CR2 */ - dev->regs[dev->configuration_select] = val; - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); - - if (val & 4) - serial_setup(dev->uart[0], (val & 2) ? ((val & 1) ? dev->com4 : dev->com3) : ((val & 1) ? 0x2f8 : 0x3f8), 4); - - if (val & 0x40) - serial_setup(dev->uart[1], (val & 0x20) ? ((val & 0x10) ? dev->com4 : dev->com3) : ((val & 0x10) ? 0x2f8 : 0x3f8), 3); - - break; - } - break; + 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 uint8_t -fdc37c651_read(uint16_t addr, void *priv) -{ - fdc37c651_t *dev = (fdc37c651_t *)priv; - return dev->regs[dev->configuration_select]; +static void +set_serial_addr(fdc37c651_t *dev, int port) +{ + uint8_t shift = (port << 2); + + serial_remove(dev->uart[port]); + if (dev->regs[2] & (4 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { + 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(fdc37c651_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(7 /*5*/); + break; + case 3: + lpt1_init(0x278); + lpt1_irq(7 /*5*/); + break; + } +} + + +static void +fdc_handler(fdc37c651_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0] & 0x10) + fdc_set_base(dev->fdc, 0x03f0); +} + + + +static void +ide_handler(fdc37c651_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, 0x1f0); + ide_set_side(1, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_pri_enable(); + } +} + + +static void +fdc37c651_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c651_t *dev = (fdc37c651_t *) priv; + uint8_t valxor = 0; + + if (dev->tries == 2) { + if (port == 0x3f0) { + if (val == 0xaa) + dev->tries = 0; + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > 15) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 0: + if (dev->has_ide && (valxor & 0x01)) + ide_handler(dev); + if (valxor & 0x10) + fdc_handler(dev); + break; + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + } + break; + case 2: + if (valxor & 7) + set_serial_addr(dev, 0); + if (valxor & 0x70) + set_serial_addr(dev, 1); + break; + } + } + } else if ((port == 0x3f0) && (val == 0x55)) + dev->tries++; +} + + +static uint8_t +fdc37c651_read(uint16_t port, void *priv) +{ + fdc37c651_t *dev = (fdc37c651_t *) priv; + uint8_t ret = 0x00; + + if (dev->tries == 2) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +static void +fdc37c651_reset(fdc37c651_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); + fdc_remove(dev->fdc); + + dev->tries = 0; + memset(dev->regs, 0, 16); + + dev->regs[0x0] = 0x3f; + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + + if (dev->has_ide) + ide_handler(dev); +} + + static void fdc37c651_close(void *priv) { - fdc37c651_t *dev = (fdc37c651_t *)priv; + fdc37c651_t *dev = (fdc37c651_t *) priv; + free(dev); } + static void * fdc37c651_init(const device_t *info) { - fdc37c651_t *dev = (fdc37c651_t *)malloc(sizeof(fdc37c651_t)); + fdc37c651_t *dev = (fdc37c651_t *) malloc(sizeof(fdc37c651_t)); memset(dev, 0, sizeof(fdc37c651_t)); - dev->fdc_controller = device_add(&fdc_at_smc_device); + dev->fdc = device_add(&fdc_at_smc_device); + dev->uart[0] = device_add_inst(&ns16450_device, 1); dev->uart[1] = device_add_inst(&ns16450_device, 2); - device_add(&ide_isa_device); - /* Program Defaults */ - dev->regs[0] = 0x3f; - dev->regs[1] = 0x9f; - dev->regs[2] = 0xdc; - ide_pri_disable(); - fdc_remove(dev->fdc_controller); - lpt1_remove(); - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); + dev->has_ide = (info->local >> 8) & 0xff; - ide_pri_enable(); - fdc_set_base(dev->fdc_controller, 0x3f0); - lpt1_init(0x278); - serial_setup(dev->uart[0], 0x2f8, 4); - serial_setup(dev->uart[1], 0x3f8, 3); + io_sethandler(0x03f0, 0x0002, + fdc37c651_read, NULL, NULL, fdc37c651_write, NULL, NULL, dev); - io_sethandler(0x03f0, 2, fdc37c651_read, NULL, NULL, fdc37c651_write, NULL, NULL, dev); + fdc37c651_reset(dev); return dev; } + +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ const device_t fdc37c651_device = { - "SMC FDC37C651", + "SMC FDC37C651 Super I/O", 0, 0, - fdc37c651_init, - fdc37c651_close, - NULL, - {NULL}, - NULL, - NULL, - NULL}; + fdc37c651_init, fdc37c651_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t fdc37c651_ide_device = { + "SMC FDC37C651 Super I/O (With IDE)", + 0, + 0x100, + fdc37c651_init, fdc37c651_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_fdc37c661.c b/src/sio/sio_fdc37c661.c index 159a68d47..8a17053a6 100644 --- a/src/sio/sio_fdc37c661.c +++ b/src/sio/sio_fdc37c661.c @@ -6,8 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of the SMC FDC37C661 Super - * I/O Chip. + * Implementation of the SMC FDC37C661 Super I/O Chip. * * * @@ -16,7 +15,6 @@ * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. - * Copyright 2020 plant/nerd73. */ #include #include @@ -38,8 +36,8 @@ typedef struct { - uint8_t lock[2], - regs[4]; + uint8_t chip_id, tries, + has_ide, regs[16]; int cur_reg, com3_addr, com4_addr; fdc_t *fdc; @@ -47,19 +45,6 @@ typedef struct { } 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) { @@ -87,10 +72,11 @@ set_com34_addr(fdc37c661_t *dev) static void set_serial_addr(fdc37c661_t *dev, int port) { - uint8_t shift = (port << 4); + uint8_t shift = (port << 2); + serial_remove(dev->uart[port]); if (dev->regs[2] & (4 << shift)) { - switch (dev->regs[2] & (3 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { case 0: serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); break; @@ -119,11 +105,11 @@ lpt1_handler(fdc37c661_t *dev) break; case 2: lpt1_init(0x378); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; case 3: lpt1_init(0x278); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; } } @@ -134,7 +120,28 @@ fdc_handler(fdc37c661_t *dev) { fdc_remove(dev->fdc); if (dev->regs[0] & 0x10) - fdc_set_base(dev->fdc, 0x03f0); + fdc_set_base(dev->fdc, 0x03f0); +} + + + +static void +ide_handler(fdc37c661_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, 0x1f0); + ide_set_side(1, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_pri_enable(); + } } @@ -144,14 +151,14 @@ 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 (dev->tries == 2) { if (port == 0x3f0) { if (val == 0xaa) - write_lock(dev, val); + dev->tries = 0; else dev->cur_reg = val; } else { - if (dev->cur_reg > 4) + if (dev->cur_reg > 15) return; valxor = val ^ dev->regs[dev->cur_reg]; @@ -159,6 +166,8 @@ fdc37c661_write(uint16_t port, uint8_t val, void *priv) switch(dev->cur_reg) { case 0: + if (dev->has_ide && (valxor & 0x01)) + ide_handler(dev); if (valxor & 0x10) fdc_handler(dev); break; @@ -166,33 +175,21 @@ fdc37c661_write(uint16_t port, uint8_t val, void *priv) 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]); + if (valxor & 7) set_serial_addr(dev, 0); - } - if (valxor & 0x70) { - serial_remove(dev->uart[1]); + if (valxor & 0x70) 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); - } + } else if ((port == 0x3f0) && (val == 0x55)) + dev->tries++; } @@ -200,9 +197,9 @@ static uint8_t fdc37c661_read(uint16_t port, void *priv) { fdc37c661_t *dev = (fdc37c661_t *) priv; - uint8_t ret = 0xff; + uint8_t ret = 0x00; - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (dev->tries == 2) { if (port == 0x3f1) ret = dev->regs[dev->cur_reg]; } @@ -227,14 +224,25 @@ fdc37c661_reset(fdc37c661_t *dev) lpt1_init(0x378); fdc_reset(dev->fdc); + fdc_remove(dev->fdc); - memset(dev->lock, 0, 2); + dev->tries = 0; memset(dev->regs, 0, 16); dev->regs[0x0] = 0x3f; dev->regs[0x1] = 0x9f; dev->regs[0x2] = 0xdc; dev->regs[0x3] = 0x78; + + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + + if (dev->has_ide) + ide_handler(dev); } @@ -255,23 +263,37 @@ fdc37c661_init(const device_t *info) 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); + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + dev->chip_id = info->local & 0xff; + dev->has_ide = (info->local >> 8) & 0xff; io_sethandler(0x03f0, 0x0002, fdc37c661_read, NULL, NULL, fdc37c661_write, NULL, NULL, dev); fdc37c661_reset(dev); - + return dev; } + +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ const device_t fdc37c661_device = { "SMC FDC37C661 Super I/O", 0, - 0, + 0x00, fdc37c661_init, fdc37c661_close, NULL, { NULL }, NULL, NULL, NULL }; +const device_t fdc37c661_ide_device = { + "SMC FDC37C661 Super I/O (With IDE)", + 0, + 0x100, + fdc37c661_init, fdc37c661_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index b2d76814e..d223cf0df 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -33,7 +33,7 @@ typedef struct { - uint8_t tries, + uint8_t id, tries, regs[42]; int locked, rw_locked, cur_reg; @@ -42,6 +42,9 @@ typedef struct { } fdc37c669_t; +static int next_id = 0; + + static uint16_t make_port(fdc37c669_t *dev, uint8_t reg) { @@ -114,7 +117,7 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) switch(dev->cur_reg) { case 0: - if (valxor & 8) { + if (!dev->id && (valxor & 8)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -122,9 +125,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 1: if (valxor & 4) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } if (valxor & 7) dev->rw_locked = (val & 8) ? 0 : 1; @@ -142,23 +151,23 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 3: - if (valxor & 2) + if (!dev->id && (valxor & 2)) fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0); break; case 5: - if (valxor & 0x18) + if (!dev->id && (valxor & 0x18)) fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3); - if (valxor & 0x20) + if (!dev->id && (valxor & 0x20)) fdc_set_swap(dev->fdc, (val & 0x20) >> 5); break; case 0xB: - if (valxor & 3) + if (!dev->id && (valxor & 3)) fdc_update_rwc(dev->fdc, 0, val & 3); - if (valxor & 0xC) + if (!dev->id && (valxor & 0xC)) fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2); break; case 0x20: - if (valxor & 0xfc) { + if (!dev->id && (valxor & 0xfc)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -166,9 +175,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 0x23: if (valxor) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } break; case 0x24: @@ -186,8 +201,12 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 0x27: - if (valxor & 0xf) - lpt1_irq(val & 0xf); + if (valxor & 0xf) { + if (dev->id) + lpt2_irq(val & 0xf); + else + lpt1_irq(val & 0xf); + } break; case 0x28: if (valxor & 0xf) { @@ -226,17 +245,12 @@ fdc37c669_read(uint16_t port, void *priv) static void fdc37c669_reset(fdc37c669_t *dev) { - fdc_reset(dev->fdc); - 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); - memset(dev->regs, 0, 42); dev->regs[0x00] = 0x28; dev->regs[0x01] = 0x9c; @@ -249,11 +263,27 @@ fdc37c669_reset(fdc37c669_t *dev) dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - dev->regs[0x23] = (0x378 >> 2); - dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; - dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + if (dev->id == 1) { + dev->regs[0x23] = (0x278 >> 2); + + lpt2_remove(); + lpt2_init(0x278); + + dev->regs[0x24] = (SERIAL3_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (SERIAL4_ADDR >> 2) & 0xfe; + } else { + fdc_reset(dev->fdc); + + lpt1_remove(); + lpt1_init(0x378); + + dev->regs[0x23] = (0x378 >> 2); + + dev->regs[0x24] = (SERIAL1_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (SERIAL2_ADDR >> 2) & 0xfe; + } dev->regs[0x26] = (2 << 4) | 3; - dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x27] = (6 << 4) | (dev->id ? 5 : 7); dev->regs[0x28] = (4 << 4) | 3; dev->locked = 0; @@ -266,6 +296,8 @@ fdc37c669_close(void *priv) { fdc37c669_t *dev = (fdc37c669_t *) priv; + next_id = 0; + free(dev); } @@ -276,16 +308,21 @@ fdc37c669_init(const device_t *info) fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); memset(dev, 0, sizeof(fdc37c669_t)); - dev->fdc = device_add(&fdc_at_smc_device); + dev->id = next_id; - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (next_id != 1) + dev->fdc = device_add(&fdc_at_smc_device); - io_sethandler(info->local ? 0x370 : 0x3f0, 0x0002, + dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1); + dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2); + + io_sethandler(info->local ? 0x370 : (next_id ? 0x370 : 0x3f0), 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev); fdc37c669_reset(dev); + next_id++; + return dev; } diff --git a/src/sio/sio_fdc37c66x.c b/src/sio/sio_fdc37c66x.c index 812bbf91b..ce8776944 100644 --- a/src/sio/sio_fdc37c66x.c +++ b/src/sio/sio_fdc37c66x.c @@ -256,7 +256,7 @@ fdc37c66x_reset(fdc37c66x_t *dev) dev->tries = 0; memset(dev->regs, 0, 16); - dev->regs[0x0] = 0x2a; + dev->regs[0x0] = 0x3a; dev->regs[0x1] = 0x9f; dev->regs[0x2] = 0xdc; dev->regs[0x3] = 0x78; diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index dc3f1c012..46a75ac9e 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -268,11 +268,11 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0x20) + if (!dev->id && (valxor & 0x20)) fdc_update_drv2en(dev->fdc, (val & 0x20) ? 0 : 1); - if (valxor & 0x10) + if (!dev->id && (valxor & 0x10)) fdc_set_swap(dev->fdc, (val & 0x10) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_update_enh_mode(dev->fdc, (val & 0x01) ? 1 : 0); break; case 0x01: @@ -291,13 +291,13 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0xc0) + if (!dev->id && (valxor & 0xc0)) fdc_update_boot_drive(dev->fdc, (val & 0xc0) >> 6); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_densel_force(dev->fdc, (val & 0x0c) >> 2); - if (valxor & 0x02) + if (!dev->id && (valxor & 0x02)) fdc_set_diswr(dev->fdc, (val & 0x02) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_set_swwp(dev->fdc, (val & 0x01) ? 1 : 0); break; } @@ -308,13 +308,13 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0xc0) + if (!dev->id && (valxor & 0xc0)) fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); - if (valxor & 0x30) + if (!dev->id && (valxor & 0x30)) fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); - if (valxor & 0x03) + if (!dev->id && (valxor & 0x03)) fdc_update_rwc(dev->fdc, 0, val & 0x03); break; } @@ -325,7 +325,7 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0x18) + if (!dev->id && (valxor & 0x18)) fdc_update_drvrate(dev->fdc, dev->cur_reg & 0x03, (val & 0x18) >> 3); break; } @@ -347,7 +347,7 @@ w83977f_read(uint16_t port, void *priv) ret = dev->cur_reg; else { if (!dev->rw_locked) { - if ((dev->cur_reg == 0xf2) && (ld == 0x00)) + if (!dev->id && ((dev->cur_reg == 0xf2) && (ld == 0x00))) ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); else if (dev->cur_reg >= 0x30) ret = dev->dev_regs[ld][dev->cur_reg - 0x30]; @@ -506,7 +506,7 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[10][0xc0] = 0x8f; } - if (next_id == 1) { + if (dev->id == 1) { serial_setup(dev->uart[0], SERIAL3_ADDR, SERIAL3_IRQ); serial_setup(dev->uart[1], SERIAL4_ADDR, SERIAL4_IRQ); } else { From 3e7057d458cd818dad6af24c98ebd1e09a489282 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Aug 2021 19:18:40 +0200 Subject: [PATCH 057/140] Changes to lpt.h. --- src/include/86box/lpt.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 7fecd4ce7..109de58ba 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -21,15 +21,15 @@ extern void lpt_port_irq(int i, uint8_t irq); extern void lpt_port_remove(int i); extern void lpt1_remove_ams(void); -#define lpt1_init(a) lpt_port_init(0, a); -#define lpt1_irq(a) lpt_port_irq(0, a); -#define lpt1_remove() lpt_port_remove(0); -#define lpt2_init(a) lpt_port_init(1, a); -#define lpt2_irq(a) lpt_port_irq(1, a); -#define lpt2_remove() lpt_port_remove(1); -#define lpt3_init(a) lpt_port_init(2, a); -#define lpt3_irq(a) lpt_port_irq(2, a); -#define lpt3_remove() lpt_port_remove(2); +#define lpt1_init(a) lpt_port_init(0, a) +#define lpt1_irq(a) lpt_port_irq(0, a) +#define lpt1_remove() lpt_port_remove(0) +#define lpt2_init(a) lpt_port_init(1, a) +#define lpt2_irq(a) lpt_port_irq(1, a) +#define lpt2_remove() lpt_port_remove(1) +#define lpt3_init(a) lpt_port_init(2, a) +#define lpt3_irq(a) lpt_port_irq(2, a) +#define lpt3_remove() lpt_port_remove(2) void lpt_devices_init(void); From 67367798a7ccc06647994eb26230a7d3f58f17b8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 21 Aug 2021 18:19:10 +0200 Subject: [PATCH 058/140] Merged various SMC FDC67C6xx Super I/O chips into one file, re-added the UMC88xx 486 chipsets (and four machines for it) based on work by tiseno100 and my own work, various other fixes, and added quite a few machines (including the AOpen AP5VM which now works), also added the remaining ALi M6117 machine (Protech SBC with Award BIOS), and made the Intel Advanced/ATX's on-board S3 Trio64V+ work, as well as the on-board S3 Trio64/V2 of the two Compaq Presarios. --- src/chipset/CMakeLists.txt | 4 +- src/chipset/intel_piix.c | 22 ++ src/chipset/sis_85c50x.c | 3 +- src/chipset/umc_8886.c | 219 ++++++++----- src/chipset/umc_8890.c | 180 ----------- src/chipset/umc_hb4.c | 272 +++++++++------- src/device/keyboard_at.c | 9 +- src/include/86box/chipset.h | 5 + src/include/86box/machine.h | 17 + src/include/86box/pci.h | 2 + src/include/86box/video.h | 3 + src/io.c | 6 +- src/machine/m_at_286_386sx.c | 54 +++- src/machine/m_at_386dx_486.c | 164 +++++++++- src/machine/m_at_compaq.c | 4 +- src/machine/m_at_slot1.c | 7 +- src/machine/m_at_socket4.c | 65 ++++ src/machine/m_at_socket7.c | 64 +++- src/machine/m_at_socket7_3v.c | 10 + src/machine/m_at_sockets7.c | 41 +++ src/machine/machine.c | 4 + src/machine/machine_table.c | 37 ++- src/pci.c | 15 +- src/port_92.c | 17 +- src/sio/CMakeLists.txt | 4 +- src/sio/sio_fdc37c651.c | 314 ------------------- src/sio/sio_fdc37c661.c | 299 ------------------ src/sio/{sio_fdc37c66x.c => sio_fdc37c6xx.c} | 130 ++++++-- src/video/vid_s3.c | 31 +- src/video/vid_table.c | 44 ++- src/video/vid_tgui9440.c | 118 ++++--- src/win/Makefile.mingw | 7 +- 32 files changed, 1030 insertions(+), 1141 deletions(-) delete mode 100644 src/chipset/umc_8890.c delete mode 100644 src/sio/sio_fdc37c651.c delete mode 100644 src/sio/sio_fdc37c661.c rename src/sio/{sio_fdc37c66x.c => sio_fdc37c6xx.c} (71%) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index c015e900d..4e46e0db4 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -18,8 +18,8 @@ add_library(chipset OBJECT acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1 intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c - sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c via_apollo.c via_pipc.c vl82c480.c - wd76c10.c) + sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c + via_pipc.c vl82c480.c wd76c10.c) if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index f4c9bcb68..a694da235 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1234,6 +1234,17 @@ piix_reset(void *p) piix_write(3, 0x91, 0x00, p); piix_write(3, 0xd2, 0x00, p); } + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[1], 0, 0); + + if (dev->type >= 4) { + sff_set_irq_mode(dev->bm[0], 1, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } else { + sff_set_irq_mode(dev->bm[0], 1, 2); + sff_set_irq_mode(dev->bm[1], 1, 2); + } } @@ -1286,6 +1297,17 @@ static void ide_board_set_force_ata3(1, 1); } + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[1], 0, 0); + + if (dev->type >= 4) { + sff_set_irq_mode(dev->bm[0], 1, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } else { + sff_set_irq_mode(dev->bm[0], 1, 2); + sff_set_irq_mode(dev->bm[1], 1, 2); + } + if (dev->type >= 3) dev->usb = device_add(&usb_device); diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c index bbc8a8ec5..c01690064 100644 --- a/src/chipset/sis_85c50x.c +++ b/src/chipset/sis_85c50x.c @@ -107,8 +107,7 @@ sis_85c50x_smm_recalc(sis_85c50x_t *dev) switch ((dev->pci_conf[0x65] & 0xe0) >> 5) { case 0x00: - if (!(dev->pci_conf[0x54] & 0xc0)) - smram_enable(dev->smram, 0xe0000, 0xe0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1); + smram_enable(dev->smram, 0xe0000, 0xe0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1); break; case 0x01: smram_enable(dev->smram, 0xb0000, ram_base, 0x10000, (dev->pci_conf[0x65] & 0x10), 1); diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index ca492a0b8..b3e721e9f 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -16,10 +16,11 @@ * Copyright 2021 Tiseno100. */ -/* UMC 8886 Configuration Registers +/* + UMC 8886xx Configuration Registers - TODO: - - More Appropriate Bitmasking(If it's even possible) + Note: PMU functionality is quite basic. There may be Enable/Disable bits, IRQ/SMI picks and it also + required for 386_common.c to get patched in order to function properly. Warning: Register documentation may be inaccurate! @@ -35,10 +36,8 @@ Bits 3-0 PCI IRQ for INTC Function 0 Register 46: - Bit 7: Replace SMI request for non-SMM CPU's (1: IRQ15/0: IRQ10) - - Function 0 Register 51: - Bit 2: VGA Power Down (0: Standard/1: VESA DPMS) + Bit 7: PMU Trigger(1: By IRQ/0: By SMI) + Bit 6: IRQ SMI Request (1: IRQ 10) (Supposedly 0 according to Phoenix is IRQ 15 but doesn't seem to make sense) Function 0 Register 56: Bit 1-0 ISA Bus Speed @@ -46,10 +45,14 @@ 0 1 PCICLK/4 1 0 PCICLK/2 + Function 0 Register A3: + Bit 7: Unlock SMM + Bit 6: Software SMI trigger + Function 0 Register A4: Bit 0: Host to PCI Clock (1: 1 by 1/0: 1 by half) - Function 1 Register 4: + Function 1 Register 4: (UMC 8886AF/8886BF Only!) Bit 0: Enable Internal IDE */ @@ -69,6 +72,7 @@ #include <86box/hdd.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> +#include <86box/pic.h> #include <86box/pci.h> #include <86box/chipset.h> @@ -76,16 +80,17 @@ #ifdef ENABLE_UMC_8886_LOG int umc_8886_do_log = ENABLE_UMC_8886_LOG; + + static void umc_8886_log(const char *fmt, ...) { va_list ap; - if (umc_8886_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + if (umc_8886_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -94,23 +99,24 @@ umc_8886_log(const char *fmt, ...) /* PCI IRQ Flags */ -#define INTA (PCI_INTA + (2 * !(addr & 1))) -#define INTB (PCI_INTB + (2 * !(addr & 1))) -#define IRQRECALCA (((val & 0xf0) != 0) ? ((val & 0xf0) >> 4) : PCI_IRQ_DISABLED) -#define IRQRECALCB (((val & 0x0f) != 0) ? (val & 0x0f) : PCI_IRQ_DISABLED) +#define INTA (PCI_INTA + (2 * !(addr & 1))) +#define INTB (PCI_INTB + (2 * !(addr & 1))) +#define IRQRECALCA (((val & 0xf0) != 0) ? ((val & 0xf0) >> 4) : PCI_IRQ_DISABLED) +#define IRQRECALCB (((val & 0x0f) != 0) ? (val & 0x0f) : PCI_IRQ_DISABLED) -/* Disable Internal IDE Flag needed for the BF Southbridge variant */ -#define HAS_IDE dev->has_ide +/* Disable Internal IDE Flag needed for the AF or BF Southbridge variant */ +#define HAS_IDE dev->has_ide /* Southbridge Revision */ -#define SB_ID dev->sb_id +#define SB_ID dev->sb_id typedef struct umc_8886_t { - uint8_t pci_conf_sb[2][256]; /* PCI Registers */ - uint16_t sb_id; /* Southbridge Revision */ - int has_ide; /* Check if Southbridge Revision is AF or F */ + uint8_t pci_conf_sb[2][256]; /* PCI Registers */ + uint16_t sb_id; /* Southbridge Revision */ + int has_ide; /* Check if Southbridge Revision is AF or F */ + } umc_8886_t; @@ -121,39 +127,69 @@ umc_8886_ide_handler(int status) ide_sec_disable(); if (status) { - ide_pri_enable(); - ide_sec_enable(); + ide_pri_enable(); + ide_sec_enable(); } } static void -um8886_write(int func, int addr, uint8_t val, void *priv) +umc_8886_write(int func, int addr, uint8_t val, void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; - umc_8886_log("UM8886: dev->regs[%02x] = %02x (%02x)\n", addr, val, func); - /* We don't know the RW status of registers but Phoenix writes on some RO registers too*/ - if (addr > 3) switch (func) { - case 0: /* Southbridge */ + switch (func) { + case 0: /* PCI to ISA Bridge */ + umc_8886_log("UM8886: dev->regs[%02x] = %02x POST %02x\n", addr, val, inb(0x80)); + switch (addr) { - case 0x43: - case 0x44: + case 0x04: case 0x05: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x07: + dev->pci_conf_sb[func][addr] &= ~(val & 0xf9); + break; + + case 0x0c: case 0x0d: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x40: case 0x41: + case 0x42: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x43: case 0x44: dev->pci_conf_sb[func][addr] = val; pci_set_irq_routing(INTA, IRQRECALCA); pci_set_irq_routing(INTB, IRQRECALCB); break; + case 0x45: + dev->pci_conf_sb[func][addr] = val; + break; + case 0x46: - dev->pci_conf_sb[func][addr] = val & 0xaf; + dev->pci_conf_sb[func][addr] = val; + + if (val & 0x40) + picint(1 << ((val & 0x80) ? 15 : 10)); + break; case 0x47: - dev->pci_conf_sb[func][addr] = val & 0x4f; + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: + dev->pci_conf_sb[func][addr] = val; break; case 0x56: dev->pci_conf_sb[func][addr] = val; + switch (val & 2) { case 0: cpu_set_isa_pci_div(3); @@ -165,51 +201,65 @@ um8886_write(int func, int addr, uint8_t val, void *priv) cpu_set_isa_pci_div(2); break; } + break; case 0x57: - dev->pci_conf_sb[func][addr] = val & 0x38; + case 0x70 ... 0x76: + case 0x80: case 0x81: + case 0x90 ... 0x92: + case 0xa0 ... 0xa2: + dev->pci_conf_sb[func][addr] = val; break; - case 0x71: - dev->pci_conf_sb[func][addr] = val & 1; - break; + case 0xa3: + dev->pci_conf_sb[func][addr] = val; - case 0x90: - dev->pci_conf_sb[func][addr] = val & 2; - break; + /* SMI Provocation (Bit 7 Enable SMM + Bit 6 Software SMI */ + if (((dev->pci_conf_sb[0][0xa3] >> 6) == 3) && !in_smm) + smi_line = 1; - case 0x92: - dev->pci_conf_sb[func][addr] = val & 0x1f; - break; - - case 0xa0: - dev->pci_conf_sb[func][addr] = val & 0xfc; break; case 0xa4: - dev->pci_conf_sb[func][addr] = val & 0x89; + dev->pci_conf_sb[func][addr] = val; cpu_set_pci_speed(cpu_busspeed / ((val & 1) ? 1 : 2)); break; - default: + case 0xa5 ... 0xa8: dev->pci_conf_sb[func][addr] = val; break; } break; - case 1: /* IDE Controller */ - dev->pci_conf_sb[func][addr] = val; - if ((addr == 4) && HAS_IDE) - umc_8886_ide_handler(val & 1); + + case 1: /* IDE Controller */ + umc_8886_log("UM8886-IDE: dev->regs[%02x] = %02x POST: %02x\n", addr, val, inb(0x80)); + + switch (addr) { + case 0x04: + dev->pci_conf_sb[func][addr] = val; + umc_8886_ide_handler(val & 1); + break; + + case 0x07: + dev->pci_conf_sb[func][addr] &= ~(val & 0xf9); + break; + + case 0x3c: + case 0x40: case 0x41: + dev->pci_conf_sb[func][addr] = val; + break; + } break; } } static uint8_t -um8886_read(int func, int addr, void *priv) +umc_8886_read(int func, int addr, void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; + return dev->pci_conf_sb[func][addr]; } @@ -219,26 +269,51 @@ umc_8886_reset(void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; - /* Defaults */ - dev->pci_conf_sb[0][0] = 0x60; /* UMC */ + dev->pci_conf_sb[0][0] = 0x60; /* UMC */ dev->pci_conf_sb[0][1] = 0x10; - dev->pci_conf_sb[0][2] = (SB_ID & 0xff); /* 8886xx */ + dev->pci_conf_sb[0][2] = (SB_ID & 0xff); /* 8886xx */ dev->pci_conf_sb[0][3] = ((SB_ID >> 8) & 0xff); - dev->pci_conf_sb[0][8] = 1; + dev->pci_conf_sb[0][4] = 0x0f; + dev->pci_conf_sb[0][7] = 2; + + dev->pci_conf_sb[0][8] = 0x0e; dev->pci_conf_sb[0][0x09] = 0x00; dev->pci_conf_sb[0][0x0a] = 0x01; dev->pci_conf_sb[0][0x0b] = 0x06; - for (int i = 1; i < 5; i++) /* Disable all IRQ interrupts */ - pci_set_irq_routing(i, PCI_IRQ_DISABLED); + dev->pci_conf_sb[0][0x40] = 1; + dev->pci_conf_sb[0][0x41] = 6; + dev->pci_conf_sb[0][0x42] = 8; + dev->pci_conf_sb[0][0x43] = 0x9a; + dev->pci_conf_sb[0][0x44] = 0xbc; + dev->pci_conf_sb[0][0x45] = 4; + dev->pci_conf_sb[0][0x47] = 0x40; + dev->pci_conf_sb[0][0x50] = 1; + dev->pci_conf_sb[0][0x51] = 3; + dev->pci_conf_sb[0][0xa8] = 0x20; if (HAS_IDE) { + dev->pci_conf_sb[1][0] = 0x60; /* UMC */ + dev->pci_conf_sb[1][1] = 0x10; + + dev->pci_conf_sb[1][2] = 0x3a; /* 8886BF IDE */ + dev->pci_conf_sb[1][3] = 0x67; + dev->pci_conf_sb[1][4] = 1; /* Start with Internal IDE Enabled */ + + dev->pci_conf_sb[1][8] = 0x10; + + dev->pci_conf_sb[1][0x09] = 0x0f; + dev->pci_conf_sb[1][0x0a] = dev->pci_conf_sb[1][0x0b] = 1; + umc_8886_ide_handler(1); } + + for (int i = 1; i < 5; i++) /* Disable all IRQ interrupts */ + pci_set_irq_routing(i, PCI_IRQ_DISABLED); } @@ -257,12 +332,12 @@ umc_8886_init(const device_t *info) umc_8886_t *dev = (umc_8886_t *)malloc(sizeof(umc_8886_t)); memset(dev, 0, sizeof(umc_8886_t)); - dev->has_ide = (info->local == 0x886a); - pci_add_card(PCI_ADD_SOUTHBRIDGE, um8886_read, um8886_write, dev); /* Device 12: UMC 8886xx */ + dev->has_ide = !!(info->local == 0x886a); + pci_add_card(PCI_ADD_SOUTHBRIDGE, umc_8886_read, umc_8886_write, dev); /* Device 12: UMC 8886xx */ /* Add IDE if UM8886AF variant */ if (HAS_IDE) - device_add(&ide_pci_2ch_device); + device_add(&ide_pci_2ch_device); /* Get the Southbridge Revision */ SB_ID = info->local; @@ -277,24 +352,16 @@ const device_t umc_8886f_device = { "UMC 8886F", DEVICE_PCI, 0x8886, - umc_8886_init, - umc_8886_close, - umc_8886_reset, - { NULL }, - NULL, - NULL, + umc_8886_init, umc_8886_close, umc_8886_reset, + { NULL }, NULL, NULL, NULL }; const device_t umc_8886af_device = { - "UMC 8886AF", + "UMC 8886AF/8886BF", DEVICE_PCI, 0x886a, - umc_8886_init, - umc_8886_close, - umc_8886_reset, - { NULL }, - NULL, - NULL, + umc_8886_init, umc_8886_close, umc_8886_reset, + { NULL }, NULL, NULL, NULL }; diff --git a/src/chipset/umc_8890.c b/src/chipset/umc_8890.c deleted file mode 100644 index da49037d1..000000000 --- a/src/chipset/umc_8890.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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 UMC 8890 Chipset. - * - * Note: This chipset has no datasheet, everything were done via - * reverse engineering the BIOS of various machines using it. - * - * - * Authors: Tiseno100, - * - * Copyright 2021 Tiseno100. - */ - -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include <86box/timer.h> -#include <86box/io.h> -#include <86box/device.h> - -#include <86box/apm.h> -#include <86box/mem.h> -#include <86box/pci.h> -#include <86box/port_92.h> -#include <86box/smram.h> - -#include <86box/chipset.h> - -#ifdef ENABLE_UMC_8890_LOG -int umc_8890_do_log = ENABLE_UMC_8890_LOG; -static void -umc_8890_log(const char *fmt, ...) -{ - va_list ap; - - if (umc_8890_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define umc_8890_log(fmt, ...) -#endif - -/* Shadow RAM Flags */ -#define ENABLE_SHADOW (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) -#define DISABLE_SHADOW (MEM_READ_EXTANY | MEM_WRITE_EXTANY) - -typedef struct umc_8890_t -{ - apm_t *apm; - smram_t *smram; - - uint8_t pci_conf[256]; -} umc_8890_t; - -uint16_t umc_8890_shadow_flag(uint8_t flag) -{ -return (flag & 1) ? (MEM_READ_INTERNAL | ((flag & 2) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY); -} - -void umc_8890_shadow(umc_8890_t *dev) -{ - - mem_set_mem_state_both(0xe0000, 0x10000, umc_8890_shadow_flag((dev->pci_conf[0x5f] & 0x0c) >> 2)); - mem_set_mem_state_both(0xf0000, 0x10000, umc_8890_shadow_flag((dev->pci_conf[0x5f] & 0xc0) >> 6)); - - for(int i = 0; i < 8; i++) - mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, umc_8890_shadow_flag(!!(dev->pci_conf[0x5d] & (1 << i)))); - - flushmmucache_nopc(); -} - -static void -um8890_write(int func, int addr, uint8_t val, void *priv) -{ - umc_8890_t *dev = (umc_8890_t *)priv; - - dev->pci_conf[addr] = val; - - switch (addr) - { - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: - umc_8890_shadow(dev); - break; - - case 0x65: /* We don't know the default SMRAM values */ - smram_disable_all(); - smram_enable(dev->smram, 0xe0000, 0xe0000, 0x10000, dev->pci_conf[0x65] & 0x10, 1); - flushmmucache_nopc(); - break; - } - - umc_8890_log("UM8890: dev->regs[%02x] = %02x POST: %02x\n", addr, dev->pci_conf[addr], inb(0x80)); -} - -static uint8_t -um8890_read(int func, int addr, void *priv) -{ - umc_8890_t *dev = (umc_8890_t *)priv; - return dev->pci_conf[addr]; -} - -static void -umc_8890_reset(void *priv) -{ - umc_8890_t *dev = (umc_8890_t *)priv; - - /* Defaults */ - dev->pci_conf[0] = 0x60; /* UMC */ - dev->pci_conf[1] = 0x10; - - dev->pci_conf[2] = 0x91; /* 8891F */ - dev->pci_conf[3] = 0x88; - - dev->pci_conf[8] = 1; - - dev->pci_conf[0x09] = 0x00; - dev->pci_conf[0x0a] = 0x00; - dev->pci_conf[0x0b] = 0x06; -} - -static void -umc_8890_close(void *priv) -{ - umc_8890_t *dev = (umc_8890_t *)priv; - - smram_del(dev->smram); - free(dev); -} - -static void * -umc_8890_init(const device_t *info) -{ - umc_8890_t *dev = (umc_8890_t *)malloc(sizeof(umc_8890_t)); - memset(dev, 0, sizeof(umc_8890_t)); - pci_add_card(PCI_ADD_NORTHBRIDGE, um8890_read, um8890_write, dev); /* Device 0: UMC 8890 */ - - /* APM */ - dev->apm = device_add(&apm_pci_device); - - /* SMRAM(Needs excessive documentation before we begin SMM implementation) */ - dev->smram = smram_add(); - - /* Port 92 */ - device_add(&port_92_pci_device); - - umc_8890_reset(dev); - - return dev; -} - -const device_t umc_8890_device = { - "UMC 8890(8891BF/8892BF)", - DEVICE_PCI, - 0x886a, - umc_8890_init, - umc_8890_close, - umc_8890_reset, - {NULL}, - NULL, - NULL, - NULL}; diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index f9371ae5f..136fc03a0 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -20,66 +20,72 @@ */ /* -UMC HB4 Configuration Registers + UMC HB4 Configuration Registers -Sources & Notes: -Cache registers were found at Vogons: https://www.vogons.org/viewtopic.php?f=46&t=68829&start=20 -Basic Reverse engineering effort was done personally by me + Sources & Notes: + Cache registers were found at Vogons: https://www.vogons.org/viewtopic.php?f=46&t=68829&start=20 + Basic Reverse engineering effort was done personally by me -TODO: -- APM, SMM, SMRAM registers(Did some early work. Still quite incomplete) -- More Appropriate Bitmasking(If it's even possible) + Warning: Register documentation may be inaccurate! -Warning: Register documentation may be inaccurate! + UMC 8881x: -UMC 8881x: + Register 50: + Bit 7: Enable L2 Cache + Bit 6: Cache Policy (0: Write Thru / 1: Write Back) -Register 50: -Bit 7: Enable L2 Cache -Bit 6: Cache Policy (0: Write Thru / 1: Write Back) + Bit 5-4 Cache Speed + 0 0 Read 3-2-2-2 Write 3T + 0 1 Read 3-1-1-1 Write 3T + 1 0 Read 2-2-2-2 Write 2T + 1 1 Read 2-1-1-1 Write 2T -Bit 5-4 Cache Speed - 0 0 Read 3-2-2-2 Write 3T - 0 1 Read 3-1-1-1 Write 3T - 1 0 Read 2-2-2-2 Write 2T - 1 1 Read 2-1-1-1 Write 2T + Bit 3 Cache Banks (0: 1 Bank / 1: 2 Banks) -Bit 3 Cache Banks (0: 1 Bank / 1: 2 Banks) + Bit 2-1-0 Cache Size + 0 0 0 0KB + 0 0 1 64KB + x-x-x Multiplications of 2(64*2 for 0 1 0) till 2MB -Bit 2-1-0 Cache Size - 0 0 0 0KB - 0 0 1 64KB - x-x-x Multiplications of 2(64*2 for 0 1 0) till 2MB + Register 51: + Bit 7-6 DRAM Read Speed + 5-4 DRAM Write Speed + 0 0 1 Waits + 0 1 1 Waits + 1 0 1 Wait + 1 1 0 Waits -Register 51: -Bit 7-6 DRAM Read Speed - 5-4 DRAM Write Speed - 0 0 1 Waits - 0 1 1 Waits - 1 0 1 Wait - 1 1 0 Waits + Bit 3 Resource Lock Enable + Bit 2 Graphics Adapter (0: VL Bus / 1: PCI Bus) + Bit 1 L1 WB Policy (0: WT / 1: WB) + Bit 0 L2 Cache Tag Lenght (0: 7 Bits / 1: 8 Bits) -Bit 3 Resource Lock Enable -Bit 2 Graphics Adapter (0: VL Bus / 1: PCI Bus) -Bit 1 L1 WB Policy (0: WT / 1: WB) -Bit 0 L2 Cache Tag Lenght (0: 7 Bits / 1: 8 Bits) + Register 52: + Bit 7: Host-to-PCI Post Write (0: 1 Wait State / 1: 0 Wait States) -Register 52: -Bit 7: Host-to-PCI Post Write (0: 1 Wait State / 1: 0 Wait States) + Register 54: + Bit 7: DC000-DFFFF Read Enable + Bit 6: D8000-DBFFF Read Enable + Bit 5: D4000-D7FFF Read Enable + Bit 4: D0000-D3FFF Read Enable + Bit 3: CC000-CFFFF Read Enable + Bit 2: C8000-CBFFF Read Enable + Bit 1: C0000-C7FFF Read Enable + Bit 0: Enable C0000-DFFFF Shadow Segment Bits -Register 54: -Bit 7: DC000-DFFFF -Bit 6: D8000-DBFFF -Bit 5: D4000-D7FFF -Bit 4: D0000-D3FFF -Bit 3: CC000-CFFFF -Bit 2: C8000-CBFFF -Bit 1: C0000-C7FFF -Bit 0: Reserved + Register 55: + Bit 7: E0000-FFFF Read Enable + Bit 6: Shadow Write Status (1: Write Protect/0: Write) -Register 55: -Bit 7: Enable Shadow Reads For System & Selected Segments -Bit 6: Write Protect Enable + Register 56h & 57h: DRAM Bank 0 Configuration + Register 58h & 59h: DRAM Bank 1 Configuration + + Register 60: + Bit 5-4: SMRAM Position(Lot's of uncertainty to those bits) + 0 0 A0000 to E0000 + 1 0 A0000 to ????? (Phoenix uses it to no avail) + + Bit 0: SMRAM Local Access Enable */ #include @@ -95,7 +101,6 @@ Bit 6: Write Protect Enable #include <86box/io.h> #include <86box/device.h> -#include <86box/apm.h> #include <86box/mem.h> #include <86box/pci.h> #include <86box/port_92.h> @@ -103,149 +108,192 @@ Bit 6: Write Protect Enable #include <86box/chipset.h> + #ifdef ENABLE_HB4_LOG int hb4_do_log = ENABLE_HB4_LOG; + + static void hb4_log(const char *fmt, ...) { va_list ap; - if (hb4_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + if (hb4_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else #define hb4_log(fmt, ...) #endif -/* Shadow RAM Flags */ -#define CAN_READ ((dev->pci_conf[0x55] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) -#define CAN_WRITE ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL) -#define DISABLE (MEM_READ_EXTANY | MEM_WRITE_EXTANY) typedef struct hb4_t { - apm_t *apm; - smram_t *smram; - - uint8_t pci_conf[256]; /* PCI Registers */ + uint8_t pci_conf[128]; /* PCI Registers */ + smram_t *smram; /* SMRAM Handler */ } hb4_t; -void hb4_shadow(int cur_addr, hb4_t *dev) -{ - mem_set_mem_state_both(0xc0000, 0x8000, (dev->pci_conf[0x54] & 2) ? (CAN_READ | CAN_WRITE) : DISABLE); - for (int i = 2; i < 8; i++) - mem_set_mem_state_both(0xc8000 + ((i - 2) << 14), 0x4000, (dev->pci_conf[0x54] & (1 << i)) ? (CAN_READ | CAN_WRITE) : DISABLE); - mem_set_mem_state_both(0xe0000, 0x20000, CAN_READ | CAN_WRITE); - - flushmmucache_nopc(); +void +hb4_shadow(hb4_t *dev) +{ + mem_set_mem_state_both(0xe0000, 0x20000, ((dev->pci_conf[0x55] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | + ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL)); + + if (dev->pci_conf[0x54] & 1) { + if (dev->pci_conf[0x54] & 2) + mem_set_mem_state_both(0xc0000, 0x8000, MEM_READ_INTERNAL | ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY :MEM_WRITE_INTERNAL)); + else + mem_set_mem_state_both(0xc0000, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + for (int i = 0; i < 5; i++) { + if ((dev->pci_conf[0x54] >> i) & 4) + mem_set_mem_state_both(0xc8000 + (i << 14), 0x8000, MEM_READ_INTERNAL | ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY :MEM_WRITE_INTERNAL)); + else + mem_set_mem_state_both(0xc8000 + (i << 14), 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + } + + flushmmucache_nopc(); } + static void -um8881_write(int func, int addr, uint8_t val, void *priv) +hb4_smram(hb4_t *dev) +{ + smram_disable_all(); + + smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); +} + + +static void +hb4_write(int func, int addr, uint8_t val, void *priv) { hb4_t *dev = (hb4_t *)priv; - hb4_log("UM8881: dev->regs[%02x] = %02x\n", addr, val); + hb4_log("UM8881: dev->regs[%02x] = %02x POST: %02x \n", addr, val, inb(0x80)); - if (addr > 3) /* We don't know the RW status of registers but Phoenix writes on some RO registers too*/ + switch (addr) { + case 0x04: case 0x05: + dev->pci_conf[addr] = val; + break; - switch (addr) - { - case 0x50: - dev->pci_conf[addr] = ((val & 0xf8) | 4); /* Hardcode Cache Size to 512KB */ - cpu_cache_ext_enabled = !!(val & 0x80); /* Fixes freezing issues on the HOT-433A*/ - cpu_update_waitstates(); - break; + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf9); + break; - case 0x54: - case 0x55: - dev->pci_conf[addr] = val & (!(addr & 1) ? 0xfe : 0xff); - hb4_shadow(addr, dev); - break; + case 0x0c: case 0x0d: + dev->pci_conf[addr] = val; + break; - case 0x60: - dev->pci_conf[addr] = val & 0x3f; - break; + case 0x50: + dev->pci_conf[addr] = ((val & 0xf8) | 4); /* Hardcode Cache Size to 512KB */ + cpu_cache_ext_enabled = !!(val & 0x80); /* Fixes freezing issues on the HOT-433A*/ + cpu_update_waitstates(); + break; - case 0x61: - dev->pci_conf[addr] = val & 0x0f; - break; + case 0x51: case 0x52: + case 0x53: + dev->pci_conf[addr] = val; + break; - default: - dev->pci_conf[addr] = val; - break; - } + case 0x54: case 0x55: + dev->pci_conf[addr] = val; + hb4_shadow(dev); + break; + + case 0x56 ... 0x5f: + dev->pci_conf[addr] = val; + break; + + case 0x60: + dev->pci_conf[addr] = val; + hb4_smram(dev); + break; + + case 0x61: + dev->pci_conf[addr] = val; + break; + } } + static uint8_t -um8881_read(int func, int addr, void *priv) +hb4_read(int func, int addr, void *priv) { hb4_t *dev = (hb4_t *)priv; + return dev->pci_conf[addr]; } + static void hb4_reset(void *priv) { hb4_t *dev = (hb4_t *)priv; - /* Defaults */ dev->pci_conf[0] = 0x60; /* UMC */ dev->pci_conf[1] = 0x10; dev->pci_conf[2] = 0x81; /* 8881x */ dev->pci_conf[3] = 0x88; - dev->pci_conf[8] = 1; + dev->pci_conf[7] = 2; + + dev->pci_conf[8] = 4; dev->pci_conf[0x09] = 0x00; dev->pci_conf[0x0a] = 0x00; dev->pci_conf[0x0b] = 0x06; + + dev->pci_conf[0x51] = 1; + dev->pci_conf[0x52] = 1; + dev->pci_conf[0x5a] = 4; + dev->pci_conf[0x5c] = 0xc0; + dev->pci_conf[0x5d] = 0x20; + dev->pci_conf[0x5f] = 0xff; + + hb4_shadow(dev); + hb4_write(0, 0x60, 0x20, dev); } + static void hb4_close(void *priv) { hb4_t *dev = (hb4_t *)priv; - //smram_del(dev->smram); free(dev); } + static void * hb4_init(const device_t *info) { hb4_t *dev = (hb4_t *)malloc(sizeof(hb4_t)); memset(dev, 0, sizeof(hb4_t)); - pci_add_card(PCI_ADD_NORTHBRIDGE, um8881_read, um8881_write, dev); /* Device 10: UMC 8881x */ - - /* APM */ - dev->apm = device_add(&apm_pci_device); - - /* SMRAM(Needs excessive documentation before we begin SMM implementation) */ - //dev->smram = smram_add(); + pci_add_card(PCI_ADD_NORTHBRIDGE, hb4_read, hb4_write, dev); /* Device 10: UMC 8881x */ /* Port 92 */ device_add(&port_92_pci_device); + /* SMRAM */ + dev->smram = smram_add(); + hb4_reset(dev); return dev; } + const device_t umc_hb4_device = { "UMC HB4(8881F)", DEVICE_PCI, 0x886a, - hb4_init, - hb4_close, - hb4_reset, - {NULL}, - NULL, - NULL, - NULL}; + hb4_init, hb4_close, hb4_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 7f5ee51db..5431b9236 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1184,7 +1184,7 @@ write_output(atkbd_t *dev, uint8_t val) kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); if (!(dev->flags & KBC_FLAG_PS2)) - val |= ((dev->mem[0x20] << 4) & 0x30); + val |= ((dev->mem[0x20] << 4) & 0x10); dev->kbd_inhibit = (val & 0x40); dev->mouse_inhibit = (val & 0x08); @@ -1211,6 +1211,7 @@ write_output(atkbd_t *dev, uint8_t val) if ((dev->p2 ^ val) & 0x01) { /*Reset*/ if (! (val & 0x01)) { /* Pin 0 selected. */ + pclog("write_output(): Pulse reset!\n"); softresetx86(); /*Pulse reset!*/ cpu_set_edx(); smbase = is_am486dxl ? 0x00060000 : 0x00030000; @@ -1503,10 +1504,8 @@ kbc_command(atkbd_t *dev) case 0xd0: /* read output port */ kbd_log("ATkbc: read output port\n"); mask = 0xff; - if (dev->mem[0x20] & 0x10) + if (!(dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x10)) mask &= 0xbf; - if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) - mask &= 0xf7; kbc_transmit(dev, dev->p2 & mask); break; @@ -2885,7 +2884,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) dev->status &= ~STAT_IFULL; kbc_send_to_ob(dev, 'H', 0, 0x00); } */ - kbc_process(dev); + // kbc_process(dev); #endif break; } diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 4ecff681e..83642fe62 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -124,6 +124,11 @@ extern const device_t stpc_atlas_device; extern const device_t stpc_serial_device; extern const device_t stpc_lpt_device; +/* UMC */ +extern const device_t umc_8886f_device; +extern const device_t umc_8886af_device; +extern const device_t umc_hb4_device; + /* VIA */ extern const device_t via_vt82c49x_device; extern const device_t via_vt82c49x_pci_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index a04b423ef..a805dc4ba 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -284,6 +284,7 @@ extern int machine_at_sbc_350a_init(const machine_t *); extern int machine_at_flytech386_init(const machine_t *); extern int machine_at_mr1217_init(const machine_t *); extern int machine_at_pja511m_init(const machine_t *); +extern int machine_at_prox1332_init(const machine_t *); extern int machine_at_awardsx_init(const machine_t *); @@ -369,12 +370,18 @@ extern int machine_at_arb1479_init(const machine_t *); extern int machine_at_pcm9340_init(const machine_t *); extern int machine_at_pcm5330_init(const machine_t *); +extern int machine_at_ecs486_init(const machine_t *); +extern int machine_at_hot433_init(const machine_t *); +extern int machine_at_atc1415_init(const machine_t *); +extern int machine_at_actionpc2600_init(const machine_t *); + #ifdef EMU_DEVICE_H extern const device_t *at_acera1g_get_device(void); extern const device_t *at_vect486vl_get_device(void); extern const device_t *at_d824_get_device(void); extern const device_t *at_pcs46c_get_device(void); extern const device_t *at_valuepoint433_get_device(void); +extern const device_t *at_sbc_490_get_device(void); #endif /* m_at_commodore.c */ @@ -394,6 +401,7 @@ extern void machine_at_award_common_init(const machine_t *); extern void machine_at_sp4_common_init(const machine_t *model); +extern int machine_at_excalibur_pci_init(const machine_t *); extern int machine_at_p5mp3_init(const machine_t *); extern int machine_at_dellxp60_init(const machine_t *); extern int machine_at_opti560l_init(const machine_t *); @@ -407,6 +415,7 @@ extern int machine_at_excalibur_init(const machine_t *); extern int machine_at_p5vl_init(const machine_t *); +extern int machine_at_excalibur_pci_2_init(const machine_t *); extern int machine_at_p5sp4_init(const machine_t *); #ifdef EMU_DEVICE_H @@ -462,6 +471,7 @@ extern int machine_at_ap5s_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *at_endeavor_get_device(void); extern const device_t *at_thor_get_device(void); +#define at_mrthor_get_device at_thor_get_device extern const device_t *at_pb640_get_device(void); #endif @@ -474,6 +484,7 @@ extern int machine_at_equium5200_init(const machine_t *); extern int machine_at_pcv240_init(const machine_t *); extern int machine_at_p65up5_cp55t2d_init(const machine_t *); +extern int machine_at_ap5vm_init(const machine_t *); extern int machine_at_p55tvp4_init(const machine_t *); extern int machine_at_5ivg_init(const machine_t *); extern int machine_at_8500tvxa_init(const machine_t *); @@ -504,6 +515,11 @@ extern int machine_at_ms5146_init(const machine_t *); extern int machine_at_m560_init(const machine_t *); extern int machine_at_ms5164_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t *at_presario2240_get_device(void); +#define at_presario4500_get_device at_presario2240_get_device +#endif + /* m_at_sockets7.c */ extern int machine_at_p5a_init(const machine_t *); extern int machine_at_m579_init(const machine_t *); @@ -513,6 +529,7 @@ extern int machine_at_ga_5ax_init(const machine_t *); extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); extern int machine_at_ficva503a_init(const machine_t *); +extern int machine_at_sy_5ema_pro_init(const machine_t *); /* m_at_socket8.c */ #if defined(DEV_BRANCH) && defined(USE_I450KX) diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 4ca5d94c4..b9fa700bf 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -52,6 +52,8 @@ #define PCI_IRQ_DISABLED -1 +#define PCI_ADD_STRICT 0x80 + enum { PCI_CARD_NORTHBRIDGE = 0, PCI_CARD_AGPBRIDGE, diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 5bd424f9e..0c839ff9b 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -167,6 +167,7 @@ extern void updatewindowsize(int x, int y); extern void video_init(void); extern void video_close(void); extern void video_reset_close(void); +extern void video_pre_reset(int card); extern void video_reset(int card); extern uint8_t video_force_resize_get(void); extern void video_force_resize_set(uint8_t res); @@ -357,6 +358,7 @@ extern const device_t s3_elsa_winner2000_pro_x_964_vlb_device; extern const device_t s3_elsa_winner2000_pro_x_pci_device; extern const device_t s3_elsa_winner2000_pro_x_vlb_device; extern const device_t s3_trio64v2_dx_pci_device; +extern const device_t s3_trio64v2_dx_onboard_pci_device; /* S3 ViRGE */ extern const device_t s3_virge_325_vlb_device; @@ -380,6 +382,7 @@ extern const device_t sigma_device; extern const device_t tgui9400cxi_device; extern const device_t tgui9440_vlb_device; extern const device_t tgui9440_pci_device; +extern const device_t tgui9440_onboard_pci_device; extern const device_t tgui9660_pci_device; extern const device_t tgui9680_pci_device; diff --git a/src/io.c b/src/io.c index 2751cc639..742e601c4 100644 --- a/src/io.c +++ b/src/io.c @@ -315,6 +315,10 @@ inb(uint16_t port) if (!found) cycles -= io_delay; + /* TriGem 486-BIOS MHz output. */ + if (port == 0x1ed) + ret = 0xfe; + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return(ret); @@ -338,7 +342,7 @@ outb(uint16_t port, uint8_t val) } p = q; } - + if (!found) { cycles -= io_delay; #ifdef USE_DYNAREC diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 091723b3c..b4d5b4ed6 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -120,11 +120,11 @@ machine_at_ama932j_init(const machine_t *model) machine_at_common_ide_init(model); - machine_at_headland_common_init(1); - if (gfxcard == VID_INTERNAL) device_add(&oti067_ama932j_device); + machine_at_headland_common_init(1); + return ret; } @@ -439,14 +439,14 @@ machine_at_spc4620p_init(const machine_t *model) if (bios_only || !ret) return ret; + if (gfxcard == VID_INTERNAL) + device_add(&ati28800k_spc4620p_device); + machine_at_scat_init(model, 1); if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - if (gfxcard == VID_INTERNAL) - device_add(&ati28800k_spc4620p_device); - return ret; } @@ -550,13 +550,13 @@ machine_at_wd76c10_init(const machine_t *model) machine_at_common_init(model); + if (gfxcard == VID_INTERNAL) + device_add(¶dise_wd90c11_megapc_device); + device_add(&keyboard_ps2_quadtel_device); device_add(&wd76c10_device); - if (gfxcard == VID_INTERNAL) - device_add(¶dise_wd90c11_megapc_device); - return ret; } @@ -621,11 +621,11 @@ machine_at_cmdsl386sx25_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_scamp_common_init(model); - if (gfxcard == VID_INTERNAL) device_add(&gd5402_onboard_device); + machine_at_scamp_common_init(model); + return ret; } @@ -648,11 +648,11 @@ machine_at_spc6033p_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_scamp_common_init(model); - if (gfxcard == VID_INTERNAL) device_add(&ati28800k_spc6033p_device); + machine_at_scamp_common_init(model); + return ret; } @@ -736,11 +736,12 @@ machine_at_flytech386_init(const machine_t *model) device_add(&ali1217_device); device_add(&w83787f_ide_en_device); - device_add(&keyboard_ps2_device); if (gfxcard == VID_INTERNAL) device_add(&tvga8900d_device); + device_add(&keyboard_ps2_device); + return ret; } @@ -788,7 +789,29 @@ machine_at_pja511m_init(const machine_t *model) machine_at_common_init(model); device_add_inst(&fdc37c669_device, 1); - //device_add_inst(&fdc37c669_device, 2); /* enable when dual FDC37C669 is implemented */ + device_add_inst(&fdc37c669_device, 2); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ali6117d_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_prox1332_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/prox1332/D30B3AC1.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&fdc37c669_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&ali6117d_device); device_add(&sst_flash_29ee010_device); @@ -845,13 +868,14 @@ machine_at_3302_init(const machine_t *model) machine_at_common_ide_init(model); device_add(&neat_device); - device_add(&keyboard_at_ncr_device); if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); if (gfxcard == VID_INTERNAL) device_add(¶dise_pvga1a_ncr3302_device); + + device_add(&keyboard_at_ncr_device); return ret; } diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0cc901538..cf27a999d 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -175,23 +175,25 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 machine_at_common_ide_init(model); device_add(&sis_85c461_device); - device_add(&keyboard_ps2_device); - - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); - if (gfxcard == VID_INTERNAL) device_add(&et4000w32_onboard_device); + device_add(&keyboard_ps2_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } + const device_t * at_valuepoint433_get_device(void) { return &et4000w32_onboard_device; } + int machine_at_ecs386_init(const machine_t *model) { @@ -346,15 +348,16 @@ machine_at_vect486vl_init(const machine_t *model) // has HDC problems if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_ide_init(model); device_add(&vl82c480_device); - device_add(&keyboard_ps2_ami_device); - device_add(&fdc37c651_device); if (gfxcard == VID_INTERNAL) device_add(&gd5428_onboard_device); + device_add(&keyboard_ps2_ami_device); + device_add(&fdc37c651_ide_device); + return ret; } @@ -379,12 +382,13 @@ machine_at_d824_init(const machine_t *model) machine_at_common_init(model); device_add(&vl82c480_device); - device_add(&keyboard_ps2_device); - device_add(&fdc37c651_device); if (gfxcard == VID_INTERNAL) device_add(&gd5428_onboard_device); + device_add(&keyboard_ps2_device); + device_add(&fdc37c651_device); + return ret; } @@ -408,11 +412,11 @@ machine_at_acera1g_init(const machine_t *model) return ret; machine_at_common_init(model); + device_add(&ali1429_device); if (gfxcard == VID_INTERNAL) device_add(&gd5428_onboard_device); - device_add(&ali1429_device); device_add(&keyboard_ps2_acer_pci_device); device_add(&ide_isa_2ch_device); @@ -1364,14 +1368,18 @@ machine_at_sbc_490_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_VIDEO, 4, 1, 2, 3); pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_VIDEO, 4, 1, 2, 3); device_add(&ali1489_device); device_add(&fdc37c665_device); + + if (gfxcard == VID_INTERNAL) + device_add(&tgui9440_onboard_pci_device); + device_add(&keyboard_ps2_ami_device); device_add(&sst_flash_29ee010_device); @@ -1379,6 +1387,13 @@ machine_at_sbc_490_init(const machine_t *model) } +const device_t * +at_sbc_490_get_device(void) +{ + return &tgui9440_onboard_pci_device; +} + + int machine_at_tf_486_init(const machine_t *model) { @@ -1519,3 +1534,128 @@ machine_at_pcm5330_init(const machine_t *model) return ret; } + + +int +machine_at_ecs486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ecs486/8810AIO.32J", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0f, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0d, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886f_device); + device_add(&ide_cmd640_pci_legacy_only_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_hot433_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hot433/433AUS33.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0d, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0f, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_atc1415_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/atc1415/1415V330.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_actionpc2600_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/actionpc2600/action2600.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0d, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0f, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index e0aef82ef..a2e8ce2a1 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -810,8 +810,6 @@ at_cpqiii_get_device(void) static void machine_at_compaq_init(const machine_t *model, int type) { - machine_at_init(model); - if (type != COMPAQ_DESKPRO386) mem_remap_top(384); @@ -846,6 +844,8 @@ machine_at_compaq_init(const machine_t *model, int type) device_add(&ide_isa_device); break; } + + machine_at_init(model); } diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index cf6a276aa..3c9baaa05 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -645,13 +645,14 @@ machine_at_ms6168_common_init(const machine_t *model) device_add(&i440zx_device); device_add(&piix4e_device); device_add(&w83977ef_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_SDRAM, 0x3, 256); if (gfxcard == VID_INTERNAL) device_add(&voodoo_3_2000_agp_onboard_8m_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + if (sound_card_current == SOUND_INTERNAL) { device_add(&es1371_onboard_device); device_add(&cs4297_device); diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 16673b22f..7e8dd9232 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -111,6 +111,38 @@ machine_at_sp4_common_init(const machine_t *model) } +int +machine_at_excalibur_pci_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excalibur_pci/S701P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_cmd640_pci_legacy_only_device); + + device_add(&i430lx_device); + device_add(&sio_zb_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + int machine_at_p5mp3_init(const machine_t *model) { @@ -331,6 +363,7 @@ machine_at_pb520r_init(const machine_t *model) return ret; } + const device_t * at_pb520r_get_device(void) { @@ -389,6 +422,38 @@ machine_at_p5vl_init(const machine_t *model) } +int +machine_at_excalibur_pci_2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excalibur_pci-2/S722P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_cmd640_pci_legacy_only_device); + + device_add(&sis_85c50x_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + int machine_at_p5sp4_init(const machine_t *model) { diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 112be1c60..d9e9b7cd1 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -44,6 +44,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> int @@ -78,6 +79,41 @@ machine_at_acerv35n_init(const machine_t *model) } +int +machine_at_ap5vm_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ap5vm/AP5V270.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + /* It seems there were plans for an on-board NCR 53C810 according to some clues + left in the manual, but were latter scrapped. The BIOS still support that + PCI device, though, so why not. */ + pci_register_slot(0x06, PCI_CARD_SCSI, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&ncr53c810_onboard_pci_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + int machine_at_p55t2p4_init(const machine_t *model) { @@ -366,9 +402,12 @@ machine_at_presario2240_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_SOUND, 3, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_VIDEO, 3, 0, 0, 0); pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + if (gfxcard == VID_INTERNAL) + device_add(&s3_trio64v2_dx_onboard_pci_device); + device_add(&i430vx_device); device_add(&piix3_device); device_add(&keyboard_ps2_ami_pci_device); @@ -379,6 +418,13 @@ machine_at_presario2240_init(const machine_t *model) } +const device_t * +at_presario2240_get_device(void) +{ + return &s3_trio64v2_dx_onboard_pci_device; +} + + int machine_at_presario4500_init(const machine_t *model) { @@ -395,8 +441,11 @@ machine_at_presario4500_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x14, PCI_CARD_VIDEO, 3, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_trio64v2_dx_onboard_pci_device); device_add(&i430vx_device); device_add(&piix3_device); @@ -646,12 +695,21 @@ machine_at_an430tx_init(const machine_t *model) { int ret; +#if 1 ret = bios_load_linear_combined2("roms/machines/an430tx/P10-0095.BIO", "roms/machines/an430tx/P10-0095.BI1", "roms/machines/an430tx/P10-0095.BI2", "roms/machines/an430tx/P10-0095.BI3", "roms/machines/an430tx/P10-0095.RCV", 0x3a000, 160); +#else + ret = bios_load_linear_combined2("roms/machines/an430tx/P06-0062.BIO", + "roms/machines/an430tx/P06-0062.BI1", + "roms/machines/an430tx/P06-0062.BI2", + "roms/machines/an430tx/P06-0062.BI3", + "roms/machines/an430tx/P10-0095.RCV", + 0x3a000, 160); +#endif if (bios_only || !ret) return ret; @@ -661,7 +719,7 @@ machine_at_an430tx_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ - pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + // pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 1b1f7c7be..5ee87fc44 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -60,6 +60,9 @@ machine_at_thor_common_init(const machine_t *model, int mr) pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64vplus_onboard_pci_device); + // device_add(&keyboard_ps2_ami_pci_device); device_add(&keyboard_ps2_intel_ami_pci_device); device_add(&i430fx_device); @@ -165,6 +168,13 @@ machine_at_thor_init(const machine_t *model) } +const device_t * +at_thor_get_device(void) +{ + return &s3_phoenix_trio64vplus_onboard_pci_device; +} + + int machine_at_mrthor_init(const machine_t *model) { diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index e9487ecfe..66eca228f 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -284,3 +284,44 @@ machine_at_ficva503a_init(const machine_t *model) return ret; } + + +int +machine_at_sy_5ema_pro_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sy-5ema_pro/5emo1aa2.bin", + 0x000e0000, 131072, 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, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&via_mvp3_device); + device_add(&via_vt82c686a_device); + device_add(&keyboard_ps2_ami_pci_device); + // device_add(&via_vt82c686_sio_device); + device_add(&fdc37c669_device); + device_add(&sst_flash_39sf010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&via_vt82c686_hwm_device); /* fans: CPU1, Chassis; temperatures: CPU, System, unused */ + hwm_values.temperatures[0] += 2; /* CPU offset */ + hwm_values.temperatures[1] += 2; /* System offset */ + hwm_values.temperatures[2] = 0; /* unused */ + + device_add(&wm9701a_device); /* on daughtercard */ + + return ret; +} diff --git a/src/machine/machine.c b/src/machine/machine.c index afa79b02c..91cdbef33 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -97,6 +97,10 @@ machine_init_ex(int m) device_add(&cassette_device); cart_reset(); + + /* Prepare some video-related things if we're using internal + or no video. */ + video_pre_reset(gfxcard); } /* All good, boot the machine! */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 5a5ae8b21..b458b5a5f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -252,6 +252,8 @@ const machine_t machines[] = { { "[ALi M1217] MR 386SX clone", "mr1217", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 16384, 1024, 127, machine_at_mr1217_init, NULL }, /* Has IBM PS/2 Type 1 KBC firmware. */ { "[ALi M6117] Acrosser PJ-A511M", "pja511m", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_pja511m_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { "[ALi M6117C] Protech ProX-1332", "prox1332", MACHINE_TYPE_386SX, CPU_PKG_M6117, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 32768,1024, 127, machine_at_prox1332_init, NULL }, /* Has an AMI KBC firmware, the only photo of this is too low resolution for me to read what's on the KBC chip, so I'm going to assume AMI 'F' based on the other known HT18 AMI BIOS strings. */ @@ -398,7 +400,7 @@ const machine_t machines[] = { /* 486 machines which utilize the PCI bus */ /* This has an AMIKey-2, which is an updated version of type 'H'. */ - { "[ALi M1489] AAEON SBC-490", "sbc-490", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_sbc_490_init, NULL }, + { "[ALi M1489] AAEON SBC-490", "sbc-490", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 65536, 1024, 255, machine_at_sbc_490_init, at_sbc_490_get_device }, /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT KBC. */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, @@ -443,6 +445,14 @@ const machine_t machines[] = { /* According to MrKsoft, his real 4DPS has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, + /* This has the UMC 88xx on-chip KBC. */ + { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, + /* Has AMIKey Z(!) KBC firmware. */ + { "[UMC 8881] Epson Action PC 2600", "actionpc2600", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_actionpc2600_init, NULL }, + /* This has a Holtek KBC. */ + { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ { "[VIA VT82C496G] DFI G486VPA", "g486vpa", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_g486vpa_init, NULL }, /* Has a VIA VT82C42N KBC. */ @@ -465,6 +475,12 @@ const machine_t machines[] = { /* Socket 4 machines */ /* 430LX */ + /* Has AMIKey H KBC firmware (AMIKey-2), per POST screen with BIOS string + shown in the manual. Has PS/2 mouse support with serial-style (DB9) + connector. + The boot block for BIOS recovery requires an unknown bit on port 805h + to be clear. */ + { "[i430LX] AMI Excalibur PCI Pentium", "excalibur_pci", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_excalibur_pci_init, NULL }, /* Has AMIKey F KBC firmware (AMIKey). */ { "[i430LX] ASUS P/I-P5MP3", "p5mp3", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 196608, 2048, 127, machine_at_p5mp3_init, NULL }, /* Has IBM PS/2 Type 1 KBC firmware. */ @@ -494,9 +510,11 @@ const machine_t machines[] = { /* This has AMIKey 'F' KBC firmware. */ { "[OPTi 597] Supermicro P5VL-PCI", "p5vl", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p5vl_init, NULL }, - /* SiS 85C50x */ + /* SiS 50x */ + /* This has an unknown AMI KBC firmware, most likely AMIKey / type 'F'. */ + { "[SiS 50x] AMI Excalibur PCI-II Pentium ISA","excalibur_pci-2", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_excalibur_pci_2_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ - { "[SiS 85C50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, + { "[SiS 50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, /* Socket 5 machines */ /* 430NX */ @@ -557,11 +575,11 @@ const machine_t machines[] = { /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ - { "[i430FX] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_thor_init, NULL }, + { "[i430FX] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_thor_init, at_thor_get_device }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ - { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, NULL }, + { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, at_mrthor_get_device }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ @@ -624,6 +642,8 @@ const machine_t machines[] = { { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p65up5_cp55t2d_init, NULL }, /* 430VX */ + /* This has the VIA VT82C42N KBC. */ + { "[i430VX] AOpen AP5VM", "ap5vm", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_SCSI, 8192, 131072, 8192, 127, machine_at_ap5vm_init, NULL }, /* Has AMIKey H KBC firmware (AMIKey-2). */ { "[i430VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55tvp4_init, NULL }, /* The BIOS does not send a single non-standard KBC command, so it must have a standard IBM @@ -633,9 +653,9 @@ const machine_t machines[] = { { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_8500tvxa_init, NULL }, /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O chip with on-chip KBC and AMI MegaKey KBC firmware. */ - { "[i430VX] Compaq Presario 2240", "presario2240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario2240_init, NULL }, + { "[i430VX] Compaq Presario 2240", "presario2240", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario2240_init, at_presario2240_get_device }, /* This most likely has AMI MegaKey as above. */ - { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario4500_init, NULL }, + { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_presario4500_init, at_presario4500_get_device }, /* The BIOS sends KBC command CB which is an AMI KBC command, so it has an AMI KBC firmware. */ { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p55va_init, NULL }, /* The BIOS does not send a single non-standard KBC command. */ @@ -711,6 +731,9 @@ const machine_t machines[] = { /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA VT82C42N. */ { "[VIA MVP3] FIC VA-503A", "ficva503a", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1800, 3100, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_ficva503a_init, NULL }, + /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { "[VIA MVP3] Soyo SY-5EMA Pro", "sy-5ema_pro", MACHINE_TYPE_SOCKETS7, CPU_PKG_SOCKET5_7, 0, 66666667, 124242424, 1800, 3100, 1.5, 5.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 786432, 8192, 255, machine_at_sy_5ema_pro_init, NULL }, /* Socket 8 machines */ /* 450KX */ diff --git a/src/pci.c b/src/pci.c index a23f44768..37c9976a5 100644 --- a/src/pci.c +++ b/src/pci.c @@ -888,10 +888,17 @@ pci_find_slot(uint8_t add_type, uint8_t ignore_slot) dev = &pci_cards[i]; if (!dev->read && !dev->write && ((ignore_slot == 0xff) || (i != ignore_slot))) { - if (((dev->type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || - (dev->type == add_type)) { - ret = i; - break; + if (add_type & PCI_ADD_STRICT) { + if (dev->type == (add_type & 0x7f)) { + ret = i; + break; + } + } else { + if (((dev->type == PCI_CARD_NORMAL) && ((add_type & 0x7f) >= PCI_ADD_NORMAL)) || + (dev->type == (add_type & 0x7f))) { + ret = i; + break; + } } } } diff --git a/src/port_92.c b/src/port_92.c index d46d2327b..5e19bee34 100644 --- a/src/port_92.c +++ b/src/port_92.c @@ -64,7 +64,13 @@ port_92_readb(uint16_t port, void *priv) static uint16_t port_92_readw(uint16_t port, void *priv) { - return port_92_readb(port, priv); + uint16_t ret = 0xffff; + port_92_t *dev = (port_92_t *) priv; + + if (!(dev->flags & PORT_92_PCI)) + ret = port_92_readb(port, priv); + + return ret; } @@ -106,7 +112,10 @@ port_92_writeb(uint16_t port, uint8_t val, void *priv) static void port_92_writew(uint16_t port, uint16_t val, void *priv) { - port_92_writeb(port, val & 0xff, priv); + port_92_t *dev = (port_92_t *) priv; + + if (!(dev->flags & PORT_92_PCI)) + port_92_writeb(port, val & 0xff, priv); } @@ -146,7 +155,7 @@ port_92_add(void *priv) { port_92_t *dev = (port_92_t *) priv; - if (dev->flags & PORT_92_WORD) + if (dev->flags & (PORT_92_WORD | PORT_92_PCI)) io_sethandler(0x0092, 2, port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); else @@ -160,7 +169,7 @@ port_92_remove(void *priv) { port_92_t *dev = (port_92_t *) priv; - if (dev->flags & PORT_92_WORD) + if (dev->flags & (PORT_92_WORD | PORT_92_PCI)) io_removehandler(0x0092, 2, port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); else diff --git a/src/sio/CMakeLists.txt b/src/sio/CMakeLists.txt index 902f8b231..856f6aaa6 100644 --- a/src/sio/CMakeLists.txt +++ b/src/sio/CMakeLists.txt @@ -13,8 +13,8 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(sio OBJECT sio_acc3221.c sio_f82c710.c sio_82091aa.c sio_fdc37c651.c sio_fdc37c661.c - sio_fdc37c66x.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c +add_library(sio OBJECT sio_acc3221.c sio_f82c710.c sio_82091aa.c sio_fdc37c6xx.c + sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c sio_it8661f.c sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c sio_prime3b.c sio_prime3c.c diff --git a/src/sio/sio_fdc37c651.c b/src/sio/sio_fdc37c651.c deleted file mode 100644 index a19460d4c..000000000 --- a/src/sio/sio_fdc37c651.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * 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 FDC37C651 Super I/O Chip. - * - * Authors: Miran Grca, - * - * Copyright 2021 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/device.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> - - -#ifdef ENABLE_FDC37C651_LOG -int fdc37c651_do_log = ENABLE_FDC37C651_LOG; - - -static void -fdc37c651_log(const char *fmt, ...) -{ - va_list ap; - - if (fdc37c651_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define fdc37c651_log(fmt, ...) -#endif - - -typedef struct { - uint8_t tries, has_ide, - regs[16]; - int cur_reg, - com3_addr, com4_addr; - fdc_t *fdc; - serial_t *uart[2]; -} fdc37c651_t; - - -static void -set_com34_addr(fdc37c651_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(fdc37c651_t *dev, int port) -{ - uint8_t shift = (port << 2); - - serial_remove(dev->uart[port]); - if (dev->regs[2] & (4 << shift)) { - switch ((dev->regs[2] >> shift) & 3) { - 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(fdc37c651_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(7 /*5*/); - break; - case 3: - lpt1_init(0x278); - lpt1_irq(7 /*5*/); - break; - } -} - - -static void -fdc_handler(fdc37c651_t *dev) -{ - fdc_remove(dev->fdc); - if (dev->regs[0] & 0x10) - fdc_set_base(dev->fdc, 0x03f0); -} - - - -static void -ide_handler(fdc37c651_t *dev) -{ - /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ - if (dev->has_ide == 2) { - ide_sec_disable(); - ide_set_base(1, 0x1f0); - ide_set_side(1, 0x3f6); - if (dev->regs[0x00] & 0x01) - ide_sec_enable(); - } else if (dev->has_ide == 1) { - ide_pri_disable(); - ide_set_base(0, 0x1f0); - ide_set_side(0, 0x3f6); - if (dev->regs[0x00] & 0x01) - ide_pri_enable(); - } -} - - -static void -fdc37c651_write(uint16_t port, uint8_t val, void *priv) -{ - fdc37c651_t *dev = (fdc37c651_t *) priv; - uint8_t valxor = 0; - - if (dev->tries == 2) { - if (port == 0x3f0) { - if (val == 0xaa) - dev->tries = 0; - else - dev->cur_reg = val; - } else { - if (dev->cur_reg > 15) - return; - - valxor = val ^ dev->regs[dev->cur_reg]; - dev->regs[dev->cur_reg] = val; - - switch(dev->cur_reg) { - case 0: - if (dev->has_ide && (valxor & 0x01)) - ide_handler(dev); - if (valxor & 0x10) - fdc_handler(dev); - break; - case 1: - if (valxor & 3) - lpt1_handler(dev); - if (valxor & 0x60) { - set_com34_addr(dev); - set_serial_addr(dev, 0); - set_serial_addr(dev, 1); - } - break; - case 2: - if (valxor & 7) - set_serial_addr(dev, 0); - if (valxor & 0x70) - set_serial_addr(dev, 1); - break; - } - } - } else if ((port == 0x3f0) && (val == 0x55)) - dev->tries++; -} - - -static uint8_t -fdc37c651_read(uint16_t port, void *priv) -{ - fdc37c651_t *dev = (fdc37c651_t *) priv; - uint8_t ret = 0x00; - - if (dev->tries == 2) { - if (port == 0x3f1) - ret = dev->regs[dev->cur_reg]; - } - - return ret; -} - - -static void -fdc37c651_reset(fdc37c651_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); - fdc_remove(dev->fdc); - - dev->tries = 0; - memset(dev->regs, 0, 16); - - dev->regs[0x0] = 0x3f; - dev->regs[0x1] = 0x9f; - dev->regs[0x2] = 0xdc; - - set_serial_addr(dev, 0); - set_serial_addr(dev, 1); - - lpt1_handler(dev); - - fdc_handler(dev); - - if (dev->has_ide) - ide_handler(dev); -} - - -static void -fdc37c651_close(void *priv) -{ - fdc37c651_t *dev = (fdc37c651_t *) priv; - - free(dev); -} - - -static void * -fdc37c651_init(const device_t *info) -{ - fdc37c651_t *dev = (fdc37c651_t *) malloc(sizeof(fdc37c651_t)); - memset(dev, 0, sizeof(fdc37c651_t)); - - dev->fdc = device_add(&fdc_at_smc_device); - - dev->uart[0] = device_add_inst(&ns16450_device, 1); - dev->uart[1] = device_add_inst(&ns16450_device, 2); - - dev->has_ide = (info->local >> 8) & 0xff; - - io_sethandler(0x03f0, 0x0002, - fdc37c651_read, NULL, NULL, fdc37c651_write, NULL, NULL, dev); - - fdc37c651_reset(dev); - - return dev; -} - - -/* The three appear to differ only in the chip ID, if I - understood their datasheets correctly. */ -const device_t fdc37c651_device = { - "SMC FDC37C651 Super I/O", - 0, - 0, - fdc37c651_init, fdc37c651_close, NULL, - { NULL }, NULL, NULL, - NULL -}; - -const device_t fdc37c651_ide_device = { - "SMC FDC37C651 Super I/O (With IDE)", - 0, - 0x100, - fdc37c651_init, fdc37c651_close, NULL, - { NULL }, NULL, NULL, - NULL -}; diff --git a/src/sio/sio_fdc37c661.c b/src/sio/sio_fdc37c661.c deleted file mode 100644 index 8a17053a6..000000000 --- a/src/sio/sio_fdc37c661.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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. - */ -#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 chip_id, tries, - has_ide, regs[16]; - int cur_reg, - com3_addr, com4_addr; - fdc_t *fdc; - serial_t *uart[2]; -} fdc37c661_t; - - -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 << 2); - - serial_remove(dev->uart[port]); - if (dev->regs[2] & (4 << shift)) { - switch ((dev->regs[2] >> shift) & 3) { - 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(7 /*5*/); - break; - case 3: - lpt1_init(0x278); - lpt1_irq(7 /*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 -ide_handler(fdc37c661_t *dev) -{ - /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ - if (dev->has_ide == 2) { - ide_sec_disable(); - ide_set_base(1, 0x1f0); - ide_set_side(1, 0x3f6); - if (dev->regs[0x00] & 0x01) - ide_sec_enable(); - } else if (dev->has_ide == 1) { - ide_pri_disable(); - ide_set_base(0, 0x1f0); - ide_set_side(0, 0x3f6); - if (dev->regs[0x00] & 0x01) - ide_pri_enable(); - } -} - - -static void -fdc37c661_write(uint16_t port, uint8_t val, void *priv) -{ - fdc37c661_t *dev = (fdc37c661_t *) priv; - uint8_t valxor = 0; - - if (dev->tries == 2) { - if (port == 0x3f0) { - if (val == 0xaa) - dev->tries = 0; - else - dev->cur_reg = val; - } else { - if (dev->cur_reg > 15) - return; - - valxor = val ^ dev->regs[dev->cur_reg]; - dev->regs[dev->cur_reg] = val; - - switch(dev->cur_reg) { - case 0: - if (dev->has_ide && (valxor & 0x01)) - ide_handler(dev); - if (valxor & 0x10) - fdc_handler(dev); - break; - case 1: - if (valxor & 3) - lpt1_handler(dev); - if (valxor & 0x60) { - set_com34_addr(dev); - set_serial_addr(dev, 0); - set_serial_addr(dev, 1); - } - break; - case 2: - if (valxor & 7) - set_serial_addr(dev, 0); - if (valxor & 0x70) - set_serial_addr(dev, 1); - break; - } - } - } else if ((port == 0x3f0) && (val == 0x55)) - dev->tries++; -} - - -static uint8_t -fdc37c661_read(uint16_t port, void *priv) -{ - fdc37c661_t *dev = (fdc37c661_t *) priv; - uint8_t ret = 0x00; - - if (dev->tries == 2) { - 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); - fdc_remove(dev->fdc); - - dev->tries = 0; - memset(dev->regs, 0, 16); - - dev->regs[0x0] = 0x3f; - dev->regs[0x1] = 0x9f; - dev->regs[0x2] = 0xdc; - dev->regs[0x3] = 0x78; - - set_serial_addr(dev, 0); - set_serial_addr(dev, 1); - - lpt1_handler(dev); - - fdc_handler(dev); - - if (dev->has_ide) - ide_handler(dev); -} - - -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(&ns16450_device, 1); - dev->uart[1] = device_add_inst(&ns16450_device, 2); - - dev->chip_id = info->local & 0xff; - dev->has_ide = (info->local >> 8) & 0xff; - - io_sethandler(0x03f0, 0x0002, - fdc37c661_read, NULL, NULL, fdc37c661_write, NULL, NULL, dev); - - fdc37c661_reset(dev); - - return dev; -} - - -/* The three appear to differ only in the chip ID, if I - understood their datasheets correctly. */ -const device_t fdc37c661_device = { - "SMC FDC37C661 Super I/O", - 0, - 0x00, - fdc37c661_init, fdc37c661_close, NULL, - { NULL }, NULL, NULL, - NULL -}; - -const device_t fdc37c661_ide_device = { - "SMC FDC37C661 Super I/O (With IDE)", - 0, - 0x100, - fdc37c661_init, fdc37c661_close, NULL, - { NULL }, NULL, NULL, - NULL -}; diff --git a/src/sio/sio_fdc37c66x.c b/src/sio/sio_fdc37c6xx.c similarity index 71% rename from src/sio/sio_fdc37c66x.c rename to src/sio/sio_fdc37c6xx.c index ce8776944..59f93c1fa 100644 --- a/src/sio/sio_fdc37c66x.c +++ b/src/sio/sio_fdc37c6xx.c @@ -37,17 +37,18 @@ typedef struct { - uint8_t chip_id, tries, - has_ide, regs[16]; + uint8_t max_reg, chip_id, + tries, has_ide, + regs[16]; int cur_reg, com3_addr, com4_addr; fdc_t *fdc; serial_t *uart[2]; -} fdc37c66x_t; +} fdc37c6xx_t; static void -set_com34_addr(fdc37c66x_t *dev) +set_com34_addr(fdc37c6xx_t *dev) { switch (dev->regs[1] & 0x60) { case 0x00: @@ -71,7 +72,7 @@ set_com34_addr(fdc37c66x_t *dev) static void -set_serial_addr(fdc37c66x_t *dev, int port) +set_serial_addr(fdc37c6xx_t *dev, int port) { uint8_t shift = (port << 2); double clock_src = 24000000.0 / 13.0; @@ -102,7 +103,7 @@ set_serial_addr(fdc37c66x_t *dev, int port) static void -lpt1_handler(fdc37c66x_t *dev) +lpt1_handler(fdc37c6xx_t *dev) { lpt1_remove(); switch (dev->regs[1] & 3) { @@ -123,7 +124,7 @@ lpt1_handler(fdc37c66x_t *dev) static void -fdc_handler(fdc37c66x_t *dev) +fdc_handler(fdc37c6xx_t *dev) { fdc_remove(dev->fdc); if (dev->regs[0] & 0x10) @@ -133,7 +134,7 @@ fdc_handler(fdc37c66x_t *dev) static void -ide_handler(fdc37c66x_t *dev) +ide_handler(fdc37c6xx_t *dev) { /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ if (dev->has_ide == 2) { @@ -153,9 +154,9 @@ ide_handler(fdc37c66x_t *dev) static void -fdc37c66x_write(uint16_t port, uint8_t val, void *priv) +fdc37c6xx_write(uint16_t port, uint8_t val, void *priv) { - fdc37c66x_t *dev = (fdc37c66x_t *) priv; + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; uint8_t valxor = 0; if (dev->tries == 2) { @@ -165,7 +166,7 @@ fdc37c66x_write(uint16_t port, uint8_t val, void *priv) else dev->cur_reg = val; } else { - if (dev->cur_reg > 15) + if (dev->cur_reg > dev->max_reg) return; valxor = val ^ dev->regs[dev->cur_reg]; @@ -221,9 +222,9 @@ fdc37c66x_write(uint16_t port, uint8_t val, void *priv) static uint8_t -fdc37c66x_read(uint16_t port, void *priv) +fdc37c6xx_read(uint16_t port, void *priv) { - fdc37c66x_t *dev = (fdc37c66x_t *) priv; + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; uint8_t ret = 0x00; if (dev->tries == 2) { @@ -236,7 +237,7 @@ fdc37c66x_read(uint16_t port, void *priv) static void -fdc37c66x_reset(fdc37c66x_t *dev) +fdc37c6xx_reset(fdc37c6xx_t *dev) { dev->com3_addr = 0x338; dev->com4_addr = 0x238; @@ -256,13 +257,33 @@ fdc37c66x_reset(fdc37c66x_t *dev) dev->tries = 0; memset(dev->regs, 0, 16); - dev->regs[0x0] = 0x3a; + switch (dev->chip_id) { + case 0x63: case 0x65: + dev->max_reg = 0x0f; + dev->regs[0x0] = 0x3b; + break; + case 0x64: case 0x66: + dev->max_reg = 0x0f; + dev->regs[0x0] = 0x2b; + break; + default: + dev->max_reg = (dev->chip_id >= 0x61) ? 0x03 : 0x02; + dev->regs[0x0] = 0x3f; + break; + } + dev->regs[0x1] = 0x9f; dev->regs[0x2] = 0xdc; dev->regs[0x3] = 0x78; - dev->regs[0x6] = 0xff; - dev->regs[0xd] = dev->chip_id; - dev->regs[0xe] = 0x01; + + if (dev->chip_id >= 0x63) { + dev->regs[0x6] = 0xff; + dev->regs[0xd] = dev->chip_id; + if (dev->chip_id >= 0x65) + dev->regs[0xe] = 0x02; + else + dev->regs[0xe] = 0x01; + } set_serial_addr(dev, 0); set_serial_addr(dev, 1); @@ -277,32 +298,37 @@ fdc37c66x_reset(fdc37c66x_t *dev) static void -fdc37c66x_close(void *priv) +fdc37c6xx_close(void *priv) { - fdc37c66x_t *dev = (fdc37c66x_t *) priv; + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; free(dev); } static void * -fdc37c66x_init(const device_t *info) +fdc37c6xx_init(const device_t *info) { - fdc37c66x_t *dev = (fdc37c66x_t *) malloc(sizeof(fdc37c66x_t)); - memset(dev, 0, sizeof(fdc37c66x_t)); + fdc37c6xx_t *dev = (fdc37c6xx_t *) malloc(sizeof(fdc37c6xx_t)); + memset(dev, 0, sizeof(fdc37c6xx_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); - dev->chip_id = info->local & 0xff; dev->has_ide = (info->local >> 8) & 0xff; - io_sethandler(0x03f0, 0x0002, - fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, dev); + if (dev->chip_id >= 0x63) { + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + } else { + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + } - fdc37c66x_reset(dev); + io_sethandler(0x03f0, 0x0002, + fdc37c6xx_read, NULL, NULL, fdc37c6xx_write, NULL, NULL, dev); + + fdc37c6xx_reset(dev); return dev; } @@ -310,11 +336,47 @@ fdc37c66x_init(const device_t *info) /* The three appear to differ only in the chip ID, if I understood their datasheets correctly. */ +const device_t fdc37c651_device = { + "SMC FDC37C651 Super I/O", + 0, + 0x51, + fdc37c6xx_init, fdc37c6xx_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t fdc37c651_ide_device = { + "SMC FDC37C651 Super I/O (With IDE)", + 0, + 0x151, + fdc37c6xx_init, fdc37c6xx_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t fdc37c661_device = { + "SMC FDC37C661 Super I/O", + 0, + 0x61, + fdc37c6xx_init, fdc37c6xx_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t fdc37c661_ide_device = { + "SMC FDC37C661 Super I/O (With IDE)", + 0, + 0x161, + fdc37c6xx_init, fdc37c6xx_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + const device_t fdc37c663_device = { "SMC FDC37C663 Super I/O", 0, 0x63, - fdc37c66x_init, fdc37c66x_close, NULL, + fdc37c6xx_init, fdc37c6xx_close, NULL, { NULL }, NULL, NULL, NULL }; @@ -323,7 +385,7 @@ const device_t fdc37c663_ide_device = { "SMC FDC37C663 Super I/O (With IDE)", 0, 0x163, - fdc37c66x_init, fdc37c66x_close, NULL, + fdc37c6xx_init, fdc37c6xx_close, NULL, { NULL }, NULL, NULL, NULL }; @@ -332,7 +394,7 @@ const device_t fdc37c665_device = { "SMC FDC37C665 Super I/O", 0, 0x65, - fdc37c66x_init, fdc37c66x_close, NULL, + fdc37c6xx_init, fdc37c6xx_close, NULL, { NULL }, NULL, NULL, NULL }; @@ -341,7 +403,7 @@ const device_t fdc37c665_ide_device = { "SMC FDC37C665 Super I/O (With IDE)", 0, 0x265, - fdc37c66x_init, fdc37c66x_close, NULL, + fdc37c6xx_init, fdc37c6xx_close, NULL, { NULL }, NULL, NULL, NULL }; @@ -350,7 +412,7 @@ const device_t fdc37c666_device = { "SMC FDC37C666 Super I/O", 0, 0x66, - fdc37c66x_init, fdc37c66x_close, NULL, + fdc37c6xx_init, fdc37c6xx_close, NULL, { NULL }, NULL, NULL, NULL }; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 74ead9b62..2b30146b5 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -73,6 +73,7 @@ enum S3_METHEUS_86C928, S3_AMI_86C924, S3_TRIO64V2_DX, + S3_TRIO64V2_DX_ONBOARD, S3_PHOENIX_TRIO64VPLUS, S3_PHOENIX_TRIO64VPLUS_ONBOARD, S3_DIAMOND_STEALTH_SE, @@ -2460,8 +2461,14 @@ s3_in(uint16_t addr, void *p) break; case 0x3c5: - if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) - return svga->seqregs[svga->seqaddr]; + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) { + temp = svga->seqregs[svga->seqaddr]; + /* This is needed for the Intel Advanced/ATX's built-in S3 Trio64V+ BIOS to not + get stuck in an infinite loop. */ + if ((s3->card_type == S3_PHOENIX_TRIO64VPLUS_ONBOARD) && (svga->seqaddr == 0x17)) + svga->seqregs[svga->seqaddr] ^= 0x01; + return temp; + } break; case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: @@ -5884,6 +5891,11 @@ static void *s3_init(const device_t *info) chip = S3_TRIO64V2; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); break; + case S3_TRIO64V2_DX_ONBOARD: + bios_fn = NULL; + chip = S3_TRIO64V2; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); + break; default: free(s3); return NULL; @@ -6205,6 +6217,7 @@ static void *s3_init(const device_t *info) break; case S3_TRIO64V2_DX: + case S3_TRIO64V2_DX_ONBOARD: svga->decode_mask = (4 << 20) - 1; s3->id = 0xe1; /*Trio64V2/DX*/ s3->id_ext = s3->id_ext_pci = 0x01; @@ -6981,3 +6994,17 @@ const device_t s3_trio64v2_dx_pci_device = s3_standard_config }; + +const device_t s3_trio64v2_dx_onboard_pci_device = +{ + "S3 Trio64V2/DX On-Board PCI", + DEVICE_PCI, + S3_TRIO64V2_DX_ONBOARD, + s3_init, + s3_close, + NULL, + { NULL }, + s3_speed_changed, + s3_force_redraw, + s3_standard_config +}; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 20b2b11bc..46ea13292 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -235,18 +235,9 @@ video_reset_close(void) } -void -video_reset(int card) +static void +video_prepare(void) { - /* This is needed to avoid duplicate resets. */ - if ((video_get_type() != VIDEO_FLAG_TYPE_NONE) && was_reset) - return; - - vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", - card, (machines[machine].flags & MACHINE_VIDEO)?1:0); - - loadfont("roms/video/mda/mda.rom", 0); - /* Reset (deallocate) the video font arrays. */ if (fontdatksc5601) { free(fontdatksc5601); @@ -260,14 +251,39 @@ video_reset(int card) /* Reset the blend. */ herc_blend = 0; + /* Do an inform on the default values, so that that there's some sane values initialized + even if the device init function does not do an inform of its own. */ + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); +} + + +void +video_pre_reset(int card) +{ + if ((card == VID_NONE) || \ + (card == VID_INTERNAL) || (machines[machine].flags & MACHINE_VIDEO_ONLY)) + video_prepare(); +} + + +void +video_reset(int card) +{ + /* This is needed to avoid duplicate resets. */ + if ((video_get_type() != VIDEO_FLAG_TYPE_NONE) && was_reset) + return; + + vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", + card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + + loadfont("roms/video/mda/mda.rom", 0); + /* Do not initialize internal cards here. */ if (!(card == VID_NONE) && \ !(card == VID_INTERNAL) && !(machines[machine].flags & MACHINE_VIDEO_ONLY)) { vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); - /* Do an inform on the default values, so that that there's some sane values initialized - even if the device init function does not do an inform of its own. */ - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); + video_prepare(); /* Initialize the video card. */ device_add(video_cards[card].device); diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 90872027f..fa522fd43 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -88,10 +88,12 @@ enum { TGUI_9400CXI = 0, TGUI_9440, - TGUI_9660, - TGUI_9680 + TGUI_9660, + TGUI_9680 }; +#define ONBOARD 0x0100 + typedef struct tgui_t { mem_mapping_t linear_mapping; @@ -160,6 +162,8 @@ typedef struct tgui_t volatile int write_blitter; void *i2c, *ddc; + + int has_bios; } tgui_t; video_timings_t timing_tgui_vlb = {VIDEO_BUS, 4, 8, 16, 4, 8, 16}; @@ -908,13 +912,13 @@ uint8_t tgui_pci_read(int func, int addr, void *p) case 0x16: return tgui->mmio_base >> 16; case 0x17: return tgui->mmio_base >> 24; - case 0x30: return (tgui->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return tgui->pci_regs[0x32]; - case 0x33: return tgui->pci_regs[0x33]; - - case 0x3c: return tgui->int_line; - case 0x3d: return PCI_INTA; + case 0x30: return tgui->has_bios ? (tgui->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return tgui->has_bios ? tgui->pci_regs[0x32] : 0x00; + case 0x33: return tgui->has_bios ? tgui->pci_regs[0x33] : 0x00; + + case 0x3c: return tgui->int_line; + case 0x3d: return PCI_INTA; } return 0; } @@ -970,23 +974,25 @@ void tgui_pci_write(int func, int addr, uint8_t val, void *p) tgui->mmio_base = (tgui->mmio_base & 0x00e00000) | (val << 24); tgui_recalcmapping(tgui); break; - - case 0x30: case 0x32: case 0x33: - tgui->pci_regs[addr] = val; - if (tgui->pci_regs[0x30] & 0x01) - { - uint32_t biosaddr = (tgui->pci_regs[0x32] << 16) | (tgui->pci_regs[0x33] << 24); - mem_mapping_set_addr(&tgui->bios_rom.mapping, biosaddr, 0x8000); - } - else - { - mem_mapping_disable(&tgui->bios_rom.mapping); - } - return; - - case 0x3c: - tgui->int_line = val; - return; + + case 0x30: case 0x32: case 0x33: + if (tgui->has_bios) { + tgui->pci_regs[addr] = val; + if (tgui->pci_regs[0x30] & 0x01) + { + uint32_t biosaddr = (tgui->pci_regs[0x32] << 16) | (tgui->pci_regs[0x33] << 24); + mem_mapping_set_addr(&tgui->bios_rom.mapping, biosaddr, 0x8000); + } + else + { + mem_mapping_disable(&tgui->bios_rom.mapping); + } + } + return; + + case 0x3c: + tgui->int_line = val; + return; } } @@ -2801,16 +2807,15 @@ tgui_mmio_read_l(uint32_t addr, void *p) static void *tgui_init(const device_t *info) { const char *bios_fn; - int type = info->local; tgui_t *tgui = malloc(sizeof(tgui_t)); - svga_t *svga = &tgui->svga; + svga_t *svga = &tgui->svga; memset(tgui, 0, sizeof(tgui_t)); tgui->vram_size = device_get_config_int("memory") << 20; tgui->vram_mask = tgui->vram_size - 1; - tgui->type = type; + tgui->type = info->local & 0xff; tgui->pci = !!(info->flags & DEVICE_PCI); @@ -2819,7 +2824,7 @@ static void *tgui_init(const device_t *info) bios_fn = ROM_TGUI_9400CXI; break; case TGUI_9440: - bios_fn = ROM_TGUI_9440; + bios_fn = (info->local & ONBOARD) ? NULL : ROM_TGUI_9440; break; case TGUI_9660: case TGUI_9680: @@ -2830,7 +2835,10 @@ static void *tgui_init(const device_t *info) return NULL; } - rom_init(&tgui->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + tgui->has_bios = (bios_fn != NULL); + + if (tgui->has_bios) + rom_init(&tgui->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (tgui->pci) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tgui_pci); @@ -2844,33 +2852,39 @@ static void *tgui_init(const device_t *info) NULL); if (tgui->type == TGUI_9400CXI) - svga->ramdac = device_add(&tkd8001_ramdac_device); + svga->ramdac = device_add(&tkd8001_ramdac_device); mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, MEM_MAPPING_EXTERNAL, svga); mem_mapping_add(&tgui->accel_mapping, 0, 0, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); - if (tgui->type >= TGUI_9440) - mem_mapping_add(&tgui->mmio_mapping, 0, 0, tgui_mmio_read, tgui_mmio_read_w, tgui_mmio_read_l, tgui_mmio_write, tgui_mmio_write_w, tgui_mmio_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); + if (tgui->type >= TGUI_9440) + mem_mapping_add(&tgui->mmio_mapping, 0, 0, tgui_mmio_read, tgui_mmio_read_w, tgui_mmio_read_l, tgui_mmio_write, tgui_mmio_write_w, tgui_mmio_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); mem_mapping_disable(&tgui->accel_mapping); - mem_mapping_disable(&tgui->mmio_mapping); + mem_mapping_disable(&tgui->mmio_mapping); - tgui_set_io(tgui); + tgui_set_io(tgui); - if (tgui->pci && (tgui->type >= TGUI_9440)) + if (tgui->pci && (tgui->type >= TGUI_9440)) { + if (tgui->has_bios) tgui->card = pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + else + tgui->card = pci_add_card(PCI_ADD_VIDEO | PCI_ADD_STRICT, tgui_pci_read, tgui_pci_write, tgui); + } - tgui->pci_regs[PCI_REG_COMMAND] = 3; + tgui->pci_regs[PCI_REG_COMMAND] = 3; + if (tgui->has_bios) { tgui->pci_regs[0x30] = 0x00; tgui->pci_regs[0x32] = 0x0c; tgui->pci_regs[0x33] = 0x00; + } - if (tgui->type >= TGUI_9440) - svga->packed_chain4 = 1; - - if (tgui->type >= TGUI_9660) { - tgui->i2c = i2c_gpio_init("ddc_tgui"); - tgui->ddc = ddc_init(i2c_gpio_get_bus(tgui->i2c)); - } + if (tgui->type >= TGUI_9440) + svga->packed_chain4 = 1; + + if (tgui->type >= TGUI_9660) { + tgui->i2c = i2c_gpio_init("ddc_tgui"); + tgui->ddc = ddc_init(i2c_gpio_get_bus(tgui->i2c)); + } return tgui; } @@ -3019,6 +3033,20 @@ const device_t tgui9440_pci_device = tgui9440_config }; +const device_t tgui9440_onboard_pci_device = +{ + "Trident TGUI 9440AGi On-Board PCI", + DEVICE_PCI, + TGUI_9440 | ONBOARD, + tgui_init, + tgui_close, + NULL, + { NULL }, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; + const device_t tgui9660_pci_device = { "Trident TGUI 9660XGi PCI", diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9b01db329..bcea4ab6e 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -328,7 +328,7 @@ else endif endif ifeq ($(DEBUG), y) - DFLAGS += -ggdb -DDEBUG + DFLAGS += -ggdb -DDEBUG -DUSE_ACYCS AOPTIM := ifndef COPTIM COPTIM := -Og @@ -599,6 +599,7 @@ CHIPSETOBJ := acc2168.o \ scamp.o scat.o \ stpc.o \ wd76c10.o vl82c480.o \ + umc_8886.o umc_hb4.o \ via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o @@ -645,8 +646,8 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hw endif SIOOBJ := sio_acc3221.o \ - sio_f82c710.o sio_82091aa.o sio_fdc37c651.o \ - sio_fdc37c661.o sio_fdc37c66x.o sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ + sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \ + sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ sio_it8661f.o \ sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \ sio_prime3b.o sio_prime3c.o \ From 2f3bb38dde83af94a4c31805d533d136569cc710 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 23 Aug 2021 17:26:40 +0200 Subject: [PATCH 059/140] Implemented the UMOV instruction on a number of CPU's, needed by some Phoenix BIOS'es. --- src/cpu/386_ops.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 5b472298b..8d2b9edf9 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -148,9 +148,9 @@ static int fopcode; static int ILLEGAL(uint32_t fetchdat) { + pclog("[%04X:%08X] Illegal instruction %08X (%02X)\n", CS, cpu_state.pc, fetchdat, fopcode); cpu_state.pc = cpu_state.oldpc; - pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); x86illegal(); return 0; } @@ -457,7 +457,7 @@ const OpFn OP_TABLE(386_0f)[1024] = /*16-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -479,7 +479,7 @@ const OpFn OP_TABLE(386_0f)[1024] = /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -501,7 +501,7 @@ const OpFn OP_TABLE(386_0f)[1024] = /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -523,7 +523,7 @@ const OpFn OP_TABLE(386_0f)[1024] = /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -548,7 +548,7 @@ const OpFn OP_TABLE(486_0f)[1024] = /*16-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -570,7 +570,7 @@ const OpFn OP_TABLE(486_0f)[1024] = /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -592,7 +592,7 @@ const OpFn OP_TABLE(486_0f)[1024] = /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -614,7 +614,7 @@ const OpFn OP_TABLE(486_0f)[1024] = /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -821,7 +821,7 @@ const OpFn OP_TABLE(ibm486_0f)[1024] = /*16-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -843,7 +843,7 @@ const OpFn OP_TABLE(ibm486_0f)[1024] = /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -865,7 +865,7 @@ const OpFn OP_TABLE(ibm486_0f)[1024] = /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -887,7 +887,7 @@ const OpFn OP_TABLE(ibm486_0f)[1024] = /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1094,7 +1094,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*16-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1116,7 +1116,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*32-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1138,7 +1138,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*16-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1160,7 +1160,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*32-bit data, 32-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, From b798b59a698963e3ace6605a92fd09db4d676fd5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 23 Aug 2021 21:48:42 +0200 Subject: [PATCH 060/140] Some ALi M1429G changes, including returning registers in the Cyrix range as FF. --- src/chipset/ali1429.c | 100 +++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index 08cc6ff14..da8ded3ab 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -38,17 +38,19 @@ #include <86box/smram.h> #include <86box/chipset.h> -#define disabled_shadow (MEM_READ_EXTANY | MEM_WRITE_EXTANY) +#define disabled_shadow (MEM_READ_EXTANY | MEM_WRITE_EXTANY) + #ifdef ENABLE_ALI1429_LOG int ali1429_do_log = ENABLE_ALI1429_LOG; + + static void ali1429_log(const char *fmt, ...) { va_list ap; - if (ali1429_do_log) - { + if (ali1429_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); @@ -58,17 +60,19 @@ ali1429_log(const char *fmt, ...) #define ali1429_log(fmt, ...) #endif + typedef struct { - uint8_t index, cfg_locked, - regs[256]; + uint8_t index, cfg_locked, + regs[256]; - smram_t *smram; + smram_t * smram; } ali1429_t; -static void ali1429_shadow_recalc(ali1429_t *dev) -{ +static void +ali1429_shadow_recalc(ali1429_t *dev) +{ uint32_t base, i, can_write, can_read; shadowbios = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x01); @@ -77,8 +81,7 @@ static void ali1429_shadow_recalc(ali1429_t *dev) can_write = (dev->regs[0x14] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; can_read = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - for (i = 0; i < 8; i++) - { + for (i = 0; i < 8; i++) { base = 0xc0000 + (i << 15); if (dev->regs[0x13] & (1 << i)) @@ -87,56 +90,61 @@ static void ali1429_shadow_recalc(ali1429_t *dev) mem_set_mem_state_both(base, 0x8000, disabled_shadow); } - flushmmucache(); + flushmmucache_nopc(); } + static void ali1429_write(uint16_t addr, uint8_t val, void *priv) { ali1429_t *dev = (ali1429_t *)priv; - switch (addr) - { - case 0x22: - dev->index = val; - break; + switch (addr) { + case 0x22: + dev->index = val; + break; - case 0x23: - if (dev->index != 0x03) - ali1429_log("M1429: dev->regs[%02x] = %02x\n", dev->index, val); + case 0x23: +#ifdef ENABLE_ALI1429_LOG + if (dev->index != 0x03) + ali1429_log("M1429: dev->regs[%02x] = %02x\n", dev->index, val); +#endif - if (dev->index == 0x03) - dev->cfg_locked = !(val == 0xc5); + if (dev->index == 0x03) + dev->cfg_locked = !(val == 0xc5); - if (!dev->cfg_locked) - { - dev->regs[dev->index] = val; + if (!dev->cfg_locked) { + dev->regs[dev->index] = val; - switch (dev->index) - { - case 0x13: - case 0x14: - ali1429_shadow_recalc(dev); - break; + switch (dev->index) { + case 0x13: case 0x14: + ali1429_shadow_recalc(dev); + break; - case 0x18: - cpu_cache_ext_enabled = !!(val & 2); - cpu_update_waitstates(); - break; - } - } - - break; + case 0x18: + cpu_cache_ext_enabled = !!(val & 2); + cpu_update_waitstates(); + break; + } + } + break; } } + static uint8_t ali1429_read(uint16_t addr, void *priv) { ali1429_t *dev = (ali1429_t *)priv; - return (addr == 0x23) ? dev->regs[dev->index] : 0xff; + uint8_t ret = 0xff; + + if ((addr == 0x23) && (dev->index < 0xc0)) + ret = dev->regs[dev->index]; + + return ret; } + static void ali1429_close(void *priv) { @@ -145,16 +153,16 @@ ali1429_close(void *priv) free(dev); } + static void * ali1429_init(const device_t *info) { ali1429_t *dev = (ali1429_t *)malloc(sizeof(ali1429_t)); memset(dev, 0, sizeof(ali1429_t)); - /* - M1429 Ports: - 22h Index Port - 23h Data Port + /* M1429 Ports: + 22h Index Port + 23h Data Port */ io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev); @@ -167,6 +175,7 @@ ali1429_init(const device_t *info) return dev; } + const device_t ali1429_device = { "ALi M1429", 0, @@ -174,7 +183,8 @@ const device_t ali1429_device = { ali1429_init, ali1429_close, NULL, - {NULL}, + { NULL }, NULL, NULL, - NULL}; + NULL +}; From 3ddbca6fca0b9c306b9c28071def6ff085b7e9bb Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 23 Aug 2021 22:01:25 +0200 Subject: [PATCH 061/140] Merged tiseno100's ALi M1429(G) changes. --- src/chipset/ali1429.c | 151 +++++++++++++++++++++++++++++++----- src/include/86box/chipset.h | 1 + 2 files changed, 132 insertions(+), 20 deletions(-) diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index da8ded3ab..2ccddc1be 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -38,7 +38,7 @@ #include <86box/smram.h> #include <86box/chipset.h> -#define disabled_shadow (MEM_READ_EXTANY | MEM_WRITE_EXTANY) +#define GREEN dev->is_g /* Is G Variant */ #ifdef ENABLE_ALI1429_LOG @@ -63,10 +63,8 @@ ali1429_log(const char *fmt, ...) typedef struct { - uint8_t index, cfg_locked, - regs[256]; - - smram_t * smram; + uint8_t is_g, index, cfg_locked, reg_57h, + regs[90]; } ali1429_t; @@ -87,7 +85,7 @@ ali1429_shadow_recalc(ali1429_t *dev) if (dev->regs[0x13] & (1 << i)) mem_set_mem_state_both(base, 0x8000, can_read | can_write); else - mem_set_mem_state_both(base, 0x8000, disabled_shadow); + mem_set_mem_state_both(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } flushmmucache_nopc(); @@ -114,17 +112,93 @@ ali1429_write(uint16_t addr, uint8_t val, void *priv) dev->cfg_locked = !(val == 0xc5); if (!dev->cfg_locked) { - dev->regs[dev->index] = val; - + /* Common M1429 Registers */ switch (dev->index) { + case 0x10: case 0x11: + dev->regs[dev->index] = val; + break; + + case 0x12: + dev->regs[dev->index] = val; + if(val & 4) + mem_remap_top(128); + else + mem_remap_top(0); + break; + case 0x13: case 0x14: + dev->regs[dev->index] = val; ali1429_shadow_recalc(dev); break; + case 0x15: case 0x16: + case 0x17: + dev->regs[dev->index] = val; + break; + case 0x18: + dev->regs[dev->index] = (val & 0x8f) | 0x20; cpu_cache_ext_enabled = !!(val & 2); cpu_update_waitstates(); break; + + case 0x19: case 0x1a: + case 0x1e: + dev->regs[dev->index] = val; + break; + + case 0x20: + dev->regs[dev->index] = val; + + switch(val & 7) { + case 0: case 7: /* Illegal */ + cpu_set_isa_speed(7159091); + break; + + case 1: + cpu_set_isa_speed(cpu_busspeed / 4); + break; + + case 2: + cpu_set_isa_speed(cpu_busspeed / 5); + break; + + case 3: + cpu_set_isa_speed(cpu_busspeed / 6); + break; + + case 4: + cpu_set_isa_speed(cpu_busspeed / 8); + break; + + case 5: + cpu_set_isa_speed(cpu_busspeed / 10); + break; + + case 6: + cpu_set_isa_speed(cpu_busspeed / 12); + break; + } + break; + + case 0x21 ... 0x27: + dev->regs[dev->index] = val; + break; + } + + /* M1429G Only Registers */ + if (GREEN) { + switch (dev->index) { + case 0x30 ... 0x41: + case 0x43: case 0x45: + case 0x4a: + dev->regs[dev->index] = val; + break; + + case 0x57: + dev->reg_57h = val; + break; + } } } break; @@ -138,8 +212,12 @@ ali1429_read(uint16_t addr, void *priv) ali1429_t *dev = (ali1429_t *)priv; uint8_t ret = 0xff; - if ((addr == 0x23) && (dev->index < 0xc0)) + if ((addr == 0x23) && (dev->index >= 0x10) && (dev->index <= 0x4a)) ret = dev->regs[dev->index]; + else if ((addr == 0x23) && (dev->index == 0x57)) + ret = dev->reg_57h; + else if (addr == 0x22) + ret = dev->index; return ret; } @@ -154,37 +232,70 @@ ali1429_close(void *priv) } +static void +ali1429_defaults(ali1429_t *dev) +{ + /* M1429 Defaults */ + dev->regs[0x10] = 0xf0; + dev->regs[0x11] = 0xff; + dev->regs[0x12] = 0x10; + dev->regs[0x14] = 0x48; + dev->regs[0x15] = 0x40; + dev->regs[0x17] = 0x7a; + dev->regs[0x1a] = 0x80; + dev->regs[0x22] = 0x80; + dev->regs[0x23] = 0x57; + dev->regs[0x25] = 0xc0; + dev->regs[0x27] = 0x30; + + /* M1429G Default Registers */ + if (GREEN) { + dev->regs[0x31] = 0x88; + dev->regs[0x32] = 0xc0; + dev->regs[0x38] = 0xe5; + dev->regs[0x40] = 0xe3; + dev->regs[0x41] = 2; + dev->regs[0x45] = 0x80; + } +} + + static void * ali1429_init(const device_t *info) { ali1429_t *dev = (ali1429_t *)malloc(sizeof(ali1429_t)); memset(dev, 0, sizeof(ali1429_t)); + dev->cfg_locked = 1; + GREEN = info->local; + /* M1429 Ports: 22h Index Port 23h Data Port */ io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev); - dev->cfg_locked = 1; - - device_add(&apm_device); device_add(&port_92_device); - /* dev->smram = smram_add(); */ + + ali1429_defaults(dev); return dev; } - const device_t ali1429_device = { "ALi M1429", 0, 0, - ali1429_init, - ali1429_close, - NULL, - { NULL }, - NULL, - NULL, + ali1429_init, ali1429_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t ali1429g_device = { + "ALi M1429G", + 0, + 1, + ali1429_init, ali1429_close, NULL, + { NULL }, NULL, NULL, NULL }; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 83642fe62..9a7db6c64 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -24,6 +24,7 @@ extern const device_t acc2168_device; /* ALi */ extern const device_t ali1217_device; extern const device_t ali1429_device; +extern const device_t ali1429g_device; extern const device_t ali1489_device; extern const device_t ali1531_device; extern const device_t ali1541_device; From d30ad04a88b897597fe036579c7aff109858bec9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 24 Aug 2021 21:11:00 +0200 Subject: [PATCH 062/140] UMC UM88xx fixes, ALi M1429 documentation, and added the DataExpert 386SX, PC Chips M919, Samsung SPC7700P-LW, and Acrosser AR-B1423C. Also renamed the ALi M1429G AMI WinBIOS 486 to Kaimei 486. --- src/chipset/ali1429.c | 66 ++++++++++++++++-- src/chipset/umc_8886.c | 62 +++++++++++------ src/chipset/umc_hb4.c | 20 ++++-- src/include/86box/machine.h | 6 +- src/machine/m_at_286_386sx.c | 30 +++++++-- src/machine/m_at_386dx_486.c | 127 ++++++++++++++++++++++++++++++----- src/machine/machine_table.c | 29 +++++--- 7 files changed, 277 insertions(+), 63 deletions(-) diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index 2ccddc1be..b96ec7896 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -8,15 +8,71 @@ * * Implementation of the ALi M1429 chipset. * - * Note: This chipset has no datasheet, everything were done via - * reverse engineering the BIOS of various machines using it. + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. * - * Authors: Tiseno100 - * - * Copyright 2020 Tiseno100 + * Authors: Tiseno100, + * Miran Grca, * + * Copyright 2020,2021 Tiseno100. + * Copyright 2021,2021 Miran Grca. */ +/* + ALi M1429/M1429G Configuration Registers + + Notes: Incorporated sometimes with a M1435 PCI-to-VLB Bridge + M1429G is just a 1429 with Green Functionality + SMM in it's entirety needs more research + + Warning: Register documentation may be inaccurate! + + Register 03h: Write C5h to unlock the configuration registers + + Register 10h & 11h: DRAM Bank Configuration + + Register 12h: + Bit 2: Memory Remapping Enable (128KB) + + Register 13h: + Bit 7: Shadow RAM Enable for F8000-FFFFF + Bit 6: Shadow RAM Enable for F0000-F7FFF + Bit 5: Shadow RAM Enable for E8000-FFFFF + Bit 4: Shadow RAM Enable for E0000-F7FFF + Bit 3: Shadow RAM Enable for D8000-FFFFF + Bit 2: Shadow RAM Enable for D0000-F7FFF + Bit 1: Shadow RAM Enable for C8000-FFFFF + Bit 0: Shadow RAM Enable for C0000-F7FFF + + Register 14h: + Bit 1: Shadow RAM Write for Enabled Segments + Bit 0: Shadow RAM Read for Enabled Segments + + Register 18h: + Bit 6-5-4 (Cache Size) + 0 0 0 32KB + 0 0 1 128KB + 0 1 0 256KB + 0 1 1 512KB + 1 0 0 64KB + 1 0 1 256KB + 1 1 0 512KB + 1 1 1 1MB + + Bit 1: L2 Cache Enable + + Register 20h: + Bits 2-1-0: Bus Clock Speed + 0 0 0: 7.1519Mhz (ATCLK2) + 0 0 1: CLK2IN/4 + 0 1 0: CLK2IN/5 + 0 1 1: CLK2IN/6 + 1 0 0: CLK2IN/8 + 1 0 1: CLK2IN/10 + 1 1 0: CLK2IN/12 + +*/ + #include #include #include diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index b3e721e9f..a8962030b 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -12,8 +12,10 @@ * reverse engineering the BIOS of various machines using it. * * Authors: Tiseno100, + * Miran Grca, * * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. */ /* @@ -35,9 +37,9 @@ Bits 7-4 PCI IRQ for INTD Bits 3-0 PCI IRQ for INTC - Function 0 Register 46: - Bit 7: PMU Trigger(1: By IRQ/0: By SMI) - Bit 6: IRQ SMI Request (1: IRQ 10) (Supposedly 0 according to Phoenix is IRQ 15 but doesn't seem to make sense) + Function 0 Register 46 (corrected by Miran Grca): + Bit 7: IRQ SMI Request (1: IRQ 15, 0: IRQ 10) + Bit 6: PMU Trigger(1: By IRQ/0: By SMI) Function 0 Register 56: Bit 1-0 ISA Bus Speed @@ -45,9 +47,17 @@ 0 1 PCICLK/4 1 0 PCICLK/2 - Function 0 Register A3: + Function 0 Register A2 - non-software SMI# status register + (documented by Miran Grca): + Bit 4: I set, graphics card goes into sleep mode + This register is most likely R/WC + + Function 0 Register A3 (added more details by Miran Grca): Bit 7: Unlock SMM - Bit 6: Software SMI trigger + Bit 6: Software SMI trigger (also doubles as software SMI# status register, + cleared by writing a 0 to it - see the handler used by Phoenix BIOS'es): + If Function 0 Register 46 Bit 6 is set, it raises the specified IRQ (15 + or 10) instead. Function 0 Register A4: Bit 0: Host to PCI Clock (1: 1 by 1/0: 1 by half) @@ -78,6 +88,9 @@ #include <86box/chipset.h> +#define IDE_BIT 0x01 + + #ifdef ENABLE_UMC_8886_LOG int umc_8886_do_log = ENABLE_UMC_8886_LOG; @@ -113,10 +126,10 @@ umc_8886_log(const char *fmt, ...) typedef struct umc_8886_t { - uint8_t pci_conf_sb[2][256]; /* PCI Registers */ + uint8_t max_func, /* Last function number */ + pci_conf_sb[2][256]; /* PCI Registers */ uint16_t sb_id; /* Southbridge Revision */ int has_ide; /* Check if Southbridge Revision is AF or F */ - } umc_8886_t; @@ -138,7 +151,7 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; - switch (func) { + if (func <= dev->max_func) switch (func) { case 0: /* PCI to ISA Bridge */ umc_8886_log("UM8886: dev->regs[%02x] = %02x POST %02x\n", addr, val, inb(0x80)); @@ -171,11 +184,8 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv) break; case 0x46: + /* Bit 6 seems to be the IRQ/SMI# toggle, 1 = IRQ, 0 = SMI#. */ dev->pci_conf_sb[func][addr] = val; - - if (val & 0x40) - picint(1 << ((val & 0x80) ? 15 : 10)); - break; case 0x47: @@ -208,17 +218,25 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv) case 0x70 ... 0x76: case 0x80: case 0x81: case 0x90 ... 0x92: - case 0xa0 ... 0xa2: + case 0xa0 ... 0xa1: dev->pci_conf_sb[func][addr] = val; break; + case 0xa2: + dev->pci_conf_sb[func][addr] &= ~val; + break; + case 0xa3: + /* SMI Provocation (Bit 7 Enable SMM + Bit 6 Software SMI) */ + if (((val & 0xc0) == 0xc0) && !(dev->pci_conf_sb[0][0xa3] & 0x40)) { + if (dev->pci_conf_sb[0][0x46] & 0x40) + picint(1 << ((dev->pci_conf_sb[0][0x46] & 0x80) ? 15 : 10)); + else + smi_line = 1; + dev->pci_conf_sb[0][0xa3] |= 0x04; + } + dev->pci_conf_sb[func][addr] = val; - - /* SMI Provocation (Bit 7 Enable SMM + Bit 6 Software SMI */ - if (((dev->pci_conf_sb[0][0xa3] >> 6) == 3) && !in_smm) - smi_line = 1; - break; case 0xa4: @@ -259,8 +277,12 @@ static uint8_t umc_8886_read(int func, int addr, void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; + uint8_t ret = 0xff; - return dev->pci_conf_sb[func][addr]; + if (func <= dev->max_func) + ret = dev->pci_conf_sb[func][addr]; + + return ret; } @@ -339,6 +361,8 @@ umc_8886_init(const device_t *info) if (HAS_IDE) device_add(&ide_pci_2ch_device); + dev->max_func = (HAS_IDE) ? 1 : 0; + /* Get the Southbridge Revision */ SB_ID = info->local; diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index 136fc03a0..ca544f7ac 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -15,8 +15,10 @@ * around the web. * * Authors: Tiseno100, + * Miran Grca, * * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. */ /* @@ -81,11 +83,9 @@ Register 58h & 59h: DRAM Bank 1 Configuration Register 60: - Bit 5-4: SMRAM Position(Lot's of uncertainty to those bits) - 0 0 A0000 to E0000 - 1 0 A0000 to ????? (Phoenix uses it to no avail) - - Bit 0: SMRAM Local Access Enable + Bit 5: If set and SMRAM is enabled, data cycles go to PCI and code cycles go to DRAM + Bit 0: SMRAM Local Access Enable - if set, SMRAM is also enabled outside SMM + SMRAM appears to always be enabled in SMM, and always set to A0000-BFFFF. */ #include @@ -165,7 +165,17 @@ hb4_smram(hb4_t *dev) { smram_disable_all(); + /* Bit 0, if set, enables SMRAM access outside SMM. SMRAM appears to be always enabled + in SMM, and is always set to A0000-BFFFF. */ smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + + /* Bit 5 seems to set data to go to PCI and code to DRAM. The Samsung SPC7700P-LW uses + this. */ + if (dev->pci_conf[0x60] & 0x20) { + if (dev->pci_conf[0x60] & 0x01) + mem_set_mem_state_smram_ex(0, 0x000a0000, 0x20000, 0x02); + mem_set_mem_state_smram_ex(1, 0x000a0000, 0x20000, 0x02); + } } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index a805dc4ba..cd3cce9b8 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -277,6 +277,7 @@ extern int machine_at_shuttle386sx_init(const machine_t *); extern int machine_at_adi386sx_init(const machine_t *); extern int machine_at_cmdsl386sx16_init(const machine_t *); extern int machine_at_cmdsl386sx25_init(const machine_t *); +extern int machine_at_dataexpert386sx_init(const machine_t *); extern int machine_at_spc6033p_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); extern int machine_at_arb1374_init(const machine_t *); @@ -288,7 +289,7 @@ extern int machine_at_prox1332_init(const machine_t *); extern int machine_at_awardsx_init(const machine_t *); -extern int machine_at_pc916sx_init(const machine_t *); +extern int machine_at_pc916sx_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *at_ama932j_get_device(void); @@ -366,6 +367,7 @@ extern int machine_at_sbc_490_init(const machine_t *); extern int machine_at_tf_486_init(const machine_t *); extern int machine_at_itoxstar_init(const machine_t *); +extern int machine_at_arb1423c_init(const machine_t *); extern int machine_at_arb1479_init(const machine_t *); extern int machine_at_pcm9340_init(const machine_t *); extern int machine_at_pcm5330_init(const machine_t *); @@ -374,6 +376,8 @@ extern int machine_at_ecs486_init(const machine_t *); extern int machine_at_hot433_init(const machine_t *); extern int machine_at_atc1415_init(const machine_t *); extern int machine_at_actionpc2600_init(const machine_t *); +extern int machine_at_m919_init(const machine_t *); +extern int machine_at_spc7700p_lw_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *at_acera1g_get_device(void); diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index b4d5b4ed6..c2f9a433d 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -590,14 +590,17 @@ machine_at_cmdsl386sx16_init(const machine_t *model) static void -machine_at_scamp_common_init(const machine_t *model) +machine_at_scamp_common_init(const machine_t *model, int is_ps2) { machine_at_common_ide_init(model); - device_add(&keyboard_ps2_ami_device); + if (is_ps2) + device_add(&keyboard_ps2_ami_device); + else + device_add(&keyboard_at_ami_device); if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); device_add(&vlsi_scamp_device); } @@ -624,7 +627,24 @@ machine_at_cmdsl386sx25_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&gd5402_onboard_device); - machine_at_scamp_common_init(model); + machine_at_scamp_common_init(model, 1); + + return ret; +} + + +int +machine_at_dataexpert386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/dataexpert386sx/5e9f20e5ef967717086346.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scamp_common_init(model, 0); return ret; } @@ -651,7 +671,7 @@ machine_at_spc6033p_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&ati28800k_spc6033p_device); - machine_at_scamp_common_init(model); + machine_at_scamp_common_init(model, 1); return ret; } diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index cf27a999d..2068b3c88 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -412,7 +412,7 @@ machine_at_acera1g_init(const machine_t *model) return ret; machine_at_common_init(model); - device_add(&ali1429_device); + device_add(&ali1429g_device); if (gfxcard == VID_INTERNAL) device_add(&gd5428_onboard_device); @@ -482,11 +482,14 @@ machine_at_decpc_lpv_init(const machine_t *model) } static void -machine_at_ali1429_common_init(const machine_t *model) +machine_at_ali1429_common_init(const machine_t *model, int is_green) { machine_at_common_ide_init(model); - device_add(&ali1429_device); + if (is_green) + device_add(&ali1429g_device); + else + device_add(&ali1429_device); device_add(&keyboard_at_ami_device); @@ -506,7 +509,7 @@ machine_at_ali1429_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_ali1429_common_init(model); + machine_at_ali1429_common_init(model, 0); return ret; } @@ -523,7 +526,7 @@ machine_at_winbios1429_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_ali1429_common_init(model); + machine_at_ali1429_common_init(model, 1); return ret; } @@ -1450,6 +1453,34 @@ machine_at_itoxstar_init(const machine_t *model) } +int +machine_at_arb1423c_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/arb1423c/A1423C.v12", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 1, 0, 0, 0); + pci_register_slot(0x1E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x1D, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&w83977f_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_consumer2_device); + device_add(&winbond_flash_w29c020_device); + + return ret; +} + + int machine_at_arb1479_init(const machine_t *model) { @@ -1552,10 +1583,10 @@ machine_at_ecs486_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0f, PCI_CARD_IDE, 0, 0, 0, 0); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0d, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); device_add(&umc_hb4_device); device_add(&umc_8886f_device); @@ -1584,10 +1615,10 @@ machine_at_hot433_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0d, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0f, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); device_add(&umc_hb4_device); device_add(&umc_8886af_device); @@ -1615,7 +1646,7 @@ machine_at_atc1415_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); @@ -1646,10 +1677,10 @@ machine_at_actionpc2600_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0c, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0d, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0e, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0f, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); device_add(&umc_hb4_device); device_add(&umc_8886af_device); @@ -1659,3 +1690,63 @@ machine_at_actionpc2600_init(const machine_t *model) return ret; } + + +int +machine_at_m919_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m919/9190914s.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_spc7700p_lw_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/spc7700p-lw/77LW13FH.P24", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b458b5a5f..77c5fbea4 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -99,11 +99,7 @@ const machine_type_t machine_types[] = { Write Input Port, same as on AMIKey-3. Machines to remove: - - Hedaka HED-919; - - A-Trend ATC-1415; - - ECS Elite UM8810PAIO; - - Shuttle HOT-433A; - - Azza 5IVG (if a more interesting machine with Prime3C is found). + - Hedaka HED-919. */ @@ -276,6 +272,10 @@ const machine_t machines[] = { the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any proprietary commands. */ { "[SCAMP] Commodore SL386SX-25", "cmdsl386sx25", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 1024, 8192, 512, 127, machine_at_cmdsl386sx25_init, at_cmdsl386sx25_get_device }, + /* The closest BIOS string I find to this one's, differs only in one part, + and ends in -8, so I'm going to assume that this, too, has an AMI '8' + (AMI Keyboard BIOS Plus) KBC firmware. */ + { "[SCAMP] DataExpert 386SX", "dataexpert386sx", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 10000000, 25000000, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_dataexpert386sx_init, NULL }, /* Has IBM PS/2 Type 1 KBC firmware. */ { "[SCAMP] Samsung SPC-6033P", "spc6033p", MACHINE_TYPE_386SX, CPU_PKG_386SX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE | MACHINE_VIDEO, 2048, 12288, 2048, 127, machine_at_spc6033p_init, at_spc6033p_get_device }, /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a @@ -297,6 +297,7 @@ const machine_t machines[] = { { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_acc386_init, NULL }, /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT, 1024, 16384, 1024, 127, machine_at_ecs386_init, NULL }, + /* Has IBM AT KBC firmware. */ { "[C&T 386] Samsung SPC-6000A", "spc6000a", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_spc6000a_init, NULL }, /* Uses Compaq KBC firmware. */ { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, CPU_PKG_386DX, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_IDE | MACHINE_VIDEO, 1024, 14336, 1024, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, @@ -366,7 +367,7 @@ const machine_t machines[] = { { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 4096, 36864, 1024, 127, machine_at_acera1g_init, at_acera1g_get_device }, /* There are two similar BIOS strings with -H, and one with -U, so I'm going to give it an AMIKey H KBC firmware. */ - { "[ALi M1429G] AMI WinBIOS 486", "win486", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, + { "[ALi M1429G] Kaimei 486", "win486", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 32768, 1024, 127, machine_at_winbios1429_init, NULL }, /* Uses an Intel KBC with Phoenix MultiKey KBC firmware. */ { "[SiS 461] DEC DECpc LPV", "decpc_lpv", MACHINE_TYPE_486_S2, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_AT | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 1024, 32768, 1024, 127, machine_at_decpc_lpv_init, NULL }, /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ @@ -446,13 +447,18 @@ const machine_t machines[] = { of type 'H'. */ { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, /* This has the UMC 88xx on-chip KBC. */ - { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, + { "[UMC 888x] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ - { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, + { "[UMC 888x] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, /* Has AMIKey Z(!) KBC firmware. */ - { "[UMC 8881] Epson Action PC 2600", "actionpc2600", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_actionpc2600_init, NULL }, + { "[UMC 888x] Epson Action PC 2600", "actionpc2600", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_actionpc2600_init, NULL }, + /* This has the UMC 88xx on-chip KBC. All the copies of the BIOS string I can find, end in + in -H, so the UMC on-chip KBC likely emulates the AMI 'H' KBC firmware. */ + { "[UMC 888x] PC Chips M919", "m919", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_m919_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. Uses a mysterious I/O port C05. */ + { "[UMC 888x] Samsung SPC7700P-LW", "spc7700p-lw", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_spc7700p_lw_init, NULL }, /* This has a Holtek KBC. */ - { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, + { "[UMC 888x] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ { "[VIA VT82C496G] DFI G486VPA", "g486vpa", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_g486vpa_init, NULL }, /* Has a VIA VT82C42N KBC. */ @@ -463,6 +469,9 @@ const machine_t machines[] = { /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { "[STPC Client] ITOX STAR", "itoxstar", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 75000000, 0, 0, 1.0, 1.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 255, machine_at_itoxstar_init, NULL }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { "[STPC Consumer-II] Acrosser AR-B1423C", "arb1423c", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 163840, 8192, 255, machine_at_arb1423c_init, NULL }, /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { "[STPC Consumer-II] Acrosser AR-B1479", "arb1479", MACHINE_TYPE_486_MISC, CPU_PKG_STPC, 0, 66666667, 66666667, 0, 0, 2.0, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 32768, 163840, 8192, 255, machine_at_arb1479_init, NULL }, From ccdf583b26f82c8b6a865283a4265b9534097641 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 24 Aug 2021 21:11:47 +0200 Subject: [PATCH 063/140] A slight AT NVR code clean-up. --- src/nvr_at.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/nvr_at.c b/src/nvr_at.c index ff1c6fcb0..8be4aa7f8 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -559,6 +559,26 @@ timer_tick(nvr_t *nvr) } +static void +nvr_reg_common_write(uint16_t reg, uint8_t val, nvr_t *nvr, local_t *local) +{ + if ((reg == 0x2c) && (local->flags & FLAG_LS_HACK)) + nvr->new = 0; + if ((reg == 0x52) && (local->flags & FLAG_APOLLO_HACK)) + nvr->new = 0; + if ((reg >= 0x38) && (reg <= 0x3f) && local->wp[0]) + return; + if ((reg >= 0xb8) && (reg <= 0xbf) && local->wp[1]) + return; + if (local->lock[reg]) + return; + if (nvr->regs[reg] != val) { + nvr->regs[reg] = val; + nvr_dosave = 1; + } +} + + /* This must be exposed because ACPI uses it. */ void nvr_reg_write(uint16_t reg, uint8_t val, void *priv) @@ -604,28 +624,17 @@ nvr_reg_write(uint16_t reg, uint8_t val, void *priv) nvr->regs[0x2f] = checksum & 0xff; break; } - /*FALLTHROUGH*/ + nvr_reg_common_write(reg, val, nvr, local); + break; case 0x32: if ((reg == 0x32) && (local->cent == RTC_CENTURY_VIA) && local->wp_32) break; - /* FALLTHROUGH */ + nvr_reg_common_write(reg, val, nvr, local); + break; default: /* non-RTC registers are just NVRAM */ - if ((reg == 0x2c) && (local->flags & FLAG_LS_HACK)) - nvr->new = 0; - if ((reg == 0x52) && (local->flags & FLAG_APOLLO_HACK)) - nvr->new = 0; - if ((reg >= 0x38) && (reg <= 0x3f) && local->wp[0]) - break; - if ((reg >= 0xb8) && (reg <= 0xbf) && local->wp[1]) - break; - if (local->lock[reg]) - break; - if (nvr->regs[reg] != val) { - nvr->regs[reg] = val; - nvr_dosave = 1; - } + nvr_reg_common_write(reg, val, nvr, local); break; } From 03253ec93c594960871483815b2baa3372dd58b7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Sep 2021 16:40:07 +0200 Subject: [PATCH 064/140] Trident changes to make merging easier. --- src/video/vid_tgui9440.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index fa522fd43..ddceff618 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -2870,7 +2870,7 @@ static void *tgui_init(const device_t *info) tgui->card = pci_add_card(PCI_ADD_VIDEO | PCI_ADD_STRICT, tgui_pci_read, tgui_pci_write, tgui); } - tgui->pci_regs[PCI_REG_COMMAND] = 3; + tgui->pci_regs[PCI_REG_COMMAND] = 7; if (tgui->has_bios) { tgui->pci_regs[0x30] = 0x00; @@ -2878,8 +2878,8 @@ static void *tgui_init(const device_t *info) tgui->pci_regs[0x33] = 0x00; } - if (tgui->type >= TGUI_9440) - svga->packed_chain4 = 1; + if (tgui->type >= TGUI_9440) + svga->packed_chain4 = 1; if (tgui->type >= TGUI_9660) { tgui->i2c = i2c_gpio_init("ddc_tgui"); From 81db8ea205a72f0b3d110ba99b5fcf89851315b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Sep 2021 16:41:11 +0200 Subject: [PATCH 065/140] I have to do this, apparently. --- src/video/vid_tgui9440.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index ddceff618..642991b58 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -2881,11 +2881,6 @@ static void *tgui_init(const device_t *info) if (tgui->type >= TGUI_9440) svga->packed_chain4 = 1; - if (tgui->type >= TGUI_9660) { - tgui->i2c = i2c_gpio_init("ddc_tgui"); - tgui->ddc = ddc_init(i2c_gpio_get_bus(tgui->i2c)); - } - return tgui; } From b75d9a20012cb6ce24c101eb876aba1d78cc7a98 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Sep 2021 16:42:39 +0200 Subject: [PATCH 066/140] And back. --- src/video/vid_tgui9440.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index dfce72e06..e067d7a4b 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -3005,7 +3005,7 @@ static void *tgui_init(const device_t *info) tgui->card = pci_add_card(PCI_ADD_VIDEO | PCI_ADD_STRICT, tgui_pci_read, tgui_pci_write, tgui); } - tgui->pci_regs[PCI_REG_COMMAND] = 7; + tgui->pci_regs[PCI_REG_COMMAND] = 7; if (tgui->has_bios) { tgui->pci_regs[0x30] = 0x00; @@ -3013,8 +3013,13 @@ static void *tgui_init(const device_t *info) tgui->pci_regs[0x33] = 0x00; } - if (tgui->type >= TGUI_9440) - svga->packed_chain4 = 1; + if (tgui->type >= TGUI_9440) + svga->packed_chain4 = 1; + + if (tgui->type >= TGUI_9660) { + tgui->i2c = i2c_gpio_init("ddc_tgui"); + tgui->ddc = ddc_init(i2c_gpio_get_bus(tgui->i2c)); + } return tgui; } From 901c2741192e2dc2d0e437d50a740e40bd4c1c73 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 8 Sep 2021 00:08:10 +0200 Subject: [PATCH 067/140] Committed three files to make the merger possible. --- src/chipset/CMakeLists.txt | 16 +++++++++------- src/video/CMakeLists.txt | 6 +++--- src/win/Makefile.mingw | 21 +++++++-------------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 4e46e0db4..3ed588afd 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,13 +13,15 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(chipset OBJECT acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c - ali1621.c ali6117.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c - intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c - sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c - via_pipc.c vl82c480.c wd76c10.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 + umc_8886.c umc_8890.c umc_hb4.c + via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c + gc100.c stpc.c + via_apollo.c via_pipc.c wd76c10.c + vl82c480.c) if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 4b5f029b9..50572dbd8 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -20,9 +20,9 @@ add_library(vid OBJECT video.c vid_table.c vid_cga.c vid_cga_comp.c vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c - vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c - vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c - vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c + vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c + vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c + vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 913549911..e96f00a06 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -598,20 +598,13 @@ 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 \ - contaq_82c59x.o \ - cs4031.o cs8230.o \ - ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ - gc100.o headland.o \ - intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ - neat.o \ - opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ - scamp.o scat.o \ - stpc.o \ - wd76c10.o vl82c480.o \ - umc_8886.o umc_hb4.o \ - via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ - sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.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 \ + sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o sis_5598.o stpc.o opti283.o opti291.o \ + umc_8886.o umc_8890.o umc_hb4.o \ + via_apollo.o via_pipc.o wd76c10.o vl82c480.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ From d5f656e86627823cfee68c0370e8b0799884ca23 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 8 Sep 2021 00:10:13 +0200 Subject: [PATCH 068/140] And back. --- src/chipset/CMakeLists.txt | 16 +++++++--------- src/video/CMakeLists.txt | 4 ++-- src/win/Makefile.mingw | 24 +++++++++++++++--------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 3ed588afd..770b54006 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -13,15 +13,13 @@ # Copyright 2020,2021 David Hrdlička. # -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 - umc_8886.c umc_8890.c umc_hb4.c - via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c - gc100.c stpc.c - via_apollo.c via_pipc.c wd76c10.c - vl82c480.c) +add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c + ali1621.c ali6117.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c + intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c + sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c + via_pipc.c vl82c480.c wd76c10.c) if(I450KX) target_sources(chipset PRIVATE intel_i450kx.c) diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 50572dbd8..c23e42917 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -20,8 +20,8 @@ add_library(vid OBJECT video.c vid_table.c vid_cga.c vid_cga_comp.c vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c - vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c - vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c + vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c + vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index a6e2da67f..175f2a6d7 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -598,13 +598,20 @@ CPUOBJ := $(DYNARECOBJ) \ 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \ x86seg.o x87.o x87_timings.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 \ - sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o sis_5598.o stpc.o opti283.o opti291.o \ - umc_8886.o umc_8890.o umc_hb4.o \ - via_apollo.o via_pipc.o wd76c10.o vl82c480.o +CHIPSETOBJ := 82c100.o acc2168.o \ + contaq_82c59x.o \ + cs4031.o cs8230.o \ + ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ + gc100.o headland.o \ + intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ + neat.o \ + opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ + scamp.o scat.o \ + stpc.o \ + wd76c10.o vl82c480.o \ + umc_8886.o umc_hb4.o \ + via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ + sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ @@ -613,7 +620,7 @@ MCHOBJ := machine.o machine_table.o \ m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ m_amstrad.o m_europc.o \ - m_xt_olivetti.o m_tandy.o m_v86p.o \ + m_xt_olivetti.o m_tandy.o \ m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o m_ps1_hdc.o \ @@ -765,7 +772,6 @@ VIDOBJ := video.o \ vid_paradise.o \ vid_rtg310x.o \ vid_ti_cf62011.o \ - vid_f82c425.o \ vid_tvga.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ vid_att20c49x_ramdac.o \ From 372b59524be903ba5cd48bd3f7a86e96cc1941a9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 8 Sep 2021 00:51:57 +0200 Subject: [PATCH 069/140] Added m_v86p.o to the makefile. --- src/win/Makefile.mingw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 175f2a6d7..793be3b17 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -620,7 +620,7 @@ MCHOBJ := machine.o machine_table.o \ m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ m_amstrad.o m_europc.o \ - m_xt_olivetti.o m_tandy.o \ + m_xt_olivetti.o m_tandy.o m_v86p.o \ m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o m_ps1_hdc.o \ From 22481af97af49d2edacd583579594dd0f8d30963 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 8 Sep 2021 01:51:47 +0200 Subject: [PATCH 070/140] Makefile fix. --- src/win/Makefile.mingw | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 793be3b17..ba4ecef21 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -772,6 +772,7 @@ VIDOBJ := video.o \ vid_paradise.o \ vid_rtg310x.o \ vid_ti_cf62011.o \ + vid_f82c425.o \ vid_tvga.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ vid_att20c49x_ramdac.o \ From 827fc28deca375aa21fe8f6a02e4f3597edc6701 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Sep 2021 22:26:17 +0200 Subject: [PATCH 071/140] Minor fixes in machine_table.c. --- src/machine/machine_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 610eb137c..d58e60296 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -581,7 +581,7 @@ const machine_t machines[] = { /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ - { "[i430FX] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_gw2katx_init, NULL }, + { "[i430FX] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_gw2katx_init, NULL }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ @@ -589,7 +589,7 @@ const machine_t machines[] = { /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ - { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, at_mrthor_get_device }, + { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mrthor_init, at_mrthor_get_device }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ @@ -748,7 +748,7 @@ const machine_t machines[] = { /* Socket 8 machines */ /* 450KX */ #if defined(DEV_BRANCH) && defined(USE_I450KX) - /* This has an AMIKey, which is an updated version of type 'F'. */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i450KX] ASUS P/I-P6RP4", "p6rp4", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p6rp4_init, NULL }, #endif From d2f3720a23789cd2491f8659fad501bb59596c71 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Sep 2021 22:29:17 +0200 Subject: [PATCH 072/140] Manually merged a change to machine_table.c. --- src/machine/machine_table.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d58e60296..81b994d7c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -118,6 +118,7 @@ const machine_t machines[] = { { "[8088] Eagle PC Spirit", "pcspirit", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pcspirit_init, NULL }, { "[8088] Generic XT clone", "genxt", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_genxt_init, NULL }, { "[8088] Juko ST", "jukopc", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] Multitech PC-500", "multitech_pc500", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_multitechpc500_init, NULL }, { "[8088] Multitech PC-700", "pc700", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 128, 640, 64, 0, machine_xt_pc700_init, NULL }, { "[8088] NCR PC4i", "pc4i", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 0, 0, 0, 0, 0, 0, MACHINE_PC, 256, 640, 256, 0, machine_xt_pc4i_init, NULL }, { "[8088] Olivetti M19", "m19", MACHINE_TYPE_8088, CPU_PKG_8088, 0, 4772728, 7159092, 0, 0, 0, 0, MACHINE_PC | MACHINE_VIDEO_FIXED, 256, 640, 256, 0, machine_xt_m19_init, m19_get_device }, From dbdf07aa96830ac0eb76aa7273bf1c05d2db4fb0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Sep 2021 22:33:39 +0200 Subject: [PATCH 073/140] Two files to resolve conflicts. --- src/CMakeLists.txt | 6 +++--- src/win/Makefile.mingw | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bb131bd2..a3cbc2e76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,9 +14,9 @@ # # WIN32 marks us as a GUI app on Windows -add_executable(86Box WIN32 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c - dma.c ddma.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c mca.c usb.c - device.c nvr.c nvr_at.c nvr_ps2.c) +add_executable(86Box WIN32 86box.c config.c random.c timer.c io.c acpi.c apm.c + dma.c ddma.c nmi.c pic.c pit.c port_92.c ppi.c pci.c mca.c usb.c + device.c nvr.c nvr_at.c nvr_ps2.c thread.c) if(NEW_DYNAREC) add_compile_definitions(USE_NEW_DYNAREC) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index ba4ecef21..29d0c3456 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -585,8 +585,14 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ +ifeq ($(PTHREAD), y) +MAINOBJ := 86box.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ + usb.o device.o nvr.o nvr_at.o nvr_ps2.o thread.o \ + $(VNCOBJ) +else +MAINOBJ := 86box.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ usb.o device.o nvr.o nvr_at.o nvr_ps2.o \ $(VNCOBJ) From b0367133d6c987286c2fcf4b50fa24d7f91389ca Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Sep 2021 22:36:21 +0200 Subject: [PATCH 074/140] And back. --- src/CMakeLists.txt | 4 ++-- src/win/Makefile.mingw | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a3cbc2e76..2bfca1c94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,8 +14,8 @@ # # WIN32 marks us as a GUI app on Windows -add_executable(86Box WIN32 86box.c config.c random.c timer.c io.c acpi.c apm.c - dma.c ddma.c nmi.c pic.c pit.c port_92.c ppi.c pci.c mca.c usb.c +add_executable(86Box WIN32 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c + dma.c ddma.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c mca.c usb.c device.c nvr.c nvr_at.c nvr_ps2.c thread.c) if(NEW_DYNAREC) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index d168796ec..90f7ab19e 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -590,13 +590,13 @@ CXXFLAGS := $(CFLAGS) # Create the (final) list of objects to build. # ######################################################################### ifeq ($(PTHREAD), y) -MAINOBJ := 86box.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ +MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ usb.o device.o nvr.o nvr_at.o nvr_ps2.o thread.o \ $(VNCOBJ) else -MAINOBJ := 86box.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ +MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ usb.o device.o nvr.o nvr_at.o nvr_ps2.o \ $(VNCOBJ) endif From 89f1583a348a767e5dfe5ed71d12c846cdd1d163 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 17 Sep 2021 02:52:44 +0200 Subject: [PATCH 075/140] Fixed UMC 888x shadow RAM. --- src/chipset/umc_hb4.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index ca544f7ac..b3d5cb0dc 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -139,20 +139,22 @@ typedef struct hb4_t void hb4_shadow(hb4_t *dev) { + int state, i; + mem_set_mem_state_both(0xe0000, 0x20000, ((dev->pci_conf[0x55] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL)); if (dev->pci_conf[0x54] & 1) { - if (dev->pci_conf[0x54] & 2) - mem_set_mem_state_both(0xc0000, 0x8000, MEM_READ_INTERNAL | ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY :MEM_WRITE_INTERNAL)); - else - mem_set_mem_state_both(0xc0000, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + state = (dev->pci_conf[0x54] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - for (int i = 0; i < 5; i++) { - if ((dev->pci_conf[0x54] >> i) & 4) - mem_set_mem_state_both(0xc8000 + (i << 14), 0x8000, MEM_READ_INTERNAL | ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY :MEM_WRITE_INTERNAL)); - else - mem_set_mem_state_both(0xc8000 + (i << 14), 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state_both(0xc0000, 0x8000, state); + + for (i = 0; i < 6; i++) { + state = (dev->pci_conf[0x54] & (1 << (i + 2))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; + + mem_set_mem_state_both(0xc8000 + (i << 4), 0x4000, state); } } @@ -265,7 +267,8 @@ hb4_reset(void *priv) dev->pci_conf[0x5d] = 0x20; dev->pci_conf[0x5f] = 0xff; - hb4_shadow(dev); + hb4_write(0, 0x54, 0x00, dev); + hb4_write(0, 0x55, 0x00, dev); hb4_write(0, 0x60, 0x20, dev); } From 626e8e58bb6ffd24279d0e5e2689f54405d2ae42 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 17 Sep 2021 02:54:19 +0200 Subject: [PATCH 076/140] Implemented a PIIX register written to by the ZAPPA that is officially reserved on PIIX (but otherwise exists on PIIX3). --- src/chipset/intel_piix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index a694da235..aa91c2fd5 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -528,6 +528,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0xab: if (dev->type == 3) fregs[addr] &= (val & 0x01); + else if (dev->type < 3) + fregs[addr] = val; break; case 0xb0: if (dev->type == 4) From b8a2fdfd0acd844941559782814bff5e9a81187c Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 17 Sep 2021 02:55:43 +0200 Subject: [PATCH 077/140] KBC reset is now hard reset. --- src/cpu/cpu.h | 1 + src/cpu/x86.c | 40 ++++++++++++++++++++++---- src/device/keyboard_at.c | 62 ++++++++++++++++++++++++++++------------ 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b28934951..68a053b6f 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -656,6 +656,7 @@ extern void resetx86(void); extern void refreshread(void); extern void resetreadlookup(void); extern void softresetx86(void); +extern void hardresetx86(void); extern void x86_int(int num); extern void x86_int_sw(int num); extern int x86_int_sw_rm(int num); diff --git a/src/cpu/x86.c b/src/cpu/x86.c index e652c5d27..c16939559 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -26,6 +26,8 @@ #include "cpu.h" #include "x86.h" #include <86box/machine.h> +#include <86box/device.h> +#include <86box/dma.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/rom.h> @@ -239,7 +241,7 @@ reset_common(int hard) leave_smm(); /* Needed for the ALi M1533. */ - if (soft_reset_pci && !hard) + if (is486 && (hard || soft_reset_pci)) pci_reset(); use32 = 0; @@ -275,13 +277,13 @@ reset_common(int hard) if (is386 || hard) EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; - if (hard) { + /* if (hard) { makeznptable(); resetreadlookup(); makemod1table(); cpu_set_edx(); mmu_perm = 4; - } + } */ x86seg_reset(); #ifdef USE_DYNAREC if (hard) @@ -299,8 +301,9 @@ reset_common(int hard) smi_block = 0; if (hard) { - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - ppi_reset(); + if (is486) + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + // ppi_reset(); } in_sys = 0; @@ -320,6 +323,15 @@ void resetx86(void) { reset_common(1); +/* ---- */ + makeznptable(); + resetreadlookup(); + makemod1table(); + cpu_set_edx(); + mmu_perm = 4; + + ppi_reset(); +/* ---- */ soft_reset_mask = 0; } @@ -334,3 +346,21 @@ softresetx86(void) reset_common(0); } + + +/* Actual hard reset. */ +void +hardresetx86(void) +{ + dma_reset(); + device_reset_all(); + + cpu_alt_reset = 0; + + mem_a20_alt = 0; + mem_a20_recalc(); + + flushmmucache(); + + resetx86(); +} diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 5431b9236..c64f8b87f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1181,6 +1181,8 @@ static void write_output(atkbd_t *dev, uint8_t val) { uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t old = dev->p2; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); if (!(dev->flags & KBC_FLAG_PS2)) @@ -1189,36 +1191,43 @@ write_output(atkbd_t *dev, uint8_t val) dev->kbd_inhibit = (val & 0x40); dev->mouse_inhibit = (val & 0x08); - if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + /* IRQ 12 */ + if ((old ^ val) & 0x20) { if (val & 0x20) { kbd_log("ATkbc: write_output(): IRQ 12\n"); picint(1 << 12); } else picintc(1 << 12); } - if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + + /* IRQ 1 */ + if ((old ^ val) & 0x10) { if (val & 0x10) { kbd_log("ATkbc: write_output(): IRQ 1\n"); picint(1 << 1); } else picintc(1 << 1); } - if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + + /* A20 enable change */ + if ((old ^ val) & 0x02) { mem_a20_key = val & 0x02; mem_a20_recalc(); flushmmucache(); } - if ((dev->p2 ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { + + /* Do this here to avoid an infinite reset loop. */ + dev->p2 = val; + + /* 0 holds the CPU in the RESET state, 1 releases it. To simply this, + we just do everything on release. */ + if ((val & 0x01) && !(old & 0x01)) { + if (val & 0x01) { /* Pin 0 selected. */ pclog("write_output(): Pulse reset!\n"); - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; + hardresetx86(); /*Pulse reset!*/ } } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->p2 = val; } @@ -2315,8 +2324,8 @@ write64_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - // kbc_transmit(dev, 'H'); - kbc_transmit(dev, 'Z'); + kbc_transmit(dev, 'H'); + // kbc_transmit(dev, 'Z'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ @@ -2928,13 +2937,14 @@ kbd_reset(void *priv) { atkbd_t *dev = (atkbd_t *)priv; int i; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t kbc_ven; - dev->status = STAT_UNLOCKED; - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; - write_output(dev, 0xcf); + if (dev == NULL) + return; + + kbc_ven = dev->flags & KBC_VEN_MASK; + + dev->status &= ~(STAT_IFULL | STAT_OFULL | STAT_CD); dev->last_irq = 0; dev->secr_phase = 0; dev->kbd_in = 0; @@ -2973,6 +2983,20 @@ kbd_reset(void *priv) } +static void +kbd_power_on(atkbd_t *dev) +{ + kbd_reset(dev); + + dev->status = STAT_UNLOCKED; + /* Write the value here first, so that we don't hit a pulse reset. */ + dev->p2 = 0xcf; + write_output(dev, 0xcf); + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; +} + + /* Reset the AT keyboard - this is needed for the PCI TRC and is done until a better solution is found. */ void @@ -3064,7 +3088,7 @@ kbd_init(const device_t *info) break; } - kbd_reset(dev); + kbd_power_on(dev); /* We need this, sadly. */ SavedKbd = dev; From 2e3c2602f74f5ae2938af8c1c98f4997f01baef8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 21 Sep 2021 13:02:22 +0200 Subject: [PATCH 078/140] Removed the M6117 flag from the CPU and Machine CMakeLists.txt files. --- src/cpu/CMakeLists.txt | 4 ---- src/machine/CMakeLists.txt | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index dd91a5ec1..ab27b77c0 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -24,10 +24,6 @@ if(CYRIX_6X86) target_compile_definitions(cpu PRIVATE USE_CYRIX_6X86) endif() -if(M6117) - target_compile_definitions(cpu PRIVATE USE_M6117) -endif() - if(DYNAREC) add_library(cgt OBJECT codegen_timing_486.c codegen_timing_686.c codegen_timing_common.c codegen_timing_k6.c diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 54c3c3646..6643566ee 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -47,8 +47,4 @@ endif() if(M154X) target_compile_definitions(mch PRIVATE USE_M154X) -endif() - -if(M6117) - target_compile_definitions(mch PRIVATE USE_M6117) endif() \ No newline at end of file From 5ad606a8f27b6af8cd99f9eafb1363c40f245fd1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 25 Sep 2021 15:30:06 +0200 Subject: [PATCH 079/140] UMC HB4 shadow RAM overhaul and SMRAM fixes, slight changes to SiS 85c4xx, a fix for SiS 85c50x, fixed SMBASE on 486 (it should *NOT* zero the most significant 8 bits!), various improvements to mem.c (eg. mem_invalidate_range() is now faster), fixed resetting PCI on soft reset, and made the KBC soft reset again. --- src/chipset/sis_85c4xx.c | 244 +++++++++++++++------------------------ src/chipset/sis_85c50x.c | 2 +- src/chipset/umc_8886.c | 6 + src/chipset/umc_hb4.c | 166 +++++++++++++++++++++----- src/cpu/386_common.c | 2 +- src/cpu/x86.c | 7 +- src/device/keyboard_at.c | 54 ++++----- src/mem/mem.c | 75 +++++------- 8 files changed, 304 insertions(+), 252 deletions(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 0a2bf34af..4ca0c76d7 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -22,6 +22,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" +#include "x86.h" #include <86box/timer.h> #include <86box/io.h> #include <86box/device.h> @@ -39,6 +40,7 @@ typedef struct reg_base, reg_last, reg_00, is_471, regs[39], scratch[2]; + uint32_t mem_state[8]; smram_t *smram; port_92_t *port_92; } sis_85c4xx_t; @@ -47,7 +49,7 @@ typedef struct static void sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) { - uint32_t base; + uint32_t base, n = 0; uint32_t i, shflags = 0; uint32_t readext, writeext; uint8_t romcs = 0xc0, cur_romcs; @@ -73,12 +75,25 @@ sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : readext; shflags |= (dev->regs[0x02] & 0x40) ? writeext : MEM_WRITE_INTERNAL; - mem_set_mem_state(base, 0x8000, shflags); - } else - mem_set_mem_state(base, 0x8000, readext | writeext); + if (dev->mem_state[i] != shflags) { + n++; + mem_set_mem_state(base, 0x8000, shflags); + if ((base >= 0xf0000) && (dev->mem_state[i] & MEM_READ_INTERNAL) && !(shflags & MEM_READ_INTERNAL)) + mem_invalidate_range(base, base + 0x7fff); + dev->mem_state[i] = shflags; + } + } else { + shflags = readext | writeext; + if (dev->mem_state[i] != shflags) { + n++; + mem_set_mem_state(base, 0x8000, shflags); + dev->mem_state[i] = shflags; + } + } } - flushmmucache_nopc(); + if (n > 0) + flushmmucache_nopc(); } @@ -141,7 +156,8 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) case 0x02: case 0x03: case 0x08: - sis_85c4xx_recalcmapping(dev); + if (valxor) + sis_85c4xx_recalcmapping(dev); break; case 0x0b: @@ -237,6 +253,69 @@ sis_85c4xx_in(uint16_t port, void *priv) } +static void +sis_85c4xx_reset(void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + int mem_size_mb = mem_size >> 10; + static uint8_t ram_4xx[64] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, 0x04, 0x04, 0x05, 0x05, 0x0b, 0x0b, 0x0b, 0x0b, + 0x13, 0x21, 0x06, 0x06, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }; + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + if (cpu_s->rspeed < 25000000) + dev->regs[0x08] = 0x80; + + if (dev->is_471) { + dev->regs[0x09] = 0x40; + if (mem_size_mb >= 64) { + if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[0x09] |= 0x22; + else + dev->regs[0x09] |= 0x24; + } else + dev->regs[0x09] |= ram_471[mem_size_mb]; + + dev->regs[0x11] = 0x09; + dev->regs[0x12] = 0xff; + dev->regs[0x1f] = 0x20; /* Video access enabled. */ + dev->regs[0x23] = 0xf0; + dev->regs[0x26] = 0x01; + + smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x00010000, 0, 1); + + port_92_remove(dev->port_92); + + mem_remap_top(256); + soft_reset_mask = 0; + } else { + /* Bits 6 and 7 must be clear on the SiS 40x. */ + if (dev->reg_base == 0x60) + dev->reg_00 = 0x24; + + if (mem_size_mb == 64) + dev->regs[0x00] = 0x1f; + else if (mem_size_mb < 64) + dev->regs[0x00] = ram_4xx[mem_size_mb]; + + dev->regs[0x11] = 0x01; + } + + dev->scratch[0] = dev->scratch[1] = 0xff; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + sis_85c4xx_recalcmapping(dev); +} + + static void sis_85c4xx_close(void *priv) { @@ -252,8 +331,6 @@ sis_85c4xx_close(void *priv) static void * sis_85c4xx_init(const device_t *info) { - int mem_size_mb; - sis_85c4xx_t *dev = (sis_85c4xx_t *) malloc(sizeof(sis_85c4xx_t)); memset(dev, 0, sizeof(sis_85c4xx_t)); @@ -261,161 +338,22 @@ sis_85c4xx_init(const device_t *info) dev->reg_base = info->local & 0xff; - mem_size_mb = mem_size >> 10; - - if (cpu_s->rspeed < 25000000) - dev->regs[0x08] = 0x80; - if (dev->is_471) { dev->reg_last = dev->reg_base + 0x76; - dev->regs[0x09] = 0x40; - switch (mem_size_mb) { - case 0: case 1: - dev->regs[0x09] |= 0x00; - break; - case 2: case 3: - dev->regs[0x09] |= 0x01; - break; - case 4: - dev->regs[0x09] |= 0x02; - break; - case 5: - dev->regs[0x09] |= 0x20; - break; - case 6: case 7: - dev->regs[0x09] |= 0x09; - break; - case 8: case 9: - dev->regs[0x09] |= 0x04; - break; - case 10: case 11: - dev->regs[0x09] |= 0x05; - break; - case 12: case 13: case 14: case 15: - dev->regs[0x09] |= 0x0b; - break; - case 16: - dev->regs[0x09] |= 0x13; - break; - case 17: - dev->regs[0x09] |= 0x21; - break; - case 18: case 19: - dev->regs[0x09] |= 0x06; - break; - case 20: case 21: case 22: case 23: - dev->regs[0x09] |= 0x0d; - break; - case 24: case 25: case 26: case 27: - case 28: case 29: case 30: case 31: - dev->regs[0x09] |= 0x0e; - break; - case 32: case 33: case 34: case 35: - dev->regs[0x09] |= 0x1b; - break; - case 36: case 37: case 38: case 39: - dev->regs[0x09] |= 0x0f; - break; - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - dev->regs[0x09] |= 0x17; - break; - case 48: - dev->regs[0x09] |= 0x1e; - break; - default: - if (mem_size_mb < 64) - dev->regs[0x09] |= 0x1e; - else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) - dev->regs[0x09] |= 0x22; - else - dev->regs[0x09] |= 0x24; - break; - } - - dev->regs[0x11] = 0x09; - dev->regs[0x12] = 0xff; - dev->regs[0x1f] = 0x20; /* Video access enabled. */ - dev->regs[0x23] = 0xf0; - dev->regs[0x26] = 0x01; - dev->smram = smram_add(); - smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x00010000, 0, 1); dev->port_92 = device_add(&port_92_device); - port_92_remove(dev->port_92); - } else { + } else dev->reg_last = dev->reg_base + 0x11; - /* Bits 6 and 7 must be clear on the SiS 40x. */ - if (dev->reg_base == 0x60) - dev->reg_00 = 0x24; - - switch (mem_size_mb) { - case 1: - default: - dev->regs[0x00] = 0x00; - break; - case 2: - dev->regs[0x00] = 0x01; - break; - case 4: - dev->regs[0x00] = 0x02; - break; - case 6: - dev->regs[0x00] = 0x03; - break; - case 8: - dev->regs[0x00] = 0x04; - break; - case 10: - dev->regs[0x00] = 0x05; - break; - case 12: - dev->regs[0x00] = 0x0b; - break; - case 16: - dev->regs[0x00] = 0x19; - break; - case 18: - dev->regs[0x00] = 0x06; - break; - case 20: - dev->regs[0x00] = 0x14; - break; - case 24: - dev->regs[0x00] = 0x15; - break; - case 32: - dev->regs[0x00] = 0x1b; - break; - case 36: - dev->regs[0x00] = 0x16; - break; - case 40: - dev->regs[0x00] = 0x17; - break; - case 48: - dev->regs[0x00] = 0x1e; - break; - case 64: - dev->regs[0x00] = 0x1f; - break; - } - - dev->regs[0x11] = 0x01; - } - io_sethandler(0x0022, 0x0002, sis_85c4xx_in, NULL, NULL, sis_85c4xx_out, NULL, NULL, dev); - dev->scratch[0] = dev->scratch[1] = 0xff; - io_sethandler(0x00e1, 0x0002, sis_85c4xx_in, NULL, NULL, sis_85c4xx_out, NULL, NULL, dev); - sis_85c4xx_recalcmapping(dev); + sis_85c4xx_reset(dev); return dev; } @@ -425,7 +363,7 @@ const device_t sis_85c401_device = { "SiS 85c401/85c402", 0, 0x060, - sis_85c4xx_init, sis_85c4xx_close, NULL, + sis_85c4xx_init, sis_85c4xx_close, sis_85c4xx_reset, { NULL }, NULL, NULL, NULL }; @@ -434,7 +372,7 @@ const device_t sis_85c460_device = { "SiS 85c460", 0, 0x050, - sis_85c4xx_init, sis_85c4xx_close, NULL, + sis_85c4xx_init, sis_85c4xx_close, sis_85c4xx_reset, { NULL }, NULL, NULL, NULL }; @@ -444,7 +382,7 @@ const device_t sis_85c461_device = { "SiS 85c461", 0, 0x050, - sis_85c4xx_init, sis_85c4xx_close, NULL, + sis_85c4xx_init, sis_85c4xx_close, sis_85c4xx_reset, { NULL }, NULL, NULL, NULL }; @@ -453,7 +391,7 @@ const device_t sis_85c471_device = { "SiS 85c407/85c471", 0, 0x150, - sis_85c4xx_init, sis_85c4xx_close, NULL, + sis_85c4xx_init, sis_85c4xx_close, sis_85c4xx_reset, { NULL }, NULL, NULL, NULL }; diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c index c01690064..84ad90c91 100644 --- a/src/chipset/sis_85c50x.c +++ b/src/chipset/sis_85c50x.c @@ -89,7 +89,7 @@ sis_85c50x_shadow_recalc(sis_85c50x_t *dev) mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x56] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); } - flushmmucache(); + flushmmucache_nopc(); } diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index a8962030b..591805329 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -291,6 +291,9 @@ umc_8886_reset(void *priv) { umc_8886_t *dev = (umc_8886_t *)priv; + memset(dev->pci_conf_sb[0], 0x00, sizeof(dev->pci_conf_sb[0])); + memset(dev->pci_conf_sb[1], 0x00, sizeof(dev->pci_conf_sb[1])); + dev->pci_conf_sb[0][0] = 0x60; /* UMC */ dev->pci_conf_sb[0][1] = 0x10; @@ -336,6 +339,9 @@ umc_8886_reset(void *priv) for (int i = 1; i < 5; i++) /* Disable all IRQ interrupts */ pci_set_irq_routing(i, PCI_IRQ_DISABLED); + + cpu_set_isa_pci_div(3); + cpu_set_pci_speed(cpu_busspeed / 2); } diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index b3d5cb0dc..d147bf5f7 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -97,6 +97,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" +#include "x86.h" #include <86box/timer.h> #include <86box/io.h> #include <86box/device.h> @@ -106,6 +107,18 @@ #include <86box/port_92.h> #include <86box/smram.h> +#ifdef USE_DYNAREC +# include "codegen_public.h" +#else +#ifdef USE_NEW_DYNAREC +# define PAGE_MASK_SHIFT 6 +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_SHIFT 4 +#endif +# define PAGE_MASK_MASK 63 +#endif #include <86box/chipset.h> @@ -131,34 +144,108 @@ hb4_log(const char *fmt, ...) typedef struct hb4_t { - uint8_t pci_conf[128]; /* PCI Registers */ - smram_t *smram; /* SMRAM Handler */ + uint8_t shadow, + shadow_read, shadow_write, + pci_conf[256]; /* PCI Registers */ + int mem_state[9]; + smram_t *smram[2]; /* SMRAM Handlers */ } hb4_t; +static int shadow_bios[4] = { (MEM_READ_EXTANY | MEM_WRITE_INTERNAL), (MEM_READ_EXTANY | MEM_WRITE_EXTANY), + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL), (MEM_READ_INTERNAL | MEM_WRITE_EXTANY) }; +static int shadow_read[2] = { MEM_READ_EXTANY, MEM_READ_INTERNAL }; +static int shadow_write[2] = { MEM_WRITE_INTERNAL, MEM_WRITE_EXTANY }; + + +int +hb4_shadow_bios_high(hb4_t *dev) +{ + int state; + + state = shadow_bios[dev->pci_conf[0x55] >> 6]; + + if (state != dev->mem_state[8]) { + mem_set_mem_state_both(0xf0000, 0x10000, state); + if ((dev->mem_state[8] & MEM_READ_INTERNAL) && !(state & MEM_READ_INTERNAL)) + mem_invalidate_range(0xf0000, 0xfffff); + dev->mem_state[8] = state; + return 1; + } + + return 0; +} + + +int +hb4_shadow_bios_low(hb4_t *dev) +{ + int state; + + state = shadow_bios[(dev->pci_conf[0x55] >> 6) & (dev->shadow | 0x01)]; + + if (state != dev->mem_state[7]) { + mem_set_mem_state_both(0xe0000, 0x10000, state); + dev->mem_state[7] = state; + return 1; + } + + return 0; +} + + +int +hb4_shadow_main(hb4_t *dev) +{ + int i, state; + int n = 0; + + for (i = 0; i < 6; i++) { + state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> (i + 2)) & 0x01)] | + shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01]; + + if (state != dev->mem_state[i + 1]) { + n++; + mem_set_mem_state_both(0xc8000 + (i << 14), 0x4000, state); + dev->mem_state[i + 1] = state; + } + } + + return n; +} + + +int +hb4_shadow_video(hb4_t *dev) +{ + int state; + + state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> 1) & 0x01)] | + shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01]; + + if (state != dev->mem_state[0]) { + mem_set_mem_state_both(0xc0000, 0x8000, state); + dev->mem_state[0] = state; + return 1; + } + + return 0; +} + + void hb4_shadow(hb4_t *dev) { - int state, i; + int n = 0; + pclog("SHADOW: %02X%02X\n", dev->pci_conf[0x55], dev->pci_conf[0x54]); - mem_set_mem_state_both(0xe0000, 0x20000, ((dev->pci_conf[0x55] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | - ((dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL)); + n = hb4_shadow_bios_high(dev); + n += hb4_shadow_bios_low(dev); + n += hb4_shadow_main(dev); + n += hb4_shadow_video(dev); - if (dev->pci_conf[0x54] & 1) { - state = (dev->pci_conf[0x54] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - state |= (dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - - mem_set_mem_state_both(0xc0000, 0x8000, state); - - for (i = 0; i < 6; i++) { - state = (dev->pci_conf[0x54] & (1 << (i + 2))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - state |= (dev->pci_conf[0x55] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - - mem_set_mem_state_both(0xc8000 + (i << 4), 0x4000, state); - } - } - - flushmmucache_nopc(); + if (n > 0) + flushmmucache_nopc(); } @@ -169,7 +256,9 @@ hb4_smram(hb4_t *dev) /* Bit 0, if set, enables SMRAM access outside SMM. SMRAM appears to be always enabled in SMM, and is always set to A0000-BFFFF. */ - smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + /* There's a mirror of the SMRAM at 0E0A0000, mapped to A0000. */ + smram_enable(dev->smram[1], 0x0e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); /* Bit 5 seems to set data to go to PCI and code to DRAM. The Samsung SPC7700P-LW uses this. */ @@ -185,6 +274,8 @@ static void hb4_write(int func, int addr, uint8_t val, void *priv) { hb4_t *dev = (hb4_t *)priv; + uint8_t old; + hb4_log("UM8881: dev->regs[%02x] = %02x POST: %02x \n", addr, val, inb(0x80)); switch (addr) { @@ -207,11 +298,23 @@ hb4_write(int func, int addr, uint8_t val, void *priv) break; case 0x51: case 0x52: - case 0x53: dev->pci_conf[addr] = val; break; - case 0x54: case 0x55: + case 0x53: + old = dev->pci_conf[addr]; + dev->pci_conf[addr] = val; + pclog("HB53: %02X\n", val); + break; + + case 0x55: + dev->shadow_read = (val & 0x80); + dev->shadow_write = (val & 0x40); + dev->pci_conf[addr] = val; + hb4_shadow(dev); + break; + case 0x54: + dev->shadow = (val & 0x01) << 1; dev->pci_conf[addr] = val; hb4_shadow(dev); break; @@ -236,8 +339,12 @@ static uint8_t hb4_read(int func, int addr, void *priv) { hb4_t *dev = (hb4_t *)priv; + uint8_t ret = 0xff; - return dev->pci_conf[addr]; + if (func == 0) + ret = dev->pci_conf[addr]; + + return ret; } @@ -245,6 +352,7 @@ static void hb4_reset(void *priv) { hb4_t *dev = (hb4_t *)priv; + memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); dev->pci_conf[0] = 0x60; /* UMC */ dev->pci_conf[1] = 0x10; @@ -269,7 +377,12 @@ hb4_reset(void *priv) hb4_write(0, 0x54, 0x00, dev); hb4_write(0, 0x55, 0x00, dev); - hb4_write(0, 0x60, 0x20, dev); + hb4_write(0, 0x60, 0x80, dev); + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + memset(dev->mem_state, 0x00, sizeof(dev->mem_state)); } @@ -294,7 +407,8 @@ hb4_init(const device_t *info) device_add(&port_92_pci_device); /* SMRAM */ - dev->smram = smram_add(); + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); hb4_reset(dev); diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 467ea01eb..4eb9530ba 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -591,7 +591,7 @@ smram_restore_state_p5(uint32_t *saved_state) smm_seg_load(&cpu_state.seg_gs); if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION) - smbase = saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET] & 0x00ffffff; + smbase = saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET]; /* Am486/5x86 stuff */ if (!is_pentium) { diff --git a/src/cpu/x86.c b/src/cpu/x86.c index c16939559..725d674e8 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -241,8 +241,13 @@ reset_common(int hard) leave_smm(); /* Needed for the ALi M1533. */ - if (is486 && (hard || soft_reset_pci)) + if (is486 && (hard || soft_reset_pci)) { pci_reset(); + if (!hard && soft_reset_pci) { + dma_reset(); + device_reset_all(); + } + } use32 = 0; cpu_cur_status = 0; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index c64f8b87f..5dc67ad55 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -673,6 +673,7 @@ kbd_status(const char *fmt, ...) } +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -1219,13 +1220,14 @@ write_output(atkbd_t *dev, uint8_t val) /* Do this here to avoid an infinite reset loop. */ dev->p2 = val; - /* 0 holds the CPU in the RESET state, 1 releases it. To simply this, + /* 0 holds the CPU in the RESET state, 1 releases it. To simplify this, we just do everything on release. */ if ((val & 0x01) && !(old & 0x01)) { if (val & 0x01) { /* Pin 0 selected. */ pclog("write_output(): Pulse reset!\n"); - hardresetx86(); /*Pulse reset!*/ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); } } } @@ -2936,18 +2938,36 @@ static void kbd_reset(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i; - uint8_t kbc_ven; if (dev == NULL) return; - kbc_ven = dev->flags & KBC_VEN_MASK; - dev->status &= ~(STAT_IFULL | STAT_OFULL | STAT_CD); dev->last_irq = 0; + picintc(1 << 1); + picintc(1 << 12); dev->secr_phase = 0; dev->kbd_in = 0; + dev->ob = 0xff; + + sc_or = 0; +} + + +static void +kbd_power_on(atkbd_t *dev) +{ + int i; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + kbd_reset(dev); + + dev->status = STAT_UNLOCKED; + /* Write the value here first, so that we don't hit a pulse reset. */ + dev->p2 = 0xcf; + write_output(dev, 0xcf); + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); /* Set up the correct Video Type bits. */ @@ -2960,17 +2980,15 @@ kbd_reset(void *priv) dev->inhibit = 0x10; kbd_log("ATkbc: input port = %02x\n", dev->p1); - keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); - /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); keyboard_scan = 1; set_enable_mouse(dev, 0); mouse_scan = 0; - dev->ob = 0xff; + dev->mem[0x31] = 0xfe; - sc_or = 0; + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); for (i = 1; i <= 2; i++) kbc_queue_reset(i); @@ -2978,22 +2996,6 @@ kbd_reset(void *priv) memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); - - dev->mem[0x31] = 0xfe; -} - - -static void -kbd_power_on(atkbd_t *dev) -{ - kbd_reset(dev); - - dev->status = STAT_UNLOCKED; - /* Write the value here first, so that we don't hit a pulse reset. */ - dev->p2 = 0xcf; - write_output(dev, 0xcf); - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; } diff --git a/src/mem/mem.c b/src/mem/mem.c index 693f9db2a..855cdd93a 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -1913,13 +1913,13 @@ page_remove_from_evict_list(page_t *p) void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -1939,13 +1939,13 @@ mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != *(uint16_t *)&p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -1975,13 +1975,13 @@ mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != *(uint32_t *)&p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -2007,13 +2007,13 @@ mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; @@ -2025,13 +2025,13 @@ mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); if ((addr & 0xf) == 0xf) @@ -2045,13 +2045,13 @@ mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) { - if ((p != NULL) && (p->mem == page_ff)) + if (p == NULL) return; #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); if ((addr & 0xf) >= 0xd) @@ -2180,42 +2180,27 @@ mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) { - uint64_t mask; #ifdef USE_NEW_DYNAREC int byte_offset; uint64_t byte_mask; - uint32_t i; page_t *p; start_addr &= ~PAGE_MASK_MASK; end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + for (; start_addr <= end_addr; start_addr += 0x1000) { if ((start_addr >> 12) >= pages_sz) continue; - mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - p = &pages[start_addr >> 12]; - p->dirty_mask |= mask; - if ((p->code_present_mask & mask) && !page_in_evict_list(p)) - page_add_to_evict_list(p); + if (p) { + p->dirty_mask = 0xffffffffffffffffULL; - for (i = start_addr; (i <= end_addr) && (i < (start_addr + (1 << PAGE_MASK_SHIFT))); i++) { - /* Do not look at the byte stuff if start_addr >= (mem_size * 1024), as we do not allocate the - byte dirty and code present mask arrays beyond the end of RAM. */ - if (i < (mem_size << 10)) { - byte_offset = (i >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; - byte_mask = (uint64_t)1 << (i & PAGE_BYTE_MASK_MASK); + if (p->byte_dirty_mask) + memset(p->byte_dirty_mask, 0xff, 64 * sizeof(uint64_t)); - if (p) { - if (p->byte_dirty_mask) - p->byte_dirty_mask[byte_offset] |= byte_mask; - if (p->byte_code_present_mask && (p->byte_code_present_mask[byte_offset] & byte_mask) && - !page_in_evict_list(p)) - page_add_to_evict_list(p); - } - } + if (!page_in_evict_list(p)) + page_add_to_evict_list(p); } } #else @@ -2223,14 +2208,12 @@ mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) start_addr &= ~PAGE_MASK_MASK; end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { - mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - + for (; start_addr <= end_addr; start_addr += 0x1000) { /* Do nothing if the pages array is empty or DMA reads/writes to/from PCI device memory addresses may crash the emulator. */ cur_addr = (start_addr >> 12); if (cur_addr < pages_sz) - pages[cur_addr].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + memset(pages[cur_addr].dirty_mask, 0xff, sizeof(pages[cur_addr].dirty_mask)); } #endif } @@ -2712,6 +2695,7 @@ mem_reset(void) if ((c << 12) >= (mem_size << 10)) pages[c].mem = page_ff; else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (mem_size > 1048576) { if ((c << 12) < (1 << 30)) pages[c].mem = &ram[c << 12]; @@ -2719,6 +2703,9 @@ mem_reset(void) pages[c].mem = &ram2[(c << 12) - (1 << 30)]; } else pages[c].mem = &ram[c << 12]; +#else + pages[c].mem = &ram[c << 12]; +#endif } if (c < m) { pages[c].write_b = mem_write_ramb_page; From 114539b2b26eb7c670436e23c295ded86e546a89 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 2 Oct 2021 23:07:12 +0200 Subject: [PATCH 080/140] Added a pic_set_pci() function that adds the PIC I/O aliases. --- src/include/86box/pic.h | 1 + src/pic.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/include/86box/pic.h b/src/include/86box/pic.h index 139aa5195..33be66135 100644 --- a/src/include/86box/pic.h +++ b/src/include/86box/pic.h @@ -45,6 +45,7 @@ extern void pic_elcr_write(uint16_t port, uint8_t val, void *priv); extern uint8_t pic_elcr_read(uint16_t port, void *priv); extern void pic_set_shadow(int sh); +extern void pic_set_pci(void); extern void pic_init(void); extern void pic_init_pcjr(void); extern void pic2_init(void); diff --git a/src/pic.c b/src/pic.c index 36bd4b0e2..86db5389c 100644 --- a/src/pic.c +++ b/src/pic.c @@ -515,6 +515,18 @@ pic_write(uint16_t addr, uint8_t val, void *priv) } +void +pic_set_pci(void) +{ + int i; + + for (i = 0x0024; i < 0x0040; i++) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } +} + + void pic_init(void) { From 63d208182aea3dadbc0675b36407c9cface83bd4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 4 Oct 2021 15:38:43 +0200 Subject: [PATCH 081/140] Fixed pic_set_pci(). --- src/pic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pic.c b/src/pic.c index 86db5389c..38cee8951 100644 --- a/src/pic.c +++ b/src/pic.c @@ -520,7 +520,7 @@ pic_set_pci(void) { int i; - for (i = 0x0024; i < 0x0040; i++) { + for (i = 0x0024; i < 0x0040; i += 4) { io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); } From 9765090991557a5ea9697c9819c4c5744ad84bbc Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 4 Oct 2021 19:52:04 +0200 Subject: [PATCH 082/140] Made pic_set_pci() also add aliases on 1120-113F and 11A0-11BF. --- src/pic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pic.c b/src/pic.c index 38cee8951..c77f08023 100644 --- a/src/pic.c +++ b/src/pic.c @@ -524,6 +524,11 @@ pic_set_pci(void) io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); } + + for (i = 0x1120; i < 0x1140; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } } From d858033ae8329473a1dfdf0c8b1765566d1592fd Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 6 Oct 2021 18:17:32 +0200 Subject: [PATCH 083/140] Removed the two IMS8848 machines. --- src/machine/machine_table.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3a57cf0c6..6910a5274 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -432,10 +432,6 @@ const machine_t machines[] = { { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, /* This has the Phoenix MultiKey KBC firmware. */ { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, - /* This most likely has a standalone AMI Megakey 1993, which is type 'P', like the below Tekram board. */ - { "[IMS 8848] J-Bond PCI400C-B", "pci400c_b", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_pci400c_b_init, NULL }, - /* This has a standalone AMI Megakey 1993, which is type 'P'. */ - { "[IMS 8848] Tekram G486IP", "g486ip", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_g486ip_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ From 126688fc5e93c95da9c1f42b2e6ce250ba40726b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 9 Oct 2021 16:40:47 +0200 Subject: [PATCH 084/140] Added a comment related to the PB450. --- src/device/keyboard_at.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 5dc67ad55..6a3d9c370 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2067,6 +2067,8 @@ write64_generic(void *priv, uint8_t val) Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), Bit 4 must be 0, Bit 6 ignored. + Packard Bell PB450: + Bit 2 must be 1. P6RP4: Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); From 79999818f5b97e2f15903e8b43b011ee88a0e6c4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 9 Oct 2021 17:27:07 +0200 Subject: [PATCH 085/140] A slight fix to the OPTi 611 IDE controller. --- src/disk/hdc_ide_opti611.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide_opti611.c b/src/disk/hdc_ide_opti611.c index 73a52a723..4cdf06b78 100644 --- a/src/disk/hdc_ide_opti611.c +++ b/src/disk/hdc_ide_opti611.c @@ -56,11 +56,11 @@ opti611_cfg_write(uint16_t addr, uint8_t val, void *priv) case 0x0002: dev->regs[0x12] = (val & 0xc1) | 0x02; if (val & 0xc0) { + if (val & 0x40) + dev->cfg_locked = 1; dev->in_cfg = 0; opti611_ide_handler(dev); } - if (val & 0x40) - dev->cfg_locked = 1; break; case 0x0003: dev->regs[0x03] = (val & 0xdf); From 1c2d1e702bafae6a71c1c32d23659642453964cb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 9 Oct 2021 17:37:09 +0200 Subject: [PATCH 086/140] Assorted changes and bugfixes and added the two IMS 8848 machines. --- src/86box.c | 20 ++ src/chipset/ims8848.c | 411 ++++++++++++++++++++++++++++++++ src/chipset/intel_4x0.c | 54 ++--- src/chipset/opti499.c | 264 ++++++++++++++++++++ src/chipset/sis_5511.c | 177 ++++++++------ src/cpu/cpu.c | 6 + src/cpu/cpu.h | 3 + src/cpu/x86.c | 21 +- src/cpu/x86_ops_misc.h | 2 + src/cpu/x86_ops_mov_ctrl.h | 81 ++++++- src/device/phoenix_486_jumper.c | 47 +++- src/include/86box/chipset.h | 5 +- src/include/86box/machine.h | 3 + src/include/86box/mem.h | 2 + src/include/86box/smram.h | 2 + src/io.c | 3 + src/machine/m_at_386dx_486.c | 71 +++++- src/machine/machine_table.c | 4 + src/mem/smram.c | 58 ++++- src/win/Makefile.mingw | 2 +- 20 files changed, 1086 insertions(+), 150 deletions(-) create mode 100644 src/chipset/ims8848.c create mode 100644 src/chipset/opti499.c diff --git a/src/86box.c b/src/86box.c index eca8544a5..e965f84c5 100644 --- a/src/86box.c +++ b/src/86box.c @@ -724,6 +724,26 @@ pc_init_modules(void) wchar_t temp[512]; char tempc[512]; + c = m = 0; + while (machine_get_internal_name_ex(c) != NULL) { + m = machine_available(c); + if (!m) + pclog("Missing machine: %s\n", machine_getname_ex(c)); + c++; + } + + c = m = 0; + while (video_get_internal_name(c) != NULL) { + memset(tempc, 0, sizeof(tempc)); + device_get_name(video_card_getdevice(c), 0, tempc); + if ((c > 1) && !(tempc[0])) + break; + m = video_card_available(c); + if (!m) + pclog("Missing video card: %s\n", tempc); + c++; + } + pc_log("Scanning for ROM images:\n"); c = m = 0; while (machine_get_internal_name_ex(m) != NULL) { diff --git a/src/chipset/ims8848.c b/src/chipset/ims8848.c new file mode 100644 index 000000000..da758ad5e --- /dev/null +++ b/src/chipset/ims8848.c @@ -0,0 +1,411 @@ +/* + * 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 IMS 8848/8849 chipset. + * + * + * + * Authors: Miran Grca, + * Tiseno100, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/smram.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + + +/* + IMS 884x Configuration Registers + + Note: IMS 884x are rebadged ATMEL AT 40411/40412 chipsets + + By: Tiseno100, Miran Grca(OBattler) + + Register 00h: + Bit 3: F0000-FFFFF Shadow Enable + Bit 2: E0000-EFFFF Shadow Enable + Bit 0: ???? + + Register 04h: + Bit 3: Cache Write Hit Wait State + Bit 2: Cache Read Hit Wait State + + Register 06h: + Bit 3: System BIOS Cacheable (1: Yes / 0: No) + Bit 1: Power Management Mode (1: IRQ / 0: SMI#) + + Register 08h: + Bit 2: System BIOS Shadow Write (1: Enable / 0: Disable) + Bit 1: System BIOS Shadow Read? + + Register 0Dh: + Bit 0: IO 100H-3FFH Idle Detect (1: Enable / 0: Disable) + + Register 0Eh: + Bit 7: DMA & Local Bus Idle Detect (1: Enable / 0: Disable) + Bit 6: Floppy Disk Idle Detect (1: Enable / 0: Disable) + Bit 5: IDE Idle Detect (1: Enable / 0: Disable) + Bit 4: Serial Port Idle Detect (1: Enable / 0: Disable) + Bit 3: Parallel Port Idle Detect (1: Enable / 0: Disable) + Bit 2: Keyboard Idle Detect (1: Enable / 0: Disable) + Bit 1: Video Idle Detect (1: Enable / 0: Disable) + + Register 12h: + Bits 3-2: Power Saving Timer (00 = 1 MIN, 01 = 3 MIN, 10 = 5 MIN, 11 = 8 MIN) + Bit 1: Base Memory (1: 512KB / 0: 640KB) + + Register 1Ah: + Bit 3: Cache Write Hit W/S For PCI (1: Enabled / 0: Disable) + Bit 2: Cache Read Hit W/S For PCI (1: Enabled / 0: Disable) + Bit 1: VESA Clock Skew (1: 4ns/6ns, 0: No Delay/2ns) + + Register 1Bh: + Bit 6: Enable SMRAM (always at 30000-4FFFF) in SMM + Bit 5: ???? + Bit 4: Software SMI# + Bit 3: DC000-DFFFF Shadow Enable + Bit 2: D8000-DBFFF Shadow Enable + Bit 1: D4000-D7FFF Shadow Enable + Bit 0: D0000-D3FFF Shadow Enable + + Register 1Ch: + Bits 7-4: INTA IRQ routing (0 = disabled, 1 to F = IRQ) + Bit 3: CC000-CFFFF Shadow Enable + Bit 2: C8000-CBFFF Shadow Enable + Bit 1: C4000-C7FFF Shadow Enable + Bit 0: C0000-C3FFF Shadow Enable + + Register 1Dh: + Bits 7-4: INTB IRQ routing (0 = disabled, 1 to F = IRQ) + + Register 1Eh: + Bits 7-4: INTC IRQ routing (0 = disabled, 1 to F = IRQ) + Bit 1: C4000-C7FFF Cacheable + Bit 0: C0000-C3FFF Cacheable + + Register 21h: + Bits 7-4: INTD IRQ routing (0 = disabled, 1 to F = IRQ) + + Register 22h: + Bit 5: Local Bus Master #2 select (0 = VESA, 1 = PCI) + Bit 4: Local Bus Master #1 select (0 = VESA, 1 = PCI) + Bits 1-0: Internal HADS# Delay Always (00 = No Delay, 01 = 1 Clk, 10 = 2 Clks) + + Register 23h: + Bit 7: Seven Bits Tag (1: Enabled / 0: Disable) + Bit 3: Extend LBRDY#(VL Master) (1: Enabled / 0: Disable) + Bit 2: Sync LRDY#(VL Slave) (1: Enabled / 0: Disable) + Bit 0: HADS# Delay After LB. Cycle (1: Enabled / 0: Disable) +*/ + +typedef struct +{ + uint8_t idx, access_data, + regs[256], pci_conf[256]; + + smram_t *smram; +} ims8848_t; + + +#ifdef ENABLE_IMS8848_LOG +int ims8848_do_log = ENABLE_IMS8848_LOG; + + +static void +ims8848_log(const char *fmt, ...) +{ + va_list ap; + + if (ims8848_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ims8848_log(fmt, ...) +#endif + + +/* Shadow write always enabled, 1B and 1C control C000-DFFF read. */ +static void +ims8848_recalc(ims8848_t *dev) +{ + int i, state_on; + uint32_t base; + ims8848_log("SHADOW: 00 = %02X, 08 = %02X, 1B = %02X, 1C = %02X\n", + dev->regs[0x00], dev->regs[0x08], dev->regs[0x1b], dev->regs[0x1c]); + + state_on = MEM_READ_INTERNAL; + state_on |= (dev->regs[0x08] & 0x04) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + + for (i = 0; i < 2; i++) { + base = 0xe0000 + (i << 16); + if (dev->regs[0x00] & (1 << (i + 2))) + mem_set_mem_state_both(base, 0x10000, state_on); + else + mem_set_mem_state_both(base, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + if (dev->regs[0x1c] & (1 << i)) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + + base = 0xd0000 + (i << 14); + if (dev->regs[0x1b] & (1 << i)) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + flushmmucache_nopc(); +} + + +static void +ims8848_base_memory(ims8848_t *dev) +{ + /* We can use the proper mem_set_access to handle that. */ + mem_set_mem_state_both(0x80000, 0x20000, (dev->regs[0x12] & 2) ? + (MEM_READ_DISABLED | MEM_WRITE_DISABLED) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); +} + + +static void +ims8848_smram(ims8848_t *dev) +{ + smram_disable_all(); + + smram_enable(dev->smram, 0x00030000, 0x00030000, 0x20000, dev->regs[0x1b] & 0x40, 1); +} + + +static void +ims8848_write(uint16_t addr, uint8_t val, void *priv) +{ + ims8848_t *dev = (ims8848_t *) priv; + uint8_t old = dev->regs[dev->idx]; + + switch (addr) { + case 0x22: + ims8848_log("[W] IDX = %02X\n", val); + dev->idx = val; + break; + case 0x23: + ims8848_log("[W] IDX IN = %02X\n", val); + if (((val & 0x0f) == ((dev->idx >> 4) & 0x0f)) && ((val & 0xf0) == ((dev->idx << 4) & 0xf0))) + dev->access_data = 1; + break; + case 0x24: + ims8848_log("[W] [%i] REG %02X = %02X\n", dev->access_data, dev->idx, val); + if (dev->access_data) { + dev->regs[dev->idx] = val; + switch (dev->idx) { + case 0x00: case 0x08: case 0x1b: case 0x1c: + /* Shadow RAM */ + ims8848_recalc(dev); + if (dev->idx == 0x1b) { + ims8848_smram(dev); + if (!(old & 0x10) && (val & 0x10)) + smi_line = 1; + } else if (dev->idx == 0x1c) + pci_set_irq_routing(PCI_INTA, (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + + case 0x1d: case 0x1e: + pci_set_irq_routing(PCI_INTB + (dev->idx - 0x1d), (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + case 0x21: + pci_set_irq_routing(PCI_INTD, (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + + case 0x12: + /* Base Memory */ + ims8848_base_memory(dev); + break; + } + dev->access_data = 0; + } + break; + } +} + + +static uint8_t +ims8848_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + ims8848_t *dev = (ims8848_t *) priv; +#ifdef ENABLE_IMS8848_LOG + uint8_t old_ad = dev->access_data; +#endif + + switch (addr) { + case 0x22: + ims8848_log("[R] IDX = %02X\n", ret); + ret = dev->idx; + break; + case 0x23: + ims8848_log("[R] IDX IN = %02X\n", ret); + ret = (dev->idx >> 4) | (dev->idx << 4); + break; + case 0x24: + if (dev->access_data) { + ret = dev->regs[dev->idx]; + dev->access_data = 0; + } + ims8848_log("[R] [%i] REG %02X = %02X\n", old_ad, dev->idx, ret); + break; + } + + return ret; +} + + +static void +ims8849_pci_write(int func, int addr, uint8_t val, void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + + ims8848_log("IMS 884x-PCI: dev->regs[%02x] = %02x POST: %02x\n", addr, val, inb(0x80)); + + if (func == 0) switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + + case 0x05: + dev->pci_conf[addr] = val & 3; + break; + + case 0x07: + dev->pci_conf[addr] &= val & 0xf7; + break; + + case 0x0c ... 0x0d: + dev->pci_conf[addr] = val; + break; + + case 0x52 ... 0x55: + dev->pci_conf[addr] = val; + break; + } +} + + +static uint8_t +ims8849_pci_read(int func, int addr, void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ims8848_reset(void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + + memset(dev->regs, 0x00, sizeof(dev->regs)); + memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); + + dev->pci_conf[0x00] = 0xe0; /* Integrated Micro Solutions (IMS) */ + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x49; /* 8849 */ + dev->pci_conf[0x03] = 0x88; + + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x07] = 0x02; + + dev->pci_conf[0x0b] = 0x06; + + ims8848_recalc(dev); /* Shadow RAM Setup */ + ims8848_base_memory(dev); /* Base Memory Setup */ + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + ims8848_smram(dev); +} + + +static void +ims8848_close(void *priv) +{ + ims8848_t *dev = (ims8848_t *) priv; + + smram_del(dev->smram); + + free(dev); +} + + +static void * +ims8848_init(const device_t *info) +{ + ims8848_t *dev = (ims8848_t *) malloc(sizeof(ims8848_t)); + memset(dev, 0, sizeof(ims8848_t)); + + device_add(&port_92_device); + + /* IMS 8848: + 22h Index + 23h Data Unlock + 24h Data + + IMS 8849: + PCI Device 0: IMS 8849 Dummy for compatibility reasons + */ + io_sethandler(0x0022, 0x0003, ims8848_read, NULL, NULL, ims8848_write, NULL, NULL, dev); + pci_add_card(PCI_ADD_NORTHBRIDGE, ims8849_pci_read, ims8849_pci_write, dev); + + dev->smram = smram_add(); + smram_set_separate_smram(1); + + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); + + ims8848_reset(dev); + + return dev; +} + + +const device_t ims8848_device = { + "IMS 8848/8849", + 0, + 0, + ims8848_init, ims8848_close, ims8848_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 6da41c24f..bf64bd00f 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -55,6 +55,7 @@ typedef struct smram_locked, max_drb, drb_unit, drb_default; uint8_t regs[256], regs_locked[256]; + uint8_t mem_state[256]; int type; smram_t *smram_low, *smram_high; } i4x0_t; @@ -81,23 +82,18 @@ i4x0_log(const char *fmt, ...) static void -i4x0_map(uint32_t addr, uint32_t size, int state) +i4x0_map(i4x0_t *dev, uint32_t addr, uint32_t size, int state) { - switch (state & 3) { - case 0: - mem_set_mem_state_both(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state_both(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 2: - mem_set_mem_state_both(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state_both(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; + uint32_t base = addr >> 12; + int states[4] = { MEM_READ_EXTANY | MEM_WRITE_EXTANY, MEM_READ_INTERNAL | MEM_WRITE_EXTANY, + MEM_READ_EXTANY | MEM_WRITE_INTERNAL, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL }; + + state &= 3; + if (dev->mem_state[base] != state) { + mem_set_mem_state_both(addr, size, states[state]); + dev->mem_state[base] = state; + flushmmucache_nopc(); } - flushmmucache_nopc(); } @@ -584,10 +580,10 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0x59: /* PAM0 */ if (dev->type <= INTEL_430NX) { if ((regs[0x59] ^ val) & 0x0f) - i4x0_map(0x80000, 0x20000, val & 0x0f); + i4x0_map(dev, 0x80000, 0x20000, val & 0x0f); } if ((regs[0x59] ^ val) & 0xf0) { - i4x0_map(0xf0000, 0x10000, val >> 4); + i4x0_map(dev, 0xf0000, 0x10000, val >> 4); shadowbios = (val & 0x10); } if (dev->type > INTEL_430NX) @@ -597,44 +593,44 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x5a: /* PAM1 */ if ((regs[0x5a] ^ val) & 0x0f) - i4x0_map(0xc0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xc0000, 0x04000, val & 0xf); if ((regs[0x5a] ^ val) & 0xf0) - i4x0_map(0xc4000, 0x04000, val >> 4); + i4x0_map(dev, 0xc4000, 0x04000, val >> 4); regs[0x5a] = val & 0x77; break; case 0x5b: /*PAM2 */ if ((regs[0x5b] ^ val) & 0x0f) - i4x0_map(0xc8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xc8000, 0x04000, val & 0xf); if ((regs[0x5b] ^ val) & 0xf0) - i4x0_map(0xcc000, 0x04000, val >> 4); + i4x0_map(dev, 0xcc000, 0x04000, val >> 4); regs[0x5b] = val & 0x77; break; case 0x5c: /*PAM3 */ if ((regs[0x5c] ^ val) & 0x0f) - i4x0_map(0xd0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xd0000, 0x04000, val & 0xf); if ((regs[0x5c] ^ val) & 0xf0) - i4x0_map(0xd4000, 0x04000, val >> 4); + i4x0_map(dev, 0xd4000, 0x04000, val >> 4); regs[0x5c] = val & 0x77; break; case 0x5d: /* PAM4 */ if ((regs[0x5d] ^ val) & 0x0f) - i4x0_map(0xd8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xd8000, 0x04000, val & 0xf); if ((regs[0x5d] ^ val) & 0xf0) - i4x0_map(0xdc000, 0x04000, val >> 4); + i4x0_map(dev, 0xdc000, 0x04000, val >> 4); regs[0x5d] = val & 0x77; break; case 0x5e: /* PAM5 */ if ((regs[0x5e] ^ val) & 0x0f) - i4x0_map(0xe0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xe0000, 0x04000, val & 0xf); if ((regs[0x5e] ^ val) & 0xf0) - i4x0_map(0xe4000, 0x04000, val >> 4); + i4x0_map(dev, 0xe4000, 0x04000, val >> 4); regs[0x5e] = val & 0x77; break; case 0x5f: /* PAM6 */ if ((regs[0x5f] ^ val) & 0x0f) - i4x0_map(0xe8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xe8000, 0x04000, val & 0xf); if ((regs[0x5f] ^ val) & 0xf0) - i4x0_map(0xec000, 0x04000, val >> 4); + i4x0_map(dev, 0xec000, 0x04000, val >> 4); regs[0x5f] = val & 0x77; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c new file mode 100644 index 000000000..87bc39c8d --- /dev/null +++ b/src/chipset/opti499.c @@ -0,0 +1,264 @@ +/* + * 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 OPTi 82C493/82C499 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2008-2020 Tiseno100. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + + +typedef struct +{ + uint8_t idx, + regs[256], scratch[2]; +} opti499_t; + + +#ifdef ENABLE_OPTI499_LOG +int opti499_do_log = ENABLE_OPTI499_LOG; + + +static void +opti499_log(const char *fmt, ...) +{ + va_list ap; + + if (opti499_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti499_log(fmt, ...) +#endif + + +static void +opti499_recalc(opti499_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x22] & 0x80) { + shadowbios = 1; + shadowbios_write = 0; + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + } else { + shadowbios = 0; + shadowbios_write = 1; + shflags = MEM_READ_INTERNAL | MEM_WRITE_DISABLED; + } + + mem_set_mem_state_both(0xf0000, 0x10000, shflags); + + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + + if ((dev->regs[0x22] & ((base >= 0xe0000) ? 0x20 : 0x40)) && + (dev->regs[0x23] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x2d] && (1 << ((i >> 1) + 2))) + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else + shflags = MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + + if ((dev->regs[0x26] & 0x10) && (dev->regs[0x26] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x26] & 0x40) { + if (dev->regs[0x2d] && (1 << (i >> 1))) + shflags = MEM_READ_EXTANY; + else + shflags = MEM_READ_EXTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x2d] && (1 << (i >> 1))) + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else + shflags = MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + } + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + flushmmucache_nopc(); +} + + +static void +opti499_write(uint16_t addr, uint8_t val, void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + switch (addr) { + case 0x22: + opti499_log("[%04X:%08X] [W] dev->idx = %02X\n", CS, cpu_state.pc, val); + dev->idx = val; + break; + case 0x24: + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + if (dev->idx == 0x20) + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0xc0) | (val & 0x3f); + else + dev->regs[dev->idx] = val; + opti499_log("[%04X:%08X] [W] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, val); + + switch(dev->idx) { + case 0x20: + reset_on_hlt = !(val & 0x02); + break; + + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); + break; + + case 0x22: case 0x23: + case 0x26: case 0x2d: + opti499_recalc(dev); + break; + } + } + break; + + case 0xe1: case 0xe2: + dev->scratch[addr] = val; + break; + } +} + + +static uint8_t +opti499_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + opti499_t *dev = (opti499_t *) priv; + + switch (addr) { + case 0x22: + opti499_log("[%04X:%08X] [R] dev->idx = %02X\n", CS, cpu_state.pc, ret); + break; + case 0x24: + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + if (dev->idx == 0x2d) + ret = dev->regs[dev->idx] & 0xbf; + else + ret = dev->regs[dev->idx]; + opti499_log("[%04X:%08X] [R] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, ret); + } + break; + case 0xe1: + case 0xe2: + ret = dev->scratch[addr]; + break; + } + + return ret; +} + + +static void +opti499_reset(void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + memset(dev->regs, 0xff, sizeof(dev->regs)); + memset(&(dev->regs[0x20]), 0x00, 14 * sizeof(uint8_t)); + + dev->scratch[0] = dev->scratch[1] = 0xff; + + dev->regs[0x22] = 0x84; + dev->regs[0x24] = 0x87; + dev->regs[0x25] = 0xf0; + dev->regs[0x27] = 0xd1; + dev->regs[0x28] = dev->regs[0x2a] = 0x80; + dev->regs[0x29] = dev->regs[0x2b] = 0x10; + dev->regs[0x2d] = 0x40; + + reset_on_hlt = 1; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + opti499_recalc(dev); + + free(dev); +} + + +static void +opti499_close(void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + free(dev); +} + + +static void * +opti499_init(const device_t *info) +{ + opti499_t *dev = (opti499_t *) malloc(sizeof(opti499_t)); + memset(dev, 0, sizeof(opti499_t)); + + device_add(&port_92_device); + + io_sethandler(0x0022, 0x0001, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + + opti499_reset(dev); + + io_sethandler(0x00e1, 0x0002, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + + return dev; +} + + +const device_t opti499_device = { + "OPTi 82C499", + 0, + 1, + opti499_init, opti499_close, opti499_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/chipset/sis_5511.c b/src/chipset/sis_5511.c index 673d37ebe..f85b021b5 100644 --- a/src/chipset/sis_5511.c +++ b/src/chipset/sis_5511.c @@ -79,40 +79,56 @@ typedef struct sis_5511_t } sis_5511_t; static void -sis_5511_shadow_recalc(int cur_reg, sis_5511_t *dev) +sis_5511_shadow_recalc(sis_5511_t *dev) { - if (cur_reg == 0x86) - mem_set_mem_state_both(0xf0000, 0x10000, ((dev->pci_conf[cur_reg] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->pci_conf[cur_reg] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); - else - { - mem_set_mem_state_both(0xc0000 + ((cur_reg & 7) << 15), 0x4000, ((dev->pci_conf[cur_reg] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->pci_conf[cur_reg] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); - mem_set_mem_state_both(0xc4000 + ((cur_reg & 7) << 15), 0x4000, ((dev->pci_conf[cur_reg] & 8) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->pci_conf[cur_reg] & 2) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); - } + int i, state; + uint32_t base; - flushmmucache_nopc(); + for (i = 0x80; i <= 0x86; i++) { + if (i == 0x86) { + state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(0xf0000, 0x10000, state); + pclog("000F0000-000FFFFF\n"); + } else { + base = ((i & 0x07) << 15) + 0xc0000; + + state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(base, 0x4000, state); + pclog("%08X-%08X\n", base, base + 0x3fff); + + state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(base + 0x4000, 0x4000, state); + pclog("%08X-%08X\n", base + 0x4000, base + 0x7fff); + } + } + + flushmmucache_nopc(); } static void sis_5511_smram_recalc(sis_5511_t *dev) { - smram_disable_all(); + smram_disable_all(); - switch (dev->pci_conf[0x65] >> 6) - { - case 0: - smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); - break; - case 1: - smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); - break; - case 2: - smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); - break; - } + switch (dev->pci_conf[0x65] >> 6) { + case 0: + smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + case 1: + smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + case 2: + smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + } flushmmucache(); } + void sis_5513_ide_handler(sis_5511_t *dev) { ide_pri_disable(); @@ -140,31 +156,19 @@ void sis_5513_bm_handler(sis_5511_t *dev) sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE + 8); } + static void sis_5511_write(int func, int addr, uint8_t val, void *priv) { - sis_5511_t *dev = (sis_5511_t *)priv; + sis_5511_t *dev = (sis_5511_t *)priv; - switch (addr) - { - case 0x04: /* Command - low byte */ - dev->pci_conf[addr] = val; - break; - - case 0x05: /* Command - high byte */ - dev->pci_conf[addr] = val; - break; - - case 0x06: /* Status - Low Byte */ - dev->pci_conf[addr] &= val; - break; - - case 0x07: /* Status - High Byte */ - dev->pci_conf[addr] &= 0x16; + switch (addr) { + case 0x07: /* Status - High Byte */ + dev->pci_conf[addr] &= 0xb0; break; case 0x50: - dev->pci_conf[addr] = (val & 0xf9) | 4; + dev->pci_conf[addr] = val; cpu_cache_ext_enabled = !!(val & 0x40); cpu_update_waitstates(); break; @@ -177,8 +181,7 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x3f; break; - case 0x53: - case 0x54: + case 0x53: case 0x54: dev->pci_conf[addr] = val; break; @@ -186,15 +189,17 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0xf8; break; - case 0x57: - case 0x58: - case 0x59: + case 0x56 ... 0x59: dev->pci_conf[addr] = val; break; case 0x5a: + /* TODO: Fast Gate A20 Emulation and Fast Reset Emulation on the KBC. + The former (bit 7) means the chipset intercepts D1h to 64h and 00h to 60h. + The latter (bit 6) means the chipset intercepts all odd FXh to 64h. + Bit 5 sets fast reset latency. This should be fixed on the other SiS + chipsets as well. */ dev->pci_conf[addr] = val; - port_92_set_features(dev->port_92, !!(val & 0x40), !!(val & 0x80)); break; case 0x5b: @@ -214,22 +219,18 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) break; case 0x5f: - dev->pci_conf[addr] = val; + dev->pci_conf[addr] = val & 0xfe; break; case 0x60: dev->pci_conf[addr] = val & 0x3e; - if (!!(val & 2) && (dev->pci_conf[0x68] & 1)) - { + if ((dev->pci_conf[0x68] & 1) && (val & 2)) { smi_line = 1; dev->pci_conf[0x69] |= 1; } break; - case 0x61: /* STPCLK# Assertion Timer */ - case 0x62: /* STPCLK# De-assertion Timer */ - case 0x63: /* System Standby Timer */ - case 0x64: + case 0x61 ... 0x64: dev->pci_conf[addr] = val; break; @@ -242,8 +243,7 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x7f; break; - case 0x67: - case 0x68: + case 0x67: case 0x68: dev->pci_conf[addr] = val; break; @@ -251,11 +251,7 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[addr] &= val; break; - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: + case 0x6a ... 0x6e: dev->pci_conf[addr] = val; break; @@ -329,8 +325,7 @@ sis_5511_write(int func, int addr, uint8_t val, void *priv) case 0x85: case 0x86: dev->pci_conf[addr] = val & ((addr == 0x86) ? 0xe8 : 0xee); - sis_5511_shadow_recalc(addr, dev); - sis_5511_smram_recalc(dev); + sis_5511_shadow_recalc(dev); break; case 0x90: /* 5512 General Purpose Register Index */ @@ -620,24 +615,45 @@ sis_5513_isa_read(uint16_t addr, void *priv) return 0xff; } + static void sis_5511_reset(void *priv) { - sis_5511_t *dev = (sis_5511_t *)priv; + sis_5511_t *dev = (sis_5511_t *)priv; + + /* SiS 5511 */ + dev->pci_conf[0x00] = 0x39; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x11; + dev->pci_conf[0x03] = 0x55; + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x05] = dev->pci_conf[0x06] = 0x00; + dev->pci_conf[0x07] = 0x02; + dev->pci_conf[0x08] = 0x00; + dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00; + dev->pci_conf[0x52] = 0x20; + dev->pci_conf[0x53] = dev->pci_conf[0x54] = 0x00; + dev->pci_conf[0x55] = dev->pci_conf[0x56] = 0x00; + dev->pci_conf[0x57] = dev->pci_conf[0x58] = 0x00; + dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00; + dev->pci_conf[0x5b] = dev->pci_conf[0x5c] = 0x00; + dev->pci_conf[0x5d] = dev->pci_conf[0x5e] = 0x00; + dev->pci_conf[0x5f] = dev->pci_conf[0x60] = 0x00; + dev->pci_conf[0x61] = dev->pci_conf[0x62] = 0xff; + dev->pci_conf[0x63] = 0xff; + dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00; + dev->pci_conf[0x66] = 0x00; + dev->pci_conf[0x67] = 0xff; + dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00; + dev->pci_conf[0x6a] = dev->pci_conf[0x6b] = 0x00; + dev->pci_conf[0x6c] = dev->pci_conf[0x6d] = 0x00; + dev->pci_conf[0x6e] = dev->pci_conf[0x6f] = 0x00; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); - /* SiS 5511 */ - dev->pci_conf[0x00] = 0x39; - dev->pci_conf[0x01] = 0x10; - dev->pci_conf[0x02] = 0x11; - dev->pci_conf[0x03] = 0x55; - dev->pci_conf[0x04] = 7; - dev->pci_conf[0x07] = 2; - dev->pci_conf[0x0b] = 6; - dev->pci_conf[0x52] = 0x20; - dev->pci_conf[0x61] = 0xff; - dev->pci_conf[0x62] = 0xff; - dev->pci_conf[0x63] = 0xff; - dev->pci_conf[0x67] = 0xff; dev->pci_conf[0x6b] = 0xff; dev->pci_conf[0x6c] = 0xff; dev->pci_conf[0x70] = 4; @@ -652,6 +668,15 @@ sis_5511_reset(void *priv) dev->pci_conf[0x7c] = 4; dev->pci_conf[0x7e] = 4; dev->pci_conf[0x7f] = 0x80; + dev->pci_conf[0x80] = 0x00; + dev->pci_conf[0x81] = 0x00; + dev->pci_conf[0x82] = 0x00; + dev->pci_conf[0x83] = 0x00; + dev->pci_conf[0x84] = 0x00; + dev->pci_conf[0x85] = 0x00; + dev->pci_conf[0x86] = 0x00; + sis_5511_smram_recalc(dev); + sis_5511_shadow_recalc(dev); /* SiS 5513 */ dev->pci_conf_sb[0][0x00] = 0x39; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 1664576fb..14d7a9b63 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -124,6 +124,10 @@ int isa_cycles, cpu_inited, timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate, timing_misaligned; uint32_t cpu_features, cpu_fast_off_flags; +uint32_t _tr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint32_t cache_index = 0; +uint8_t _cache[2048]; + uint64_t cpu_CR4_mask, tsc = 0; uint64_t pmc[2] = {0, 0}; @@ -2290,6 +2294,7 @@ amd_k_invalid_rdmsr: EDX = tsc >> 32; break; } + pclog("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); break; case CPU_PENTIUMPRO: @@ -2695,6 +2700,7 @@ amd_k_invalid_wrmsr: case CPU_CxGX1: case CPU_Cx6x86MX: #endif + pclog("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); switch (ECX) { case 0x10: tsc = EAX | ((uint64_t)EDX << 32); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 68a053b6f..9beac3fab 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -542,6 +542,9 @@ extern uint64_t amd_efer, star; #define msw cpu_state.CR0.w extern uint32_t cr2, cr3, cr4; extern uint32_t dr[8]; +extern uint32_t _tr[8]; +extern uint32_t cache_index; +extern uint8_t _cache[2048]; /*Segments - diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 725d674e8..55ef45000 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -282,13 +282,13 @@ reset_common(int hard) if (is386 || hard) EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; - /* if (hard) { + if (hard) { makeznptable(); resetreadlookup(); makemod1table(); cpu_set_edx(); mmu_perm = 4; - } */ + } x86seg_reset(); #ifdef USE_DYNAREC if (hard) @@ -308,15 +308,19 @@ reset_common(int hard) if (hard) { if (is486) smbase = is_am486dxl ? 0x00060000 : 0x00030000; - // ppi_reset(); + ppi_reset(); } in_sys = 0; shadowbios = shadowbios_write = 0; alt_access = cpu_end_block_after_ins = 0; - if (hard) + if (hard) { reset_on_hlt = hlt_reset_pending = 0; + cache_index = 0; + memset(_tr, 0x00, sizeof(_tr)); + memset(_cache, 0x00, sizeof(_cache)); + } if (!is286) reset_808x(hard); @@ -328,15 +332,6 @@ void resetx86(void) { reset_common(1); -/* ---- */ - makeznptable(); - resetreadlookup(); - makemod1table(); - cpu_set_edx(); - mmu_perm = 4; - - ppi_reset(); -/* ---- */ soft_reset_mask = 0; } diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index a6e7e9193..e630c685b 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -607,6 +607,8 @@ static int opF7_l_a32(uint32_t fetchdat) static int opHLT(uint32_t fetchdat) { + pclog("HLT: CS = %04X, DS = %04X, ES = %04X, SS = %04X, IP = %04X\n", CS, DS, ES, SS, cpu_state.pc); + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x86gpf(NULL,0); diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 17f51b971..28504890c 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -256,54 +256,113 @@ static int opMOV_DRx_r_a32(uint32_t fetchdat) return 0; } +static void opMOV_r_TRx(void) +{ + uint32_t base; + + base = _tr[4] & 0xfffff800; + switch (cpu_reg) { + case 3: + pclog("[R] %08X cache = %08X\n", base + cache_index, _tr[3]); + _tr[3] = *(uint32_t *) &(_cache[cache_index]); + cache_index = (cache_index + 4) & 0xf; + break; + } + cpu_state.regs[cpu_rm].l = _tr[cpu_reg]; + CLOCK_CYCLES(6); +} static int opMOV_r_TRx_a16(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_16(fetchdat); - cpu_state.regs[cpu_rm].l = 0; - CLOCK_CYCLES(6); + opMOV_r_TRx(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); return 0; } static int opMOV_r_TRx_a32(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_32(fetchdat); - cpu_state.regs[cpu_rm].l = 0; - CLOCK_CYCLES(6); + opMOV_r_TRx(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); return 0; } +static void opMOV_TRx_r(void) +{ + uint32_t base; + int i, ctl; + + _tr[cpu_reg] = cpu_state.regs[cpu_rm].l; + base = _tr[4] & 0xfffff800; + ctl = _tr[5] & 3; + switch (cpu_reg) { + case 3: + pclog("[W] %08X cache = %08X\n", base + cache_index, _tr[3]); + *(uint32_t *) &(_cache[cache_index]) = _tr[3]; + cache_index = (cache_index + 4) & 0xf; + break; + case 4: + if (!(cr0 & 1) && !(_tr[5] & (1 << 19))) + pclog("TAG = %08X, DEST = %08X\n", base, base + cache_index - 16); + break; + case 5: + pclog("[16] EXT = %i (%i), SET = %04X\n", !!(_tr[5] & (1 << 19)), _tr[5] & 0x03, _tr[5] & 0x7f0); + if (!(_tr[5] & (1 << 19))) { + switch(ctl) { + case 0: + pclog(" Cache fill or read...\n", base); + break; + case 1: + base += (_tr[5] & 0x7f0); + pclog(" Writing 16 bytes to %08X...\n", base); + for (i = 0; i < 16; i += 4) + mem_writel_phys(base + i, *(uint32_t *) &(_cache[i])); + break; + case 2: + base += (_tr[5] & 0x7f0); + pclog(" Reading 16 bytes from %08X...\n", base); + for (i = 0; i < 16; i += 4) + *(uint32_t *) &(_cache[i]) = mem_readl_phys(base + i); + break; + case 3: + pclog(" Cache invalidate/flush...\n", base); + break; + } + } + break; + } + CLOCK_CYCLES(6); +} static int opMOV_TRx_r_a16(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_16(fetchdat); - CLOCK_CYCLES(6); + opMOV_TRx_r(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); return 0; } static int opMOV_TRx_r_a32(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } - fetch_ea_16(fetchdat); - CLOCK_CYCLES(6); + fetch_ea_32(fetchdat); + opMOV_TRx_r(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); return 0; } diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c index 5a07362d2..53fea5d92 100644 --- a/src/device/phoenix_486_jumper.c +++ b/src/device/phoenix_486_jumper.c @@ -39,11 +39,14 @@ typedef struct { - uint8_t jumper; + uint8_t type, jumper; } phoenix_486_jumper_t; + #ifdef ENABLE_PHOENIX_486_JUMPER_LOG int phoenix_486_jumper_do_log = ENABLE_PHOENIX_486_JUMPER_LOG; + + static void phoenix_486_jumper_log(const char *fmt, ...) { @@ -59,14 +62,19 @@ phoenix_486_jumper_log(const char *fmt, ...) #define phoenix_486_jumper_log(fmt, ...) #endif + static void phoenix_486_jumper_write(uint16_t addr, uint8_t val, void *priv) { phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; phoenix_486_jumper_log("Phoenix 486 Jumper: Write %02x\n", val); - dev->jumper = val; + if (dev->type == 1) + dev->jumper = val & 0xbf; + else + dev->jumper = val; } + static uint8_t phoenix_486_jumper_read(uint16_t addr, void *priv) { @@ -76,6 +84,21 @@ phoenix_486_jumper_read(uint16_t addr, void *priv) } +static void +phoenix_486_jumper_reset(void *priv) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; + + if (dev->type == 1) + dev->jumper = 0x00; + else { + dev->jumper = 0x9f; + if (gfxcard != 0x01) + dev->jumper |= 0x40; + } +} + + static void phoenix_486_jumper_close(void *priv) { @@ -84,26 +107,38 @@ phoenix_486_jumper_close(void *priv) free(dev); } + static void * phoenix_486_jumper_init(const device_t *info) { phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) malloc(sizeof(phoenix_486_jumper_t)); memset(dev, 0, sizeof(phoenix_486_jumper_t)); - dev->jumper = 0x9f; - if (gfxcard != 0x01) - dev->jumper |= 0x40; + dev->type = info->local; + + phoenix_486_jumper_reset(dev); io_sethandler(0x0078, 0x0001, phoenix_486_jumper_read, NULL, NULL, phoenix_486_jumper_write, NULL, NULL, dev); return dev; } + const device_t phoenix_486_jumper_device = { "Phoenix 486 Jumper Readout", 0, 0, - phoenix_486_jumper_init, phoenix_486_jumper_close, NULL, + phoenix_486_jumper_init, phoenix_486_jumper_close, phoenix_486_jumper_reset, + { NULL }, NULL, NULL, + NULL +}; + + +const device_t phoenix_486_jumper_pci_device = { + "Phoenix 486 Jumper Readout (PCI machines)", + 0, + 1, + phoenix_486_jumper_init, phoenix_486_jumper_close, phoenix_486_jumper_reset, { NULL }, NULL, NULL, NULL }; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index c12aec7e8..988717406 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -59,6 +59,9 @@ extern const device_t headland_ht18a_device; extern const device_t headland_ht18b_device; extern const device_t headland_ht18c_device; +/* IMS */ +extern const device_t ims8848_device; + /* Intel */ extern const device_t intel_82335_device; extern const device_t i420ex_device; @@ -162,7 +165,7 @@ extern const device_t wd76c10_device; /* Miscellaneous Hardware */ extern const device_t phoenix_486_jumper_device; -extern const device_t vpc2007_device; +extern const device_t phoenix_486_jumper_pci_device; #if defined(DEV_BRANCH) && defined(USE_OLIVETTI) extern const device_t olivetti_eva_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b3c875925..8fa2b2f12 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -366,6 +366,9 @@ extern int machine_at_ms4145_init(const machine_t *); extern int machine_at_sbc_490_init(const machine_t *); extern int machine_at_tf_486_init(const machine_t *); +extern int machine_at_pci400c_b_init(const machine_t *); +extern int machine_at_g486ip_init(const machine_t *); + extern int machine_at_itoxstar_init(const machine_t *); extern int machine_at_arb1423c_init(const machine_t *); extern int machine_at_arb1479_init(const machine_t *); diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 2bd76eb30..dfcbef242 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -89,6 +89,7 @@ /* Internal execute access, external read access. */ #define MEM_READ_EXTERNAL_EX 0 #define MEM_READ_SMRAM (ACCESS_X_SMRAM | ACCESS_R_SMRAM) +#define MEM_READ_CACHE (ACCESS_X_CACHE | ACCESS_R_CACHE) #define MEM_READ_SMRAM_EX (ACCESS_X_SMRAM) #define MEM_EXEC_SMRAM MEM_READ_SMRAM_EX #define MEM_READ_SMRAM_2 (ACCESS_R_SMRAM) @@ -104,6 +105,7 @@ #define MEM_WRITE_ROMCS (ACCESS_W_ROMCS) #define MEM_WRITE_EXTANY (ACCESS_W_ROMCS) #define MEM_WRITE_SMRAM (ACCESS_W_SMRAM) +#define MEM_WRITE_CACHE (ACCESS_W_CACHE) /* Theese two are going to be identical. */ #define MEM_WRITE_DISABLED_EX MEM_READ_DISABLED #define MEM_WRITE_MASK 0x03e0 diff --git a/src/include/86box/smram.h b/src/include/86box/smram.h index 3d91c1e96..6fc89971e 100644 --- a/src/include/86box/smram.h +++ b/src/include/86box/smram.h @@ -52,6 +52,8 @@ extern void smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, ui extern int smram_enabled(smram_t *smr); /* Changes the SMRAM state. */ extern void smram_state_change(smram_t *smr, int smm, int flags); +/* Enables or disables the use of a separate SMRAM for addresses below A0000. */ +extern void smram_set_separate_smram(uint8_t set); #endif /*EMU_SMRAM_H*/ diff --git a/src/io.c b/src/io.c index 742e601c4..21ea02f1b 100644 --- a/src/io.c +++ b/src/io.c @@ -319,6 +319,9 @@ inb(uint16_t port) if (port == 0x1ed) ret = 0xfe; + if (port == 0x2b60) + ret = 0x00; + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return(ret); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 2068b3c88..50718475b 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -66,7 +66,7 @@ machine_at_acc386_init(const machine_t *model) device_add(&keyboard_at_ami_device); if (fdc_type == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_device); return ret; } @@ -1147,6 +1147,68 @@ machine_at_486sp3_init(const machine_t *model) } +int +machine_at_pci400c_b_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pci400c-b/032295.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_isa_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 3, 2, 1); /* 0F = Slot 1 */ + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 0E = Slot 2 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 0D = Slot 3 */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 0C = Slot 4 */ + device_add(&keyboard_ps2_ami_pci_device); /* Assume AMI Megakey 1993 stanalone ('P') + because of the Tekram machine below. */ + + device_add(&ims8848_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_g486ip_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/g486ip/G486IP.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_isa_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 03 = Slot 1 */ + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 05 = Slot 3 */ + device_add(&keyboard_ps2_ami_pci_device); /* AMI Megakey 1993 stanalone ('P') */ + + device_add(&ims8848_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + int machine_at_486sp3g_init(const machine_t *model) { @@ -1623,8 +1685,10 @@ machine_at_hot433_init(const machine_t *model) device_add(&umc_hb4_device); device_add(&umc_8886af_device); device_add(&um8669f_device); - device_add(&intel_flash_bxt_device); - device_add(&keyboard_at_ami_device); + // device_add(&intel_flash_bxt_device); + device_add(&sst_flash_29ee010_device); + // device_add(&keyboard_at_ami_device); + device_add(&keyboard_ps2_ami_device); return ret; } @@ -1652,6 +1716,7 @@ machine_at_atc1415_init(const machine_t *model) device_add(&umc_hb4_device); device_add(&umc_8886af_device); + device_add(&intel_flash_bxt_device); device_add(&keyboard_at_ami_device); if (fdc_type == FDC_INTERNAL) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 6910a5274..3a57cf0c6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -432,6 +432,10 @@ const machine_t machines[] = { { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, /* This has the Phoenix MultiKey KBC firmware. */ { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, + /* This most likely has a standalone AMI Megakey 1993, which is type 'P', like the below Tekram board. */ + { "[IMS 8848] J-Bond PCI400C-B", "pci400c_b", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_pci400c_b_init, NULL }, + /* This has a standalone AMI Megakey 1993, which is type 'P'. */ + { "[IMS 8848] Tekram G486IP", "g486ip", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_g486ip_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ diff --git a/src/mem/smram.c b/src/mem/smram.c index 1173d716a..8e405af8a 100644 --- a/src/mem/smram.c +++ b/src/mem/smram.c @@ -32,6 +32,9 @@ static smram_t *base_smram, *last_smram; +static uint8_t use_separate_smram = 0; +static uint8_t smram[0x40000]; + #ifdef ENABLE_SMRAM_LOG int smram_do_log = ENABLE_SMRAM_LOG; @@ -61,8 +64,10 @@ smram_read(uint32_t addr, void *priv) if (new_addr >= (1 << 30)) return mem_read_ram_2gb(new_addr, priv); - else + else if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_ram(new_addr, priv); + else + return dev->mapping.exec[addr - dev->host_base]; } @@ -74,8 +79,10 @@ smram_readw(uint32_t addr, void *priv) if (new_addr >= (1 << 30)) return mem_read_ram_2gbw(new_addr, priv); - else + else if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_ramw(new_addr, priv); + else + return *(uint16_t *) &(dev->mapping.exec[addr - dev->host_base]); } @@ -87,8 +94,10 @@ smram_readl(uint32_t addr, void *priv) if (new_addr >= (1 << 30)) return mem_read_ram_2gbl(new_addr, priv); - else + else if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_raml(new_addr, priv); + else + return *(uint32_t *) &(dev->mapping.exec[addr - dev->host_base]); } @@ -98,7 +107,10 @@ smram_write(uint32_t addr, uint8_t val, void *priv) smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; - mem_write_ram(new_addr, val, priv); + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_ram(new_addr, val, priv); + else + dev->mapping.exec[addr - dev->host_base] = val; } @@ -108,7 +120,10 @@ smram_writew(uint32_t addr, uint16_t val, void *priv) smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; - mem_write_ramw(new_addr, val, priv); + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_ramw(new_addr, val, priv); + else + *(uint16_t *) &(dev->mapping.exec[addr - dev->host_base]) = val; } @@ -118,7 +133,10 @@ smram_writel(uint32_t addr, uint32_t val, void *priv) smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; - mem_write_raml(new_addr, val, priv); + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_raml(new_addr, val, priv); + else + *(uint32_t *) &(dev->mapping.exec[addr - dev->host_base]) = val; } @@ -263,6 +281,8 @@ smram_add(void) smram_write,smram_writew,smram_writel, ram, MEM_MAPPING_SMRAM, temp_smram); + smram_set_separate_smram(0); + return temp_smram; } @@ -326,10 +346,21 @@ smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, smr->size = size; mem_mapping_set_addr(&(smr->mapping), smr->host_base, smr->size); - if (smr->ram_base < (1 << 30)) - mem_mapping_set_exec(&(smr->mapping), ram + smr->ram_base); - else - mem_mapping_set_exec(&(smr->mapping), ram2 + smr->ram_base - (1 << 30)); + if (!use_separate_smram || (smr->ram_base >= 0x000a0000)) { + if (smr->ram_base < (1 << 30)) + mem_mapping_set_exec(&(smr->mapping), ram + smr->ram_base); + else + mem_mapping_set_exec(&(smr->mapping), ram2 + smr->ram_base - (1 << 30)); + } else { + if (smr->ram_base == 0x00030000) + mem_mapping_set_exec(&(smr->mapping), smram); + else if (smr->ram_base == 0x00040000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x10000); + else if (smr->ram_base == 0x00060000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x20000); + else if (smr->ram_base == 0x00070000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x30000); + } smram_map(0, host_base, size, flags_normal); smram_map(1, host_base, size, flags_smm); @@ -364,3 +395,10 @@ smram_state_change(smram_t *smr, int smm, int flags) smram_map(smm, smr->host_base, smr->size, flags); } + + +void +smram_set_separate_smram(uint8_t set) +{ + use_separate_smram = set; +} diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index f06c3d77a..b7680640f 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -593,7 +593,7 @@ CHIPSETOBJ := 82c100.o acc2168.o \ cs4031.o cs8230.o \ ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ gc100.o headland.o \ - intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ + ims8848.o intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ neat.o \ opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ scamp.o scat.o \ From cc043eed5d85f4627a3287f34b35440e4db2cb9c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 9 Oct 2021 17:38:27 +0200 Subject: [PATCH 087/140] Removed port 2B60 read. --- src/io.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/io.c b/src/io.c index 21ea02f1b..742e601c4 100644 --- a/src/io.c +++ b/src/io.c @@ -319,9 +319,6 @@ inb(uint16_t port) if (port == 0x1ed) ret = 0xfe; - if (port == 0x2b60) - ret = 0x00; - io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return(ret); From 7e15229524a0df6d0519bc19b0bf497b68083234 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 9 Oct 2021 22:32:56 +0200 Subject: [PATCH 088/140] Gave the UMC 8810 the required second SMRAM mirror at 4E0A0000-4E0BFFFF. --- src/chipset/umc_hb4.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index d147bf5f7..0948a228b 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -148,7 +148,7 @@ typedef struct hb4_t shadow_read, shadow_write, pci_conf[256]; /* PCI Registers */ int mem_state[9]; - smram_t *smram[2]; /* SMRAM Handlers */ + smram_t *smram[3]; /* SMRAM Handlers */ } hb4_t; @@ -237,7 +237,7 @@ void hb4_shadow(hb4_t *dev) { int n = 0; - pclog("SHADOW: %02X%02X\n", dev->pci_conf[0x55], dev->pci_conf[0x54]); + hb4_log("SHADOW: %02X%02X\n", dev->pci_conf[0x55], dev->pci_conf[0x54]); n = hb4_shadow_bios_high(dev); n += hb4_shadow_bios_low(dev); @@ -259,6 +259,8 @@ hb4_smram(hb4_t *dev) smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); /* There's a mirror of the SMRAM at 0E0A0000, mapped to A0000. */ smram_enable(dev->smram[1], 0x0e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + /* There's another mirror of the SMRAM at 4E0A0000, mapped to A0000. */ + smram_enable(dev->smram[2], 0x4e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); /* Bit 5 seems to set data to go to PCI and code to DRAM. The Samsung SPC7700P-LW uses this. */ @@ -274,7 +276,6 @@ static void hb4_write(int func, int addr, uint8_t val, void *priv) { hb4_t *dev = (hb4_t *)priv; - uint8_t old; hb4_log("UM8881: dev->regs[%02x] = %02x POST: %02x \n", addr, val, inb(0x80)); @@ -302,9 +303,8 @@ hb4_write(int func, int addr, uint8_t val, void *priv) break; case 0x53: - old = dev->pci_conf[addr]; dev->pci_conf[addr] = val; - pclog("HB53: %02X\n", val); + hb4_log("HB53: %02X\n", val); break; case 0x55: @@ -409,6 +409,7 @@ hb4_init(const device_t *info) /* SMRAM */ dev->smram[0] = smram_add(); dev->smram[1] = smram_add(); + dev->smram[2] = smram_add(); hb4_reset(dev); From 10a257749ffa163a7cb012fe766e3649438b6f67 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 19 Oct 2021 18:19:29 +0200 Subject: [PATCH 089/140] Fixed Intel PIIX and VIA PIPC trap SMI# function calls. --- src/chipset/intel_piix.c | 2 +- src/chipset/via_pipc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index a333c52b7..1a278a2c3 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -281,7 +281,7 @@ piix_trap_io(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) if (*(trap->en_reg) & trap->en_mask) { *(trap->sts_reg) |= trap->sts_mask; - acpi_raise_smi(trap->dev->acpi); + acpi_raise_smi(trap->dev->acpi, 1); } } diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index f3112974d..3829e337c 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -172,7 +172,7 @@ pipc_trap_io_pact(int size, uint16_t addr, uint8_t write, uint8_t val, void *pri *(trap->sts_reg) |= trap->mask; trap->dev->acpi->regs.glbsts |= 0x0001; if (trap->dev->acpi->regs.glben & 0x0001) - acpi_raise_smi(trap->dev->acpi); + acpi_raise_smi(trap->dev->acpi, 1); } } @@ -184,7 +184,7 @@ pipc_io_trap_glb(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv if (*(trap->en_reg) & trap->mask) { *(trap->sts_reg) |= trap->mask; - acpi_raise_smi(trap->dev->acpi); + acpi_raise_smi(trap->dev->acpi, 1); } } From 3ba9c8c9c6ddc08ac054aa464c68d01f95183c67 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 19 Oct 2021 18:23:48 +0200 Subject: [PATCH 090/140] A fix to acpi.c. --- src/acpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/acpi.c b/src/acpi.c index 0cb2fc9e2..0b9676c81 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -90,6 +90,8 @@ acpi_update_irq(acpi_t *dev) void acpi_raise_smi(void *priv, int do_smi) { + acpi_t *dev = (acpi_t *) priv; + if (dev->regs.glbctl & 0x01) { if ((dev->vendor == VEN_VIA) || (dev->vendor == VEN_VIA_596B)) { if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { From 77d73ed3c29e016dd45e112adec144a43e24ae07 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 26 Oct 2021 01:54:35 +0200 Subject: [PATCH 091/140] Finished the Intel 450KX, changes to the memory and SMRAM API's, removed the ASUS P/I-P6RP4 from the Dev branch, added the CMD646 PCI IDE controller, and fixed some bugs on the CMD640. --- src/chipset/CMakeLists.txt | 6 +- src/chipset/intel_i450kx.c | 630 ++++++++++++++++++--------- src/disk/CMakeLists.txt | 2 +- src/disk/hdc_ide_cmd640.c | 157 ++++--- src/disk/hdc_ide_cmd646.c | 435 ++++++++++++++++++ src/disk/hdc_ide_sff8038i.c | 24 +- src/include/86box/chipset.h | 4 +- src/include/86box/hdc.h | 3 + src/include/86box/hdc_ide_sff8038i.h | 11 +- src/include/86box/machine.h | 2 - src/include/86box/mem.h | 8 + src/include/86box/nvr.h | 1 + src/include/86box/smram.h | 7 + src/machine/CMakeLists.txt | 4 - src/machine/m_at_socket8.c | 14 +- src/machine/machine_table.c | 4 +- src/mem/mem.c | 6 + src/mem/smram.c | 35 +- src/nvr_at.c | 43 +- src/pci.c | 152 ++++++- src/scsi/scsi_cdrom.c | 9 +- src/win/Makefile.mingw | 17 +- 22 files changed, 1269 insertions(+), 305 deletions(-) create mode 100644 src/disk/hdc_ide_cmd646.c diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 770b54006..ce5bded9a 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -15,16 +15,12 @@ add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c ali1621.c ali6117.c headland.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c - intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.c + intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.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 via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c via_pipc.c vl82c480.c wd76c10.c) -if(I450KX) - target_sources(chipset PRIVATE intel_i450kx.c) -endif() - if(OLIVETTI) target_sources(chipset PRIVATE olivetti_eva.c) endif() \ No newline at end of file diff --git a/src/chipset/intel_i450kx.c b/src/chipset/intel_i450kx.c index 5a89f2659..2696db495 100644 --- a/src/chipset/intel_i450kx.c +++ b/src/chipset/intel_i450kx.c @@ -58,71 +58,95 @@ i450kx_log(const char *fmt, ...) #endif -/* Shadow RAM Flags */ -#define LSB_DECISION (((shadow_value & 1) ? MEM_READ_EXTANY : MEM_READ_INTERNAL) | ((shadow_value & 2) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL)) -#define MSB_DECISION (((shadow_value & 0x10) ? MEM_READ_EXTANY : MEM_READ_INTERNAL) | ((shadow_value & 0x20) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL)) -#define LSB_DECISION_MC (((shadow_value & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((shadow_value & 2) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)) -#define MSB_DECISION_MC (((shadow_value & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((shadow_value & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)) - -/* SMRAM */ -#define SMRAM_ADDR (((dev->pb_pci_conf[0xb9] << 8) | dev->pb_pci_conf[0xb8]) << 17) -#define SMRAM_ADDR_MC (((dev->mc_pci_conf[0xb9] << 8) | dev->mc_pci_conf[0xb8]) << 16) -#define SMRAM_SIZE (((dev->pb_pci_conf[0xbb] >> 4) + 1) * 64) -#define SMRAM_SIZE_MC (((dev->mc_pci_conf[0xbb] >> 4) + 1) * 64) - -/* Miscellaneous */ -#define ENABLE_SEGMENT (MEM_READ_EXTANY | MEM_WRITE_EXTANY) -#define DISABLE_SEGMENT (MEM_READ_DISABLED | MEM_WRITE_DISABLED) - - +/* TODO: Finish the bus index stuff. */ typedef struct i450kx_t { - smram_t *smram; + smram_t * smram[2]; - uint8_t pb_pci_conf[256], mc_pci_conf[256]; + uint8_t pb_pci_conf[256], mc_pci_conf[256]; + uint8_t mem_state[2][256]; + + uint8_t bus_index; } i450kx_t; static void -i450kx_shadow(int is_mc, int cur_reg, uint8_t shadow_value, i450kx_t *dev) +i450kx_map(i450kx_t *dev, int bus, uint32_t addr, uint32_t size, int state) { - if (cur_reg == 0x59) { - mem_set_mem_state_both(0x80000, 0x20000, (is_mc) ? LSB_DECISION_MC : LSB_DECISION); - mem_set_mem_state_both(0xf0000, 0x10000, (is_mc) ? MSB_DECISION_MC : MSB_DECISION); - } else { - mem_set_mem_state_both(0xc0000 + (((cur_reg & 7) - 2) * 0x8000), 0x4000, (is_mc) ? LSB_DECISION_MC : LSB_DECISION); - mem_set_mem_state_both(0xc4000 + (((cur_reg & 7) - 2) * 0x8000), 0x4000, (is_mc) ? MSB_DECISION_MC : MSB_DECISION); + uint32_t base = addr >> 12; + int states[4] = { MEM_READ_EXTANY | MEM_WRITE_EXTANY, MEM_READ_INTERNAL | MEM_WRITE_EXTANY, + MEM_READ_EXTANY | MEM_WRITE_INTERNAL, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL }; + + state &= 3; + if (dev->mem_state[bus][base] != state) { + if (bus) + mem_set_mem_state_bus_both(addr, size, states[state]); + else + mem_set_mem_state_cpu_both(addr, size, states[state]); + dev->mem_state[bus][base] = state; + flushmmucache_nopc(); } - flushmmucache_nopc(); } static void -i450kx_smm(uint32_t smram_addr, uint32_t smram_size, i450kx_t *dev) +i450kx_smram_recalc(i450kx_t *dev, int bus) { - smram_disable_all(); + uint8_t *regs = bus ? dev->pb_pci_conf : dev->mc_pci_conf; + uint32_t addr, size; - if ((smram_addr != 0) && !!(dev->mc_pci_conf[0x57] & 8)) - smram_enable(dev->smram, smram_addr, smram_addr, smram_size, !!(dev->pb_pci_conf[0x57] & 8), 1); + smram_disable(dev->smram[bus]); + + addr = ((uint32_t) regs[0xb8] << 16) | ((uint32_t) regs[0xb9] << 24); + size = (((uint32_t) ((regs[0xbb] >> 4) & 0x0f)) << 16) + 0x00010000; + + if ((addr != 0x00000000) && !!(regs[0x57] & 0x08)) { + if (bus) + smram_enable_ex(dev->smram[bus], addr, addr, size, 0, !!(regs[0x57] & 8), 0, 1); + else + smram_enable_ex(dev->smram[bus], addr, addr, size, !!(regs[0x57] & 8), 0, 1, 0); + } flushmmucache(); } +static void +i450kx_vid_buf_recalc(i450kx_t *dev, int bus) +{ + uint8_t *regs = bus ? dev->pb_pci_conf : dev->mc_pci_conf; + + // int state = (regs[0x58] & 0x02) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_DISABLED | MEM_WRITE_DISABLED); + int state = (regs[0x58] & 0x02) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + if (bus) + mem_set_mem_state_bus_both(0x000a0000, 0x00020000, state); + else + mem_set_mem_state_cpu_both(0x000a0000, 0x00020000, state); + + flushmmucache_nopc(); +} + + static void pb_write(int func, int addr, uint8_t val, void *priv) { i450kx_t *dev = (i450kx_t *)priv; - switch (addr) { - case 0x04: - dev->pb_pci_conf[addr] &= val & 0xd7; - break; + // pclog("i450KX-PB: [W] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + i450kx_log("i450KX-PB: [W] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); - case 0x06: - dev->pb_pci_conf[addr] = val & 0x80; + if (func == 0) switch (addr) { + case 0x04: + dev->pb_pci_conf[addr] = (dev->pb_pci_conf[addr] & 0x04) | (val & 0x53); + break; + case 0x05: + dev->pb_pci_conf[addr] = val & 0x01; break; case 0x07: + dev->pb_pci_conf[addr] &= ~(val & 0xf9); + break; + case 0x0d: dev->pb_pci_conf[addr] = val; break; @@ -131,63 +155,106 @@ pb_write(int func, int addr, uint8_t val, void *priv) dev->pb_pci_conf[addr] = val & 0xcf; break; - case 0x40: - case 0x41: + case 0x40: case 0x41: dev->pb_pci_conf[addr] = val; break; - case 0x43: dev->pb_pci_conf[addr] = val & 0x80; break; case 0x48: - dev->pb_pci_conf[addr] = val & 6; + dev->pb_pci_conf[addr] = val & 0x06; break; - case 0x4a: - case 0x4b: + case 0x4a: case 0x4b: dev->pb_pci_conf[addr] = val; + // if (addr == 0x4a) + // pci_remap_bus(dev->bus_index, val); break; case 0x4c: - dev->pb_pci_conf[addr] = val & 0xd8; + dev->pb_pci_conf[addr] = (dev->pb_pci_conf[addr] & 0x01) | (val & 0xd8); + break; + + case 0x51: + dev->pb_pci_conf[addr] = val; break; case 0x53: - dev->pb_pci_conf[addr] = val & 2; + dev->pb_pci_conf[addr] = val & 0x02; break; case 0x54: dev->pb_pci_conf[addr] = val & 0x7b; break; - case 0x55: - dev->pb_pci_conf[addr] = val & 2; + dev->pb_pci_conf[addr] = val & 0x03; break; case 0x57: - dev->pb_pci_conf[addr] = val & 8; - i450kx_smm(SMRAM_ADDR, SMRAM_SIZE, dev); + dev->pb_pci_conf[addr] = val & 0x08; + i450kx_smram_recalc(dev, 1); break; case 0x58: - dev->pb_pci_conf[addr] = val & 2; - mem_set_mem_state_both(0xa0000, 0x20000, (val & 2) ? ENABLE_SEGMENT : DISABLE_SEGMENT); + dev->pb_pci_conf[addr] = val & 0x02; + i450kx_vid_buf_recalc(dev, 1); break; - case 0x59: - case 0x5a: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: - dev->pb_pci_conf[addr] = val & 0x33; - i450kx_shadow(0, addr, val, dev); + case 0x59: /* PAM0 */ + if ((dev->pb_pci_conf[0x59] ^ val) & 0x0f) + i450kx_map(dev, 1, 0x80000, 0x20000, val & 0x0f); + if ((dev->pb_pci_conf[0x59] ^ val) & 0xf0) { + i450kx_map(dev, 1, 0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + dev->pb_pci_conf[0x59] = val & 0x33; + break; + case 0x5a: /* PAM1 */ + if ((dev->pb_pci_conf[0x5a] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xc0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5a] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xc4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5a] = val & 0x33; + break; + case 0x5b: /*PAM2 */ + if ((dev->pb_pci_conf[0x5b] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xc8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5b] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xcc000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5b] = val & 0x33; + break; + case 0x5c: /*PAM3 */ + if ((dev->pb_pci_conf[0x5c] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xd0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5c] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xd4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5c] = val & 0x33; + break; + case 0x5d: /* PAM4 */ + if ((dev->pb_pci_conf[0x5d] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xd8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5d] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xdc000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5d] = val & 0x33; + break; + case 0x5e: /* PAM5 */ + if ((dev->pb_pci_conf[0x5e] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xe0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5e] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xe4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5e] = val & 0x33; + break; + case 0x5f: /* PAM6 */ + if ((dev->pb_pci_conf[0x5f] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xe8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5f] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xec000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5f] = val & 0x33; break; case 0x70: - dev->pb_pci_conf[addr] = val & 0xfc; + dev->pb_pci_conf[addr] = val & 0xf8; break; case 0x71: @@ -197,47 +264,49 @@ pb_write(int func, int addr, uint8_t val, void *priv) case 0x78: dev->pb_pci_conf[addr] = val & 0xf0; break; - case 0x79: dev->pb_pci_conf[addr] = val & 0xfc; break; - - case 0x7c: - dev->pb_pci_conf[addr] = val & 0x5f; + case 0x7a: + dev->pb_pci_conf[addr] = val; + break; + case 0x7b: + dev->pb_pci_conf[addr] = val & 0x0f; break; + case 0x7c: + dev->pb_pci_conf[addr] = val & 0x9f; + break; case 0x7d: dev->pb_pci_conf[addr] = val & 0x1a; break; - case 0x7e: dev->pb_pci_conf[addr] = val & 0xf0; break; - case 0x7f: - case 0x88: - case 0x89: - case 0x8a: dev->pb_pci_conf[addr] = val; break; + case 0x88: case 0x89: + dev->pb_pci_conf[addr] = val; + break; case 0x8b: dev->pb_pci_conf[addr] = val & 0x80; break; - - case 0x9c: - dev->pb_pci_conf[addr] = val & 1; - break; - - case 0xa4: - dev->pb_pci_conf[addr] = val & 0xf9; - break; - - case 0xa5: - case 0xa6: + case 0x8c: case 0x8d: dev->pb_pci_conf[addr] = val; break; + case 0x9c: + dev->pb_pci_conf[addr] = val & 0x01; + break; + + case 0xa4: + dev->pb_pci_conf[addr] = val & 0xf8; + break; + case 0xa5: case 0xa6: + dev->pb_pci_conf[addr] = val; + break; case 0xa7: dev->pb_pci_conf[addr] = val & 0x0f; break; @@ -245,36 +314,45 @@ pb_write(int func, int addr, uint8_t val, void *priv) case 0xb0: dev->pb_pci_conf[addr] = val & 0xe0; break; - case 0xb1: - dev->pb_pci_conf[addr] = val & 0x1f; + dev->pb_pci_conf[addr] = val & /*0x1a*/ 0x1f; break; case 0xb4: - dev->pb_pci_conf[addr] = val & 0xe8; + dev->pb_pci_conf[addr] = val & 0xe0; break; - case 0xb5: dev->pb_pci_conf[addr] = val & 0x1f; break; - case 0xb8: - case 0xb9: + case 0xb8: case 0xb9: + dev->pb_pci_conf[addr] = val; + i450kx_smram_recalc(dev, 1); + break; case 0xbb: - dev->pb_pci_conf[addr] = !(addr == 0xbb) ? val : (val & 0xf0); - i450kx_smm(SMRAM_ADDR, SMRAM_SIZE, dev); + dev->pb_pci_conf[addr] = val & 0xf0; + i450kx_smram_recalc(dev, 1); + break; + + case 0xbc: + dev->pb_pci_conf[addr] = val & 0x11; + break; + + case 0xc0: + dev->pb_pci_conf[addr] = val & 0xdf; + break; + case 0xc1: + dev->pb_pci_conf[addr] = val & 0x3f; break; case 0xc4: - dev->pb_pci_conf[addr] = val & 5; + dev->pb_pci_conf[addr] &= ~(val & 0x0f); break; - case 0xc5: - dev->pb_pci_conf[addr] = val & 0x0a; + dev->pb_pci_conf[addr] &= ~(val & 0x0a); break; - case 0xc6: - dev->pb_pci_conf[addr] = val & 0x1d; + dev->pb_pci_conf[addr] &= ~(val & 0x1f); break; case 0xc8: @@ -286,7 +364,6 @@ pb_write(int func, int addr, uint8_t val, void *priv) dev->pb_pci_conf[addr] = val; break; } - i450kx_log("i450KX-PB: dev->regs[%02x] = %02x POST: %02x\n", addr, dev->pb_pci_conf[addr], inb(0x80)); } @@ -294,7 +371,30 @@ static uint8_t pb_read(int func, int addr, void *priv) { i450kx_t *dev = (i450kx_t *)priv; - return dev->pb_pci_conf[addr]; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->pb_pci_conf[addr]; + + // pclog("i450KX-PB: [R] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, ret, inb(0x80)); + + return ret; +} + + +/* A way to use spd_write_drbs_interlaved() and convert the output to what we need. */ +static void +mc_fill_drbs(i450kx_t *dev) +{ + int i; + + spd_write_drbs_interleaved(dev->mc_pci_conf, 0x60, 0x6f, 4); + for (i = 0x60; i <= 0x6f; i++) { + if (i & 0x01) + dev->mc_pci_conf[i] = 0x00; + else + dev->mc_pci_conf[i] &= 0x7f; + } } @@ -303,75 +403,97 @@ mc_write(int func, int addr, uint8_t val, void *priv) { i450kx_t *dev = (i450kx_t *)priv; - switch (addr) - { + // pclog("i450KX-MC: [W] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + i450kx_log("i450KX-MC: [W] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + + if (func == 0) switch (addr) { case 0x4c: dev->mc_pci_conf[addr] = val & 0xdf; break; - case 0x4d: - dev->mc_pci_conf[addr] = val & 0xdf; + dev->mc_pci_conf[addr] = val & 0xff; break; case 0x57: - dev->mc_pci_conf[addr] = val & 8; - i450kx_smm(SMRAM_ADDR, SMRAM_SIZE, dev); + dev->mc_pci_conf[addr] = val & 0x08; + i450kx_smram_recalc(dev, 0); break; case 0x58: - dev->mc_pci_conf[addr] = val & 2; + dev->mc_pci_conf[addr] = val & 0x02; + i450kx_vid_buf_recalc(dev, 0); break; - case 0x59: - case 0x5a: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: - dev->mc_pci_conf[addr] = val & 0x33; - i450kx_shadow(1, addr, val, dev); + case 0x59: /* PAM0 */ + if ((dev->mc_pci_conf[0x59] ^ val) & 0x0f) + i450kx_map(dev, 0, 0x80000, 0x20000, val & 0x0f); + if ((dev->mc_pci_conf[0x59] ^ val) & 0xf0) { + i450kx_map(dev, 0, 0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + dev->mc_pci_conf[0x59] = val & 0x33; + break; + case 0x5a: /* PAM1 */ + if ((dev->mc_pci_conf[0x5a] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xc0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5a] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xc4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5a] = val & 0x33; + break; + case 0x5b: /*PAM2 */ + if ((dev->mc_pci_conf[0x5b] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xc8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5b] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xcc000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5b] = val & 0x33; + break; + case 0x5c: /*PAM3 */ + if ((dev->mc_pci_conf[0x5c] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xd0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5c] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xd4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5c] = val & 0x33; + break; + case 0x5d: /* PAM4 */ + if ((dev->mc_pci_conf[0x5d] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xd8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5d] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xdc000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5d] = val & 0x33; + break; + case 0x5e: /* PAM5 */ + if ((dev->mc_pci_conf[0x5e] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xe0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5e] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xe4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5e] = val & 0x33; + break; + case 0x5f: /* PAM6 */ + if ((dev->mc_pci_conf[0x5f] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xe8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5f] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xec000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5f] = val & 0x33; break; - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - dev->mc_pci_conf[addr] = ((addr & 0x0f) % 2) ? 0 : (val & 0x7f); - spd_write_drbs(dev->mc_pci_conf, 0x60, 0x6f, 4); + case 0x60 ... 0x6f: + dev->mc_pci_conf[addr] = ((addr & 0x0f) & 0x01) ? 0x00 : (val & 0x7f); + mc_fill_drbs(dev); break; - case 0x74: - case 0x75: - case 0x76: - case 0x77: + case 0x74 ... 0x77: dev->mc_pci_conf[addr] = val; break; case 0x78: dev->mc_pci_conf[addr] = val & 0xf0; break; - case 0x79: dev->mc_pci_conf[addr] = val & 0xfe; break; - case 0x7a: dev->mc_pci_conf[addr] = val; break; - case 0x7b: dev->mc_pci_conf[addr] = val & 0x0f; break; @@ -379,45 +501,36 @@ mc_write(int func, int addr, uint8_t val, void *priv) case 0x7c: dev->mc_pci_conf[addr] = val & 0x1f; break; - case 0x7d: dev->mc_pci_conf[addr] = val & 0x0c; break; - case 0x7e: dev->mc_pci_conf[addr] = val & 0xf0; break; - case 0x7f: dev->mc_pci_conf[addr] = val; break; - case 0x88: - case 0x89: + case 0x88: case 0x89: dev->mc_pci_conf[addr] = val; break; - case 0x8b: dev->mc_pci_conf[addr] = val & 0x80; break; - case 0x8c: - case 0x8d: + case 0x8c: case 0x8d: dev->mc_pci_conf[addr] = val; break; case 0xa4: - dev->mc_pci_conf[addr] = val & 1; + dev->mc_pci_conf[addr] = val & 0x01; break; - case 0xa5: dev->pb_pci_conf[addr] = val & 0xf0; break; - case 0xa6: dev->mc_pci_conf[addr] = val; break; - case 0xa7: dev->mc_pci_conf[addr] = val & 0x0f; break; @@ -425,49 +538,56 @@ mc_write(int func, int addr, uint8_t val, void *priv) case 0xa8: dev->mc_pci_conf[addr] = val & 0xfe; break; - - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: + case 0xa9 ... 0xab: dev->mc_pci_conf[addr] = val; break; + case 0xac ... 0xae: + dev->mc_pci_conf[addr] = val; + break; case 0xaf: dev->mc_pci_conf[addr] = val & 0x7f; break; - case 0xb8: - case 0xb9: + case 0xb8: case 0xb9: + dev->mc_pci_conf[addr] = val; + i450kx_smram_recalc(dev, 0); + break; case 0xbb: - dev->mc_pci_conf[addr] = !(addr == 0xbb) ? val : (val & 0xf0); - - i450kx_smm(SMRAM_ADDR_MC, SMRAM_SIZE_MC, dev); + dev->mc_pci_conf[addr] = val & 0xf0; + i450kx_smram_recalc(dev, 0); break; case 0xbc: - dev->mc_pci_conf[addr] = val & 1; + dev->mc_pci_conf[addr] = val & 0x01; break; case 0xc0: - dev->mc_pci_conf[addr] = val & 7; + dev->mc_pci_conf[addr] = val & 0x07; break; case 0xc2: - dev->mc_pci_conf[addr] = val & 3; + dev->mc_pci_conf[addr] &= ~(val & 0x03); break; case 0xc4: - dev->mc_pci_conf[addr] = val & 0x3f; + dev->mc_pci_conf[addr] = val & 0xbf; + break; + case 0xc5: + dev->mc_pci_conf[addr] = val & 0x03; break; case 0xc6: - dev->mc_pci_conf[addr] = val & 0x19; + dev->mc_pci_conf[addr] &= ~(val & 0x19); + break; + + case 0xc8: + dev->mc_pci_conf[addr] = val & 0x1f; + break; + case 0xca: case 0xcb: + dev->mc_pci_conf[addr] = val; break; } - i450kx_log("i450KX-MC: dev->regs[%02x] = %02x POST: %02x\n", addr, dev->mc_pci_conf[addr], inb(0x80)); } @@ -475,7 +595,14 @@ static uint8_t mc_read(int func, int addr, void *priv) { i450kx_t *dev = (i450kx_t *)priv; - return dev->mc_pci_conf[addr]; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->mc_pci_conf[addr]; + + // pclog("i450KX-MC: [R] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, ret, inb(0x80)); + + return ret; } @@ -483,57 +610,168 @@ static void i450kx_reset(void *priv) { i450kx_t *dev = (i450kx_t *)priv; + uint32_t i; - /* CONFLICTS WARNING! We do not program anything on reset due to that */ + // pclog("i450KX: i450kx_reset()\n"); /* Defaults PB */ dev->pb_pci_conf[0x00] = 0x86; dev->pb_pci_conf[0x01] = 0x80; dev->pb_pci_conf[0x02] = 0xc4; dev->pb_pci_conf[0x03] = 0x84; - dev->pb_pci_conf[0x05] = 4; + dev->pb_pci_conf[0x04] = 0x07; + dev->pb_pci_conf[0x05] = 0x00; dev->pb_pci_conf[0x06] = 0x40; - dev->pb_pci_conf[0x07] = 2; - dev->pb_pci_conf[0x08] = 2; - dev->pb_pci_conf[0x0b] = 6; - dev->pb_pci_conf[0x0c] = 8; + dev->pb_pci_conf[0x07] = 0x02; + dev->pb_pci_conf[0x08] = 0x02; + dev->pb_pci_conf[0x09] = 0x00; + dev->pb_pci_conf[0x0a] = 0x00; + dev->pb_pci_conf[0x0b] = 0x06; + dev->pb_pci_conf[0x0c] = 0x08; dev->pb_pci_conf[0x0d] = 0x20; - dev->pb_pci_conf[0x49] = 0x14; - dev->pb_pci_conf[0x4c] = 0x39; - dev->pb_pci_conf[0x58] = 2; - dev->pb_pci_conf[0x59] = 0x30; - dev->pb_pci_conf[0x5a] = 0x33; - dev->pb_pci_conf[0x5b] = 0x33; - dev->pb_pci_conf[0x5c] = 0x33; - dev->pb_pci_conf[0x5d] = 0x33; - dev->pb_pci_conf[0x5e] = 0x33; - dev->pb_pci_conf[0x5f] = 0x33; - dev->pb_pci_conf[0xa4] = 1; + dev->pb_pci_conf[0x0e] = 0x00; + dev->pb_pci_conf[0x0f] = 0x00; + dev->pb_pci_conf[0x40] = 0x00; + dev->pb_pci_conf[0x41] = 0x00; + dev->pb_pci_conf[0x42] = 0x00; + dev->pb_pci_conf[0x43] = 0x00; + dev->pb_pci_conf[0x48] = 0x06; + dev->pb_pci_conf[0x49] = 0x19; + dev->pb_pci_conf[0x4a] = 0x00; + dev->pb_pci_conf[0x4b] = 0x00; + dev->pb_pci_conf[0x4c] = 0x19; + dev->pb_pci_conf[0x51] = 0x80; + dev->pb_pci_conf[0x53] = 0x00; + dev->pb_pci_conf[0x54] = 0x00; + dev->pb_pci_conf[0x55] = 0x00; + dev->pb_pci_conf[0x57] = 0x00; + dev->pb_pci_conf[0x58] = 0x02; + dev->pb_pci_conf[0x70] = 0x00; + dev->pb_pci_conf[0x71] = 0x00; + dev->pb_pci_conf[0x78] = 0x00; + dev->pb_pci_conf[0x79] = 0x00; + dev->pb_pci_conf[0x7a] = 0x00; + dev->pb_pci_conf[0x7b] = 0x00; + dev->pb_pci_conf[0x7c] = 0x00; + dev->pb_pci_conf[0x7d] = 0x00; + dev->pb_pci_conf[0x7e] = 0x00; + dev->pb_pci_conf[0x7f] = 0x00; + dev->pb_pci_conf[0x88] = 0x00; + dev->pb_pci_conf[0x89] = 0x00; + dev->pb_pci_conf[0x8a] = 0x00; + dev->pb_pci_conf[0x8b] = 0x00; + dev->pb_pci_conf[0x8c] = 0x00; + dev->pb_pci_conf[0x8d] = 0x00; + dev->pb_pci_conf[0x8e] = 0x00; + dev->pb_pci_conf[0x8f] = 0x00; + dev->pb_pci_conf[0x9c] = 0x00; + dev->pb_pci_conf[0xa4] = 0x01; dev->pb_pci_conf[0xa5] = 0xc0; dev->pb_pci_conf[0xa6] = 0xfe; - dev->pb_pci_conf[0xc8] = 3; - dev->pb_pci_conf[0xb8] = 5; + dev->pb_pci_conf[0xa7] = 0x00; + /* Note: Do NOT reset these two registers on programmed (TRC) hard reset! */ + // dev->pb_pci_conf[0xb0] = 0x00; + // dev->pb_pci_conf[0xb1] = 0x00; + dev->pb_pci_conf[0xb4] = 0x00; + dev->pb_pci_conf[0xb5] = 0x00; + dev->pb_pci_conf[0xb8] = 0x05; + dev->pb_pci_conf[0xb9] = 0x00; + dev->pb_pci_conf[0xba] = 0x00; + dev->pb_pci_conf[0xbb] = 0x00; + dev->pb_pci_conf[0xbc] = 0x01; + dev->pb_pci_conf[0xc0] = 0x02; + dev->pb_pci_conf[0xc1] = 0x00; + dev->pb_pci_conf[0xc2] = 0x00; + dev->pb_pci_conf[0xc3] = 0x00; + dev->pb_pci_conf[0xc4] = 0x00; + dev->pb_pci_conf[0xc5] = 0x00; + dev->pb_pci_conf[0xc6] = 0x00; + dev->pb_pci_conf[0xc7] = 0x00; + dev->pb_pci_conf[0xc8] = 0x03; + dev->pb_pci_conf[0xc9] = 0x00; + dev->pb_pci_conf[0xca] = 0x00; + dev->pb_pci_conf[0xcb] = 0x00; + + // pci_remap_bus(dev->bus_index, 0x00); + i450kx_smram_recalc(dev, 1); + i450kx_vid_buf_recalc(dev, 1); + pb_write(0, 0x59, 0x30, dev); + for (i = 0x5a; i <= 0x5f; i++) + pb_write(0, i, 0x33, dev); /* Defaults MC */ dev->mc_pci_conf[0x00] = 0x86; dev->mc_pci_conf[0x01] = 0x80; dev->mc_pci_conf[0x02] = 0xc5; dev->mc_pci_conf[0x03] = 0x84; + dev->mc_pci_conf[0x04] = 0x00; + dev->mc_pci_conf[0x05] = 0x00; dev->mc_pci_conf[0x06] = 0x80; - dev->mc_pci_conf[0x08] = 4; - dev->mc_pci_conf[0x0b] = 5; + dev->mc_pci_conf[0x07] = 0x00; + dev->mc_pci_conf[0x08] = 0x04; + dev->mc_pci_conf[0x09] = 0x00; + dev->mc_pci_conf[0x0a] = 0x00; + dev->mc_pci_conf[0x0b] = 0x05; dev->mc_pci_conf[0x49] = 0x14; dev->mc_pci_conf[0x4c] = 0x0b; + dev->mc_pci_conf[0x4d] = 0x08; + dev->mc_pci_conf[0x4e] = 0x00; + dev->mc_pci_conf[0x4f] = 0x00; + dev->mc_pci_conf[0x57] = 0x00; + dev->mc_pci_conf[0x58] = 0x00; + dev->mc_pci_conf[0x74] = 0x00; + dev->mc_pci_conf[0x75] = 0x00; + dev->mc_pci_conf[0x76] = 0x00; + dev->mc_pci_conf[0x77] = 0x00; dev->mc_pci_conf[0x78] = 0x10; - dev->mc_pci_conf[0xa4] = 1; + dev->mc_pci_conf[0x79] = 0x00; + dev->mc_pci_conf[0x7a] = 0x00; + dev->mc_pci_conf[0x7b] = 0x00; + dev->mc_pci_conf[0x7c] = 0x00; + dev->mc_pci_conf[0x7d] = 0x00; + dev->mc_pci_conf[0x7e] = 0x10; + dev->mc_pci_conf[0x7f] = 0x00; + dev->mc_pci_conf[0x88] = 0x00; + dev->mc_pci_conf[0x89] = 0x00; + dev->mc_pci_conf[0x8a] = 0x00; + dev->mc_pci_conf[0x8b] = 0x00; + dev->mc_pci_conf[0x8c] = 0x00; + dev->mc_pci_conf[0x8d] = 0x00; + dev->mc_pci_conf[0x8e] = 0x00; + dev->mc_pci_conf[0x8f] = 0x00; + dev->mc_pci_conf[0xa4] = 0x01; dev->mc_pci_conf[0xa5] = 0xc0; dev->mc_pci_conf[0xa6] = 0xfe; + dev->mc_pci_conf[0xa7] = 0x00; + dev->mc_pci_conf[0xa8] = 0x00; + dev->mc_pci_conf[0xa9] = 0x00; + dev->mc_pci_conf[0xaa] = 0x00; + dev->mc_pci_conf[0xab] = 0x00; dev->mc_pci_conf[0xac] = 0x16; dev->mc_pci_conf[0xad] = 0x35; dev->mc_pci_conf[0xae] = 0xdf; dev->mc_pci_conf[0xaf] = 0x30; dev->mc_pci_conf[0xb8] = 0x0a; - dev->mc_pci_conf[0xbc] = 1; + dev->mc_pci_conf[0xb9] = 0x00; + dev->mc_pci_conf[0xba] = 0x00; + dev->mc_pci_conf[0xbb] = 0x00; + dev->mc_pci_conf[0xbc] = 0x01; + dev->mc_pci_conf[0xc0] = 0x00; + dev->mc_pci_conf[0xc1] = 0x00; + dev->mc_pci_conf[0xc2] = 0x00; + dev->mc_pci_conf[0xc3] = 0x00; + dev->mc_pci_conf[0xc4] = 0x00; + dev->mc_pci_conf[0xc5] = 0x00; + dev->mc_pci_conf[0xc6] = 0x00; + dev->mc_pci_conf[0xc7] = 0x00; + + i450kx_smram_recalc(dev, 0); + i450kx_vid_buf_recalc(dev, 0); + mc_write(0, 0x59, 0x03, dev); + for (i = 0x5a; i <= 0x5f; i++) + mc_write(0, i, 0x00, dev); + for (i = 0x60; i <= 0x6f; i++) + dev->mc_pci_conf[i] = 0x01; } @@ -542,7 +780,8 @@ i450kx_close(void *priv) { i450kx_t *dev = (i450kx_t *)priv; - smram_del(dev->smram); + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); free(dev); } @@ -552,10 +791,11 @@ i450kx_init(const device_t *info) { i450kx_t *dev = (i450kx_t *)malloc(sizeof(i450kx_t)); memset(dev, 0, sizeof(i450kx_t)); - pci_add_card(PCI_ADD_NORTHBRIDGE, pb_read, pb_write, dev); /* Device 19: Intel 450KX PCI Bridge PB */ - pci_add_card(PCI_ADD_NORTHBRIDGE, mc_read, mc_write, dev); /* Device 14: Intel 450KX Memory Controller MC */ + pci_add_card(PCI_ADD_NORTHBRIDGE, pb_read, pb_write, dev); /* Device 19h: Intel 450KX PCI Bridge PB */ + pci_add_card(PCI_ADD_AGPBRIDGE, mc_read, mc_write, dev); /* Device 14h: Intel 450KX Memory Controller MC */ - dev->smram = smram_add(); + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); cpu_cache_int_enabled = 1; cpu_cache_ext_enabled = 1; diff --git a/src/disk/CMakeLists.txt b/src/disk/CMakeLists.txt index f0ec758fe..9a5c72e00 100644 --- a/src/disk/CMakeLists.txt +++ b/src/disk/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(hdd OBJECT hdd.c hdd_image.c hdd_table.c hdc.c hdc_st506_xt.c hdc_st506_at.c hdc_xta.c hdc_esdi_at.c hdc_esdi_mca.c hdc_xtide.c - hdc_ide.c hdc_ide_opti611.c hdc_ide_cmd640.c hdc_ide_sff8038i.c) + hdc_ide.c hdc_ide_opti611.c hdc_ide_cmd640.c hdc_ide_cmd646.c hdc_ide_sff8038i.c) add_library(zip OBJECT zip.c) diff --git a/src/disk/hdc_ide_cmd640.c b/src/disk/hdc_ide_cmd640.c index ad2c739cc..ac6146094 100644 --- a/src/disk/hdc_ide_cmd640.c +++ b/src/disk/hdc_ide_cmd640.c @@ -7,7 +7,7 @@ * This file is part of the 86Box distribution. * * Implementation of the CMD PCI-0640B controller. - + * * Authors: Miran Grca, * * Copyright 2020 Miran Grca. @@ -42,7 +42,8 @@ typedef struct { uint8_t vlb_idx, id, in_cfg, single_channel, - regs[256]; + pci, regs[256]; + uint32_t local; int slot, irq_mode[2], irq_pin, irq_line; } cmd640_t; @@ -51,15 +52,45 @@ typedef struct static int next_id = 0; +#ifdef ENABLE_CMD640_LOG +int cmd640_do_log = ENABLE_CMD640_LOG; +static void +cmd640_log(const char *fmt, ...) +{ + va_list ap; + + if (cmd640_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cmd640_log(fmt, ...) +#endif + + void cmd640_set_irq(int channel, void *priv) { cmd640_t *dev = (cmd640_t *) priv; - dev->regs[0x50] &= ~0x04; - dev->regs[0x50] |= (channel >> 4); + int irq = !!(channel & 0x40); + + if (channel & 0x01) { + if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { + dev->regs[0x57] &= ~0x10; + dev->regs[0x57] |= (channel >> 2); + } + } else { + if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { + dev->regs[0x50] &= ~0x04; + dev->regs[0x50] |= (channel >> 4); + } + } channel &= 0x01; - if (dev->regs[0x50] & 0x04) { + if (irq) { if (dev->irq_mode[channel] == 1) pci_set_irq(dev->slot, dev->irq_pin); else @@ -196,6 +227,8 @@ cmd640_vlb_read(uint16_t addr, void *priv) ret = dev->regs[dev->vlb_idx]; if (dev->vlb_idx == 0x50) dev->regs[0x50] &= ~0x04; + else if (dev->vlb_idx == 0x57) + dev->regs[0x57] &= ~0x10; if (dev->regs[0x50] & 0x80) dev->in_cfg = 0; break; @@ -234,6 +267,8 @@ cmd640_pci_write(int func, int addr, uint8_t val, void *priv) { cmd640_t *dev = (cmd640_t *) priv; + cmd640_log("cmd640_pci_write(%i, %02X, %02X)\n", func, addr, val); + if (func == 0x00) switch (addr) { case 0x04: dev->regs[addr] = (val & 0x41); @@ -315,15 +350,20 @@ cmd640_pci_read(int func, int addr, void *priv) ret = dev->regs[addr]; if (addr == 0x50) dev->regs[0x50] &= ~0x04; + else if (addr == 0x57) + dev->regs[0x57] &= ~0x10; } + cmd640_log("cmd640_pci_read(%i, %02X, %02X)\n", func, addr, ret); + return ret; } static void -cmd640_reset(void *p) +cmd640_reset(void *priv) { + cmd640_t *dev = (cmd640_t *) priv; int i = 0; for (i = 0; i < CDROM_NUM; i++) { @@ -342,8 +382,58 @@ cmd640_reset(void *p) mo_reset((scsi_common_t *) mo_drives[i].priv); } - cmd640_set_irq(0x00, p); - cmd640_set_irq(0x01, p); + cmd640_set_irq(0x00, priv); + cmd640_set_irq(0x01, priv); + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + dev->regs[0x50] = 0x02; /* Revision 02 */ + dev->regs[0x50] |= (dev->id << 3); /* Device ID: 00 = 60h, 01 = 61h, 10 = 62h, 11 = 63h */ + + dev->regs[0x59] = 0x40; + + if (dev->pci) { + cmd640_log("dev->local = %08X\n", dev->local); + if ((dev->local & 0xffff) == 0x0a) { + dev->regs[0x50] |= 0x40; /* Enable Base address register R/W; + If 0, they return 0 and are read-only 8 */ + } + + dev->regs[0x00] = 0x95; /* CMD */ + dev->regs[0x01] = 0x10; + dev->regs[0x02] = 0x40; /* PCI-0640B */ + dev->regs[0x03] = 0x06; + dev->regs[0x04] = 0x01; /* Apparently required by the ASUS PCI/I-P5SP4 AND PCI/I-P54SP4 */ + dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ + dev->regs[0x08] = 0x02; /* Revision 02 */ + dev->regs[0x09] = dev->local; /* Programming interface */ + dev->regs[0x0a] = 0x01; /* IDE controller */ + dev->regs[0x0b] = 0x01; /* Mass storage controller */ + + /* Base addresses (1F0, 3F4, 170, 374) */ + if (dev->regs[0x50] & 0x40) { + dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; + dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; + dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; + dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; + } + + dev->regs[0x3c] = 0x14; /* IRQ 14 */ + dev->regs[0x3d] = 0x01; /* INTA */ + + dev->irq_mode[0] = dev->irq_mode[1] = 0; + dev->irq_pin = PCI_INTA; + dev->irq_line = 14; + } else { + if ((dev->local & 0xffff) == 0x0078) + dev->regs[0x50] |= 0x20; /* 0 = 178h, 17Ch; 1 = 078h, 07Ch */ + + /* If bit 7 is 1, then device ID has to be written on port x78h before + accessing the configuration registers */ + dev->in_cfg = 1; /* Configuration registers are accessible */ + } + + cmd640_ide_handlers(dev); } @@ -366,45 +456,13 @@ cmd640_init(const device_t *info) dev->id = next_id | 0x60; - dev->regs[0x50] = 0x02; /* Revision 02 */ - dev->regs[0x50] |= (next_id << 3); /* Device ID: 00 = 60h, 01 = 61h, 10 = 62h, 11 = 63h */ - - dev->regs[0x59] = 0x40; + dev->pci = !!(info->flags & DEVICE_PCI); + dev->local = info->local; if (info->flags & DEVICE_PCI) { - if ((info->local & 0xffff) == 0x0a) { - dev->regs[0x50] |= 0x40; /* Enable Base address register R/W; - If 0, they return 0 and are read-only 8 */ - } - - dev->regs[0x00] = 0x95; /* CMD */ - dev->regs[0x01] = 0x10; - dev->regs[0x02] = 0x40; /* PCI-0640B */ - dev->regs[0x03] = 0x06; - dev->regs[0x04] = 0x01; /* Apparently required by the ASUS PCI/I-P5SP4 AND PCI/I-P54SP4 */ - dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ - dev->regs[0x08] = 0x02; /* Revision 02 */ - dev->regs[0x09] = info->local; /* Programming interface */ - dev->regs[0x0a] = 0x01; /* IDE controller */ - dev->regs[0x0b] = 0x01; /* Mass storage controller */ - - /* Base addresses (1F0, 3F4, 170, 374) */ - if (dev->regs[0x50] & 0x40) { - dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; - dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; - dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; - dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; - } - - dev->regs[0x3c] = 0x14; /* IRQ 14 */ - dev->regs[0x3d] = 0x01; /* INTA */ - device_add(&ide_pci_2ch_device); dev->slot = pci_add_card(PCI_ADD_IDE, cmd640_pci_read, cmd640_pci_write, dev); - dev->irq_mode[0] = dev->irq_mode[1] = 0; - dev->irq_pin = PCI_INTA; - dev->irq_line = 14; ide_set_bus_master(0, NULL, cmd640_set_irq, dev); ide_set_bus_master(1, NULL, cmd640_set_irq, dev); @@ -416,12 +474,6 @@ cmd640_init(const device_t *info) // ide_pri_disable(); } else if (info->flags & DEVICE_VLB) { - if ((info->local & 0xffff) == 0x0078) - dev->regs[0x50] |= 0x20; /* 0 = 178h, 17Ch; 1 = 078h, 07Ch */ - /* If bit 7 is 1, then device ID has to be written on port x78h before - accessing the configuration registers */ - dev->in_cfg = 1; /* Configuration register are accessible */ - device_add(&ide_vlb_2ch_device); io_sethandler(info->local & 0xffff, 0x0008, @@ -432,11 +484,10 @@ cmd640_init(const device_t *info) dev->single_channel = !!(info->local & 0x20000); - if (!dev->single_channel) - ide_sec_disable(); - next_id++; + cmd640_reset(dev); + return dev; } @@ -445,7 +496,7 @@ const device_t ide_cmd640_vlb_device = { "CMD PCI-0640B VLB", DEVICE_VLB, 0x0078, - cmd640_init, cmd640_close, NULL, + cmd640_init, cmd640_close, cmd640_reset, { NULL }, NULL, NULL, NULL }; @@ -454,7 +505,7 @@ const device_t ide_cmd640_vlb_178_device = { "CMD PCI-0640B VLB (Port 178h)", DEVICE_VLB, 0x0178, - cmd640_init, cmd640_close, NULL, + cmd640_init, cmd640_close, cmd640_reset, { NULL }, NULL, NULL, NULL }; diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c new file mode 100644 index 000000000..4a8e9a176 --- /dev/null +++ b/src/disk/hdc_ide_cmd646.c @@ -0,0 +1,435 @@ +/* + * 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 CMD PCI-0646 controller. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/scsi_cdrom.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/zip.h> +#include <86box/mo.h> + + +typedef struct +{ + uint8_t vlb_idx, single_channel, + in_cfg, regs[256]; + uint32_t local; + int slot, irq_mode[2], + irq_pin; + sff8038i_t *bm[2]; +} cmd646_t; + + +#ifdef ENABLE_CMD646_LOG +int cmd646_do_log = ENABLE_CMD646_LOG; +static void +cmd646_log(const char *fmt, ...) +{ + va_list ap; + + if (cmd646_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cmd646_log(fmt, ...) +#endif + + +static void +cmd646_set_irq(int channel, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + if (channel & 0x01) { + if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { + dev->regs[0x57] &= ~0x10; + dev->regs[0x57] |= (channel >> 2); + } + } else { + if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { + dev->regs[0x50] &= ~0x04; + dev->regs[0x50] |= (channel >> 4); + } + } + + sff_bus_master_set_irq(channel, dev->bm[channel & 0x01]); +} + + +static int +cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + return sff_bus_master_dma(channel, data, transfer_length, out, dev->bm[channel & 0x01]); +} + + +static void +cmd646_ide_handlers(cmd646_t *dev) +{ + uint16_t main, side; + int irq_mode[2] = { 0, 0 }; + + ide_pri_disable(); + + if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8); + side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->regs[0x09] & 0x01) + irq_mode[0] = 1; + + sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); + + if (dev->regs[0x04] & 0x01) + ide_pri_enable(); + + if (dev->single_channel) + return; + + ide_sec_disable(); + + if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8); + side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + + ide_set_base(1, main); + ide_set_side(1, side); + + if (dev->regs[0x09] & 0x04) + irq_mode[1] = 1; + + sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); + + if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08)) + ide_sec_enable(); + +} + + +static void +cmd646_ide_bm_handlers(cmd646_t *dev) +{ + uint16_t base = (dev->regs[0x20] & 0xf0) | (dev->regs[0x21] << 8); + + sff_bus_master_handler(dev->bm[0], (dev->regs[0x04] & 1), base); + sff_bus_master_handler(dev->bm[1], (dev->regs[0x04] & 1), base + 8); +} + + +static void +cmd646_pci_write(int func, int addr, uint8_t val, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + cmd646_log("[%04X:%08X] (%08X) cmd646_pci_write(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, val); + + if (func == 0x00) switch (addr) { + case 0x04: + dev->regs[addr] = (val & 0x45); + cmd646_ide_handlers(dev); + break; + case 0x07: + dev->regs[addr] &= ~(val & 0xb1); + break; + case 0x09: + if ((dev->regs[addr] & 0x0a) == 0x0a) { + dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); + dev->irq_mode[0] = !!(val & 0x01); + dev->irq_mode[1] = !!(val & 0x04); + cmd646_ide_handlers(dev); + } + break; + case 0x10: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x10] = (val & 0xf8) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x11: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x11] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x14: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x14] = (val & 0xfc) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x15: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x15] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x18: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x18] = (val & 0xf8) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x19: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x19] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x1c: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1c] = (val & 0xfc) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x1d: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1d] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x20: + dev->regs[0x20] = (val & 0xf0) | 1; + cmd646_ide_bm_handlers(dev); + break; + case 0x21: + dev->regs[0x21] = val; + cmd646_ide_bm_handlers(dev); + break; + case 0x51: + dev->regs[addr] = val & 0xc8; + cmd646_ide_handlers(dev); + break; + case 0x52: case 0x54: case 0x56: case 0x58: + case 0x59: case 0x5b: + dev->regs[addr] = val; + break; + case 0x53: case 0x55: + dev->regs[addr] = val & 0xc0; + break; + case 0x57: + dev->regs[addr] = (dev->regs[addr] & 0x10) | (val & 0xcc); + break; + case 0x70 ... 0x77: + sff_bus_master_write(addr & 0x0f, val, dev->bm[0]); + break; + case 0x78 ... 0x7f: + sff_bus_master_write(addr & 0x0f, val, dev->bm[1]); + break; + } +} + + +static uint8_t +cmd646_pci_read(int func, int addr, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) { + ret = dev->regs[addr]; + + if (addr == 0x50) + dev->regs[0x50] &= ~0x04; + else if (addr == 0x57) + dev->regs[0x57] &= ~0x10; + else if ((addr >= 0x70) && (addr <= 0x77)) + ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); + else if ((addr >= 0x78) && (addr <= 0x7f)) + ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); + } + + cmd646_log("[%04X:%08X] (%08X) cmd646_pci_read(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, ret); + + return ret; +} + + +static void +cmd646_reset(void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + (cdrom[i].ide_channel < 4) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } + for (i = 0; i < MO_NUM; i++) { + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && + (mo_drives[i].ide_channel < 4) && mo_drives[i].priv) + mo_reset((scsi_common_t *) mo_drives[i].priv); + } + + cmd646_set_irq(0x00, priv); + cmd646_set_irq(0x01, priv); + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + dev->regs[0x00] = 0x95; /* CMD */ + dev->regs[0x01] = 0x10; + dev->regs[0x02] = 0x46; /* PCI-0646 */ + dev->regs[0x03] = 0x06; + dev->regs[0x04] = 0x00; + dev->regs[0x06] = 0x80; + dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ + dev->regs[0x09] = dev->local; /* Programming interface */ + dev->regs[0x0a] = 0x01; /* IDE controller */ + dev->regs[0x0b] = 0x01; /* Mass storage controller */ + + if ((dev->local & 0xffff) == 0x8a) { + dev->regs[0x50] = 0x40; /* Enable Base address register R/W; + If 0, they return 0 and are read-only 8 */ + + /* Base addresses (1F0, 3F4, 170, 374) */ + dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; + dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; + dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; + dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; + } + + dev->regs[0x20] = 0x01; + + dev->regs[0x3c] = 0x0e; /* IRQ 14 */ + dev->regs[0x3d] = 0x01; /* INTA */ + dev->regs[0x3e] = 0x02; /* Min_Gnt */ + dev->regs[0x3f] = 0x04; /* Max_Iat */ + + if (!dev->single_channel) + dev->regs[0x51] = 0x08; + + dev->regs[0x57] = 0x0c; + dev->regs[0x59] = 0x40; + + dev->irq_mode[0] = dev->irq_mode[1] = 0; + dev->irq_pin = PCI_INTA; + + cmd646_ide_handlers(dev); + cmd646_ide_bm_handlers(dev); +} + + +static void +cmd646_close(void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + free(dev); +} + + +static void * +cmd646_init(const device_t *info) +{ + cmd646_t *dev = (cmd646_t *) malloc(sizeof(cmd646_t)); + memset(dev, 0x00, sizeof(cmd646_t)); + + dev->local = info->local; + + device_add(&ide_pci_2ch_device); + + dev->slot = pci_add_card(PCI_ADD_IDE, cmd646_pci_read, cmd646_pci_write, dev); + + dev->single_channel = !!(info->local & 0x20000); + + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + if (!dev->single_channel) + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + + ide_set_bus_master(0, cmd646_bus_master_dma, cmd646_set_irq, dev); + if (!dev->single_channel) + ide_set_bus_master(1, cmd646_bus_master_dma, cmd646_set_irq, dev); + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[0], 1, 0); + + if (!dev->single_channel) { + sff_set_irq_mode(dev->bm[1], 0, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } + + cmd646_reset(dev); + + return dev; +} + + +const device_t ide_cmd646_device = { + "CMD PCI-0646", + DEVICE_PCI, + 0x8a, + cmd646_init, cmd646_close, cmd646_reset, + { NULL }, NULL, NULL, + NULL +}; + +const device_t ide_cmd646_legacy_only_device = { + "CMD PCI-0646 (Legacy Mode Only)", + DEVICE_PCI, + 0x80, + cmd646_init, cmd646_close, cmd646_reset, + { NULL }, NULL, NULL, + NULL +}; + +const device_t ide_cmd646_single_channel_device = { + "CMD PCI-0646", + DEVICE_PCI, + 0x2008a, + cmd646_init, cmd646_close, cmd646_reset, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 44d9ad545..8fe9fec88 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -47,10 +47,10 @@ static int next_id = 0; -static uint8_t sff_bus_master_read(uint16_t port, void *priv); +uint8_t sff_bus_master_read(uint16_t port, void *priv); static uint16_t sff_bus_master_readw(uint16_t port, void *priv); static uint32_t sff_bus_master_readl(uint16_t port, void *priv); -static void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv); static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv); @@ -112,7 +112,7 @@ sff_bus_master_next_addr(sff8038i_t *dev) } -static void +void sff_bus_master_write(uint16_t port, uint8_t val, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -138,6 +138,9 @@ sff_bus_master_write(uint16_t port, uint8_t val, void *priv) dev->command = val; break; + case 1: + dev->dma_mode = val & 0x03; + break; case 2: sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status); dev->status &= 0x07; @@ -177,6 +180,7 @@ sff_bus_master_writew(uint16_t port, uint16_t val, void *priv) switch (port & 7) { case 0: + case 1: case 2: sff_bus_master_write(port, val & 0xff, priv); break; @@ -202,6 +206,7 @@ sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) switch (port & 7) { case 0: + case 1: case 2: sff_bus_master_write(port, val & 0xff, priv); break; @@ -214,7 +219,7 @@ sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) } -static uint8_t +uint8_t sff_bus_master_read(uint16_t port, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -225,6 +230,9 @@ sff_bus_master_read(uint16_t port, void *priv) case 0: ret = dev->command; break; + case 1: + ret = dev->dma_mode & 0x03; + break; case 2: ret = dev->status & 0x67; break; @@ -257,6 +265,7 @@ sff_bus_master_readw(uint16_t port, void *priv) switch (port & 7) { case 0: + case 1: case 2: ret = (uint16_t) sff_bus_master_read(port, priv); break; @@ -283,6 +292,7 @@ sff_bus_master_readl(uint16_t port, void *priv) switch (port & 7) { case 0: + case 1: case 2: ret = (uint32_t) sff_bus_master_read(port, priv); break; @@ -297,7 +307,7 @@ sff_bus_master_readl(uint16_t port, void *priv) } -static int +int sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -311,8 +321,10 @@ sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, voi sop = out ? "Read" : "Writ"; #endif - if (!(dev->status & 1)) + if (!(dev->status & 1)) { + sff_log("DMA disabled\n"); return 2; /*DMA disabled*/ + } sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 00160ae13..ae97b156e 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -83,10 +83,7 @@ extern const device_t i440bx_device; extern const device_t i440bx_no_agp_device; extern const device_t i440gx_device; extern const device_t i440zx_device; - -#if defined(DEV_BRANCH) && defined(USE_I450KX) extern const device_t i450kx_device; -#endif extern const device_t sio_device; extern const device_t sio_zb_device; @@ -133,6 +130,7 @@ extern const device_t stpc_serial_device; extern const device_t stpc_lpt_device; /* UMC */ +extern const device_t umc_um82c49x_device; extern const device_t umc_8886f_device; extern const device_t umc_8886af_device; extern const device_t umc_hb4_device; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 9175dddaf..1008b38c9 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -56,6 +56,9 @@ extern const device_t ide_cmd640_vlb_178_device; /* CMD PCI-640B VLB (Port 178h extern const device_t ide_cmd640_pci_device; /* CMD PCI-640B PCI */ extern const device_t ide_cmd640_pci_legacy_only_device; /* CMD PCI-640B PCI (Legacy Mode Only) */ extern const device_t ide_cmd640_pci_single_channel_device; /* CMD PCI-640B PCI (Only primary channel) */ +extern const device_t ide_cmd646_device; /* CMD PCI-646 */ +extern const device_t ide_cmd646_legacy_only_device; /* CMD PCI-646 (Legacy Mode Only) */ +extern const device_t ide_cmd646_single_channel_device; /* CMD PCI-646 (Only primary channel) */ extern const device_t ide_opti611_vlb_device; /* OPTi 82c611/611A VLB */ diff --git a/src/include/86box/hdc_ide_sff8038i.h b/src/include/86box/hdc_ide_sff8038i.h index 305d2d40c..700684dae 100644 --- a/src/include/86box/hdc_ide_sff8038i.h +++ b/src/include/86box/hdc_ide_sff8038i.h @@ -19,8 +19,10 @@ typedef struct { uint8_t command, status, - ptr0, enabled; - uint16_t base, pad; + ptr0, enabled, + dma_mode, pad, + pad0, pad1; + uint16_t base, pad2; uint32_t ptr, ptr_cur, addr; int count, eot, @@ -39,6 +41,11 @@ extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_len extern void sff_bus_master_set_irq(int channel, void *priv); +extern int sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv); + +extern void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +extern uint8_t sff_bus_master_read(uint16_t port, void *priv); + extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base); extern void sff_set_slot(sff8038i_t *dev, int slot); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index efedfc6e4..2767789b3 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -539,9 +539,7 @@ extern int machine_at_ficva503a_init(const machine_t *); extern int machine_at_sy_5ema_pro_init(const machine_t *); /* m_at_socket8.c */ -#if defined(DEV_BRANCH) && defined(USE_I450KX) extern int machine_at_p6rp4_init(const machine_t *); -#endif extern int machine_at_686nx_init(const machine_t *); extern int machine_at_v60n_init(const machine_t *); diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index dfcbef242..5d1f6848c 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -145,10 +145,18 @@ mem_set_access(ACCESS_SMM, 0, base, size, access) #define mem_set_mem_state_both(base, size, access) \ mem_set_access(ACCESS_ALL, 0, base, size, access) +#define mem_set_mem_state_cpu_both(base, size, access) \ + mem_set_access(ACCESS_CPU_BOTH, 0, base, size, access) +#define mem_set_mem_state_bus_both(base, size, access) \ + mem_set_access(ACCESS_BUS_BOTH, 0, base, size, access) #define mem_set_mem_state_smram(smm, base, size, is_smram) \ mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), 1, base, size, is_smram) #define mem_set_mem_state_smram_ex(smm, base, size, is_smram) \ mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), 2, base, size, is_smram) +#define mem_set_access_smram_cpu(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_CPU_SMM : ACCESS_CPU), 1, base, size, is_smram) +#define mem_set_access_smram_bus(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_BUS_SMM : ACCESS_BUS), 1, base, size, is_smram) #define flushmmucache_cr3 \ flushmmucache_nopc diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index f1776bf79..386954b54 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -95,6 +95,7 @@ extern const device_t piix4_nvr_device; extern const device_t ls486e_nvr_device; extern const device_t ami_apollo_nvr_device; extern const device_t via_nvr_device; +extern const device_t p6rp4_nvr_device; #endif diff --git a/src/include/86box/smram.h b/src/include/86box/smram.h index 6fc89971e..996e5df30 100644 --- a/src/include/86box/smram.h +++ b/src/include/86box/smram.h @@ -39,12 +39,19 @@ extern void smram_recalc_all(int ret); extern void smram_del(smram_t *smr); /* Add a SMRAM mapping. */ extern smram_t *smram_add(void); +/* Set memory state in the specified model (normal or SMM) according to the specified flags, + separately for bus and CPU. */ +extern void smram_map_ex(int bus, int smm, uint32_t addr, uint32_t size, int is_smram); /* Set memory state in the specified model (normal or SMM) according to the specified flags. */ extern void smram_map(int smm, uint32_t addr, uint32_t size, int is_smram); /* Disable a specific SMRAM mapping. */ extern void smram_disable(smram_t *smr); /* Disable all SMRAM mappings. */ extern void smram_disable_all(void); +/* Enable SMRAM mappings according to flags for both normal and SMM modes, separately for bus + and CPU. */ +extern void smram_enable_ex(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, + int flags_normal, int flags_normal_bus, int flags_smm, int flags_smm_bus); /* Enable SMRAM mappings according to flags for both normal and SMM modes. */ extern void smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, int flags_normal, int flags_smm); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 6643566ee..c20d21a75 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -28,10 +28,6 @@ if(HEDAKA) target_compile_definitions(mch PRIVATE USE_HEDAKA) endif() -if(I450KX) - target_compile_definitions(mch PRIVATE USE_I450KX) -endif() - if(LASERXT) target_sources(mch PRIVATE m_xt_laserxt.c) target_compile_definitions(mch PRIVATE USE_LASERXT) diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index ab3bc05b7..8067e17b0 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -30,6 +30,8 @@ #include <86box/hdc_ide.h> #include <86box/keyboard.h> #include <86box/flash.h> +#include <86box/timer.h> +#include <86box/nvr.h> #include <86box/sio.h> #include <86box/hwm.h> #include <86box/spd.h> @@ -37,7 +39,7 @@ #include "cpu.h" #include <86box/machine.h> -#if defined(DEV_BRANCH) && defined(USE_I450KX) + int machine_at_p6rp4_init(const machine_t *model) { @@ -49,11 +51,12 @@ machine_at_p6rp4_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + device_add(&p6rp4_nvr_device); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x19, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_AGPBRIDGE, 0, 0, 0, 0); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x08, PCI_CARD_IDE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); @@ -62,16 +65,15 @@ machine_at_p6rp4_init(const machine_t *model) pci_register_slot(0x04, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&i450kx_device); device_add(&sio_zb_device); - // device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_cmd646_device); /* Input port bit 2 must be 1 or CMOS Setup is disabled. */ device_add(&keyboard_ps2_ami_pci_device); device_add(&fdc37c665_device); - device_add(&ide_cmd640_pci_device); device_add(&intel_flash_bxt_device); return ret; } -#endif + int machine_at_686nx_init(const machine_t *model) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 239fd2f41..0f2479961 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -398,6 +398,8 @@ const machine_t machines[] = { { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, + /* Has an Intel 82C42PE with Phoenix MultiKey KBC firmware. */ + { "[UMC 491/493] Epson Action Tower 3000", "actiontower3000", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_actiontower3000_init, NULL }, /* 486 machines which utilize the PCI bus */ /* This has an AMIKey-2, which is an updated version of type 'H'. */ @@ -750,10 +752,8 @@ const machine_t machines[] = { /* Socket 8 machines */ /* 450KX */ -#if defined(DEV_BRANCH) && defined(USE_I450KX) /* This has an AMIKey-2, which is an updated version of type 'H'. */ { "[i450KX] ASUS P/I-P6RP4", "p6rp4", MACHINE_TYPE_SOCKET8, CPU_PKG_SOCKET8, 0, 60000000, 66666667, 2100, 3500, 1.5, 8.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 524288, 8192, 127, machine_at_p6rp4_init, NULL }, -#endif /* 440FX */ /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ diff --git a/src/mem/mem.c b/src/mem/mem.c index de6e0a60b..da2e1f31e 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2247,6 +2247,12 @@ mem_mapping_access_allowed(uint32_t flags, uint16_t access) ret = ret && !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); } else ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM); + } else { + /* Still allow SMRAM if access is DISABLED but also has CACHE and/or SMRAM flags set. */ + if (access & ACCESS_CACHE) + ret = (flags & MEM_MAPPING_CACHE); + else if (access & ACCESS_SMRAM) + ret = (flags & MEM_MAPPING_SMRAM); } return ret; diff --git a/src/mem/smram.c b/src/mem/smram.c index 8e405af8a..8b1f9fd40 100644 --- a/src/mem/smram.c +++ b/src/mem/smram.c @@ -287,11 +287,24 @@ smram_add(void) } +/* Set memory state in the specified model (normal or SMM) according to the specified flags, + separately for bus and CPU. */ +void +smram_map_ex(int bus, int smm, uint32_t addr, uint32_t size, int is_smram) +{ + if (bus) + mem_set_access_smram_bus(smm, addr, size, is_smram); + else + mem_set_access_smram_cpu(smm, addr, size, is_smram); +} + + /* Set memory state in the specified model (normal or SMM) according to the specified flags. */ void smram_map(int smm, uint32_t addr, uint32_t size, int is_smram) { - mem_set_mem_state_smram(smm, addr, size, is_smram); + smram_map_ex(0, smm, addr, size, is_smram); + smram_map_ex(1, smm, addr, size, is_smram); } @@ -331,9 +344,11 @@ smram_disable_all(void) } -/* Enable SMRAM mappings according to flags for both normal and SMM modes. */ +/* Enable SMRAM mappings according to flags for both normal and SMM modes, separately for bus + and CPU. */ void -smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, int flags_normal, int flags_smm) +smram_enable_ex(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, + int flags_normal, int flags_normal_bus, int flags_smm, int flags_smm_bus) { if (smr == NULL) { fatal("smram_add(): Invalid SMRAM mapping\n"); @@ -362,13 +377,23 @@ smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, mem_mapping_set_exec(&(smr->mapping), smram + 0x30000); } - smram_map(0, host_base, size, flags_normal); - smram_map(1, host_base, size, flags_smm); + smram_map_ex(0, 0, host_base, size, flags_normal); + smram_map_ex(1, 0, host_base, size, flags_normal_bus); + smram_map_ex(0, 1, host_base, size, flags_smm); + smram_map_ex(1, 1, host_base, size, flags_smm_bus); } else smram_disable(smr); } +/* Enable SMRAM mappings according to flags for both normal and SMM modes. */ +void +smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, int flags_normal, int flags_smm) +{ + smram_enable_ex(smr, host_base, ram_base, size, flags_normal, flags_normal, flags_smm, flags_smm); +} + + /* Checks if a SMRAM mapping is enabled or not. */ int smram_enabled(smram_t *smr) diff --git a/src/nvr_at.c b/src/nvr_at.c index 1942f1c1f..03f3ea6bb 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -292,7 +292,8 @@ #define FLAG_LS_HACK 0x01 #define FLAG_APOLLO_HACK 0x02 -#define FLAG_PIIX4 0x04 +#define FLAG_P6RP4_HACK 0x04 +#define FLAG_PIIX4 0x08 typedef struct { @@ -755,10 +756,31 @@ nvr_read(uint16_t addr, void *priv) ret = checksum >> 8; else ret = checksum & 0xff; + } else if (!nvr->new && (local->flags & FLAG_P6RP4_HACK)) { + /* The checksum at 3E-3F is for 37-3D and 40-51. */ + for (i = 0x37; i <= 0x3d; i++) + checksum += nvr->regs[i]; + for (i = 0x40; i <= 0x51; i++) { + if (i == 0x43) + checksum += (nvr->regs[i] | 0x02); + else + checksum += nvr->regs[i]; + } + if (local->addr[addr_id] == 0x3e) + ret = checksum >> 8; + else + ret = checksum & 0xff; } else ret = nvr->regs[local->addr[addr_id]]; break; + case 0x43: + if (!nvr->new && (local->flags & FLAG_P6RP4_HACK)) + ret = nvr->regs[local->addr[addr_id]] | 0x02; + else + ret = nvr->regs[local->addr[addr_id]]; + break; + case 0x52: if (!nvr->new && (local->flags & FLAG_APOLLO_HACK)) ret = nvr->regs[local->addr[addr_id]] & 0xf3; @@ -972,8 +994,14 @@ nvr_at_init(const device_t *info) local->flags = 0x00; switch(info->local & 7) { case 0: /* standard AT, no century register */ - nvr->irq = 8; - local->cent = 0xff; + if (info->local == 16) { + local->flags |= FLAG_P6RP4_HACK; + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + } else { + nvr->irq = 8; + local->cent = 0xff; + } break; case 1: /* standard AT */ @@ -1162,3 +1190,12 @@ const device_t via_nvr_device = { { NULL }, nvr_at_speed_changed, NULL }; + +const device_t p6rp4_nvr_device = { + "ASUS P/I-P6RP4 PC/AT NVRAM", + DEVICE_ISA | DEVICE_AT, + 16, + nvr_at_init, nvr_at_close, nvr_at_reset, + { NULL }, nvr_at_speed_changed, + NULL +}; diff --git a/src/pci.c b/src/pci.c index 37c9976a5..fc6e1e75e 100644 --- a/src/pci.c +++ b/src/pci.c @@ -150,6 +150,80 @@ pci_write(uint16_t port, uint8_t val, void *priv) } +static void +pci_writew(uint16_t port, uint16_t val, void *priv) +{ + uint8_t slot = 0; + + if (in_smm) + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + + switch (port) { + case 0xcfc: case 0xcfe: + if (! pci_enable) + return; + + pci_log("Writing %04X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | (port & 3) | 1, val >> 8, pci_cards[slot].priv); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + + break; + } +} + + +static void +pci_writel(uint16_t port, uint32_t val, void *priv) +{ + uint8_t slot = 0; + + if (in_smm) + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + + switch (port) { + case 0xcfc: + if (! pci_enable) + return; + + pci_log("Writing %08X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | (port & 3) | 1, (val >> 8) & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | (port & 3) | 2, (val >> 16) & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | (port & 3) | 3, (val >> 24) & 0xff, pci_cards[slot].priv); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + + break; + } +} + + static uint8_t pci_read(uint16_t port, void *priv) { @@ -185,6 +259,82 @@ pci_read(uint16_t port, void *priv) } +static uint16_t +pci_readw(uint16_t port, void *priv) +{ + uint8_t slot = 0; + uint16_t ret = 0xffff; + + if (in_smm) + pci_log("(%i) %03x read\n", pci_enable, port); + + switch (port) { + case 0xcfc: case 0xcfe: + if (! pci_enable) + return 0xff; + + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) { + ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + ret |= (pci_cards[slot].read(pci_func, pci_index | (port & 3) | 1, pci_cards[slot].priv) << 8); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } + + pci_log("Reading %04X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + + return ret; +} + + +static uint32_t +pci_readl(uint16_t port, void *priv) +{ + uint8_t slot = 0; + uint32_t ret = 0xffffffff; + + if (in_smm) + pci_log("(%i) %03x read\n", pci_enable, port); + + switch (port) { + case 0xcfc: case 0xcfe: + if (! pci_enable) + return 0xff; + + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) { + ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + ret |= (pci_cards[slot].read(pci_func, pci_index | (port & 3) | 1, pci_cards[slot].priv) << 8); + ret |= (pci_cards[slot].read(pci_func, pci_index | (port & 3) | 2, pci_cards[slot].priv) << 16); + ret |= (pci_cards[slot].read(pci_func, pci_index | (port & 3) | 3, pci_cards[slot].priv) << 24); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } + + pci_log("Reading %08X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + + return ret; +} + + static void pci_type2_write(uint16_t port, uint8_t val, void *priv); static uint8_t pci_type2_read(uint16_t port, void *priv); @@ -803,7 +953,7 @@ pci_init(int type) io_sethandler(0x0cf8, 1, NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); io_sethandler(0x0cfc, 4, - pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + pci_read,pci_readw,pci_readl, pci_write,pci_writew,pci_writel, NULL); pci_pmc = 1; } else { io_sethandler(0x0cf8, 1, diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index ce9b9852c..a69413596 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -160,6 +160,7 @@ static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_CDROM_PAGE | GPMODEP_CDROM_AUDIO_PAGE | + (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); @@ -180,7 +181,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -227,7 +228,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -261,7 +262,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { { { 0, 0 }, { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0E, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -274,7 +275,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0x8E, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index b7680640f..068562028 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -45,9 +45,6 @@ ifeq ($(DEV_BUILD), y) ifndef HEDAKA HEDAKA := y endif - ifndef I450KX - I450KX := y - endif ifndef LASERXT LASERXT := y endif @@ -109,9 +106,6 @@ else ifndef HEDAKA HEDAKA := n endif - ifndef I450KX - I450KX := n - endif ifndef LASERXT LASERXT := n endif @@ -501,11 +495,6 @@ ifeq ($(HEDAKA), y) OPTS += -DUSE_HEDAKA endif -ifeq ($(I450KX), y) -OPTS += -DUSE_I450KX -DEVBROBJ += intel_i450kx.o -endif - ifeq ($(LASERXT), y) OPTS += -DUSE_LASERXT DEVBROBJ += m_xt_laserxt.o @@ -593,7 +582,8 @@ CHIPSETOBJ := 82c100.o acc2168.o \ cs4031.o cs8230.o \ ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ gc100.o headland.o \ - ims8848.o intel_82335.o intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ + ims8848.o intel_82335.o intel_420ex.o intel_4x0.o intel_i450kx.o intel_sio.o intel_piix.o \ + ioapic.o \ neat.o \ opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ scamp.o scat.o \ @@ -674,7 +664,8 @@ HDDOBJ := hdd.o \ hdc_esdi_at.o hdc_esdi_mca.o \ hdc_xtide.o hdc_ide.o \ hdc_ide_opti611.o \ - hdc_ide_cmd640.o hdc_ide_sff8038i.o + hdc_ide_cmd640.o hdc_ide_cmd646.o \ + hdc_ide_sff8038i.o MINIVHDOBJ := cwalk.o libxml2_encoding.o minivhd_convert.o \ minivhd_create.o minivhd_io.o minivhd_manage.o \ From b0fe3d8f0f3eb9a4b60322db9030713dca13a496 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 26 Oct 2021 20:00:01 +0200 Subject: [PATCH 092/140] Removed the Epson Action Tower 3000. --- src/machine/machine_table.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 0f2479961..a5c9732cf 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -398,8 +398,6 @@ const machine_t machines[] = { { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ { "[SiS 471] Epox 486SX/DX Green", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, - /* Has an Intel 82C42PE with Phoenix MultiKey KBC firmware. */ - { "[UMC 491/493] Epson Action Tower 3000", "actiontower3000", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_actiontower3000_init, NULL }, /* 486 machines which utilize the PCI bus */ /* This has an AMIKey-2, which is an updated version of type 'H'. */ From 92bfb61dfc73703fe2e24583cc8ca526266f398e Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Thu, 28 Oct 2021 15:44:31 -0400 Subject: [PATCH 093/140] More systems which have PS/2 mouse --- src/machine/machine_table.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9dd5db1fa..e4d5ff9bc 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -221,24 +221,24 @@ const machine_t machines[] = { { "[SiS 471] AMI 486 Clone", "ami471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_ami471_init, NULL }, { "[SiS 471] AMI WinBIOS 486 clone", "win471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_win471_init, NULL }, { "[SiS 471] AOpen Vi15G", "vi15g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_vi15g_init, NULL }, - { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, + { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 65536, 1024, 127, machine_at_vli486sv2g_init, NULL }, { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_dtk486_init, NULL }, { "[SiS 471] Phoenix SiS 471", "px471", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_VLB | MACHINE_IDE, 1024,131072, 1024, 127, machine_at_px471_init, NULL }, /* 486 machines which utilize the PCI bus */ { "[ALi M1489] ABIT AB-PB4", "abpb4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_abpb4_init, NULL }, { "[ALi M1489] AMI WinBIOS 486 PCI", "win486pci", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_win486pci_init, NULL }, - { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, - { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_486ap4_init, NULL }, - { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3g_init, NULL }, + { "[OPTi 802G] IBM PC 330 (type 6573)", "pc330_6573", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3_PC330, 0, 25000000, 33333333, 0, 0, 2.0, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE, 1024, 65536, 1024, 127, machine_at_pc330_6573_init, NULL }, + { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_486ap4_init, NULL }, + { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3g_init, NULL }, { "[i420TX] ASUS PCI/I-486SP3", "486sp3", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL | MACHINE_SCSI, 1024, 131072, 1024, 127, machine_at_486sp3_init, NULL }, { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 2048, 131072, 2048, 127, machine_at_alfredo_init, NULL }, - { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, + { "[SiS 496] ASUS PVI-486SP3C", "486sp3c", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCIV | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_486sp3c_init, NULL }, { "[SiS 496] Lucky Star LS-486E", "ls486e", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ls486e_init, NULL }, { "[SiS 496] Micronics M4Li", "m4li", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 131072, 1024, 127, machine_at_m4li_init, NULL }, { "[SiS 496] Rise Computer R418", "r418", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_r418_init, NULL }, { "[SiS 496] Soyo 4SA2", "4sa2", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4sa2_init, NULL }, - { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, + { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 1024, 261120, 1024, 255, machine_at_4dps_init, NULL }, { "[UMC 8881] A-Trend ATC-1415", "atc1415", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 65536, 1024, 255, machine_at_atc1415_init, NULL }, { "[UMC 8881] ECS Elite UM8810PAIO", "ecs486", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 131072, 1024, 255, machine_at_ecs486_init, NULL }, { "[UMC 8881] Shuttle HOT-433A", "hot433", MACHINE_TYPE_486_S3, CPU_PKG_SOCKET3, 0, 0, 0, 0, 0, 0, 0, MACHINE_PCI | MACHINE_IDE_DUAL, 1024, 262144, 1024, 255, machine_at_hot433_init, NULL }, @@ -266,7 +266,7 @@ const machine_t machines[] = { { "[i430LX] Packard Bell PB520R", "pb520r", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 139264, 2048, 127, machine_at_pb520r_init, at_pb520r_get_device }, /* OPTi 596/597 */ - { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_VLB | MACHINE_IDE, 2048, 65536, 2048, 127, machine_at_excalibur_init, NULL }, + { "[OPTi 597] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_VLB | MACHINE_BUS_PS2 | MACHINE_IDE, 2048, 65536, 2048, 127, machine_at_excalibur_init, NULL }, /* SiS 85C50x */ { "[SiS 85C50x] ASUS PCI/I-P5SP4", "p5sp4", MACHINE_TYPE_SOCKET4, CPU_PKG_SOCKET4, 0, 60000000, 66666667, 5000, 5000, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p5sp4_init, NULL }, @@ -297,7 +297,7 @@ const machine_t machines[] = { { "[SiS 85C50x] BCM SQ-588", "sq588", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_PENTIUMMMX), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_sq588_init, NULL }, /* UMC 889x */ - { "[UMC 889x] Shuttle HOT-539", "hot539", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3600, 1.5, 2.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_hot539_init, NULL }, + { "[UMC 889x] Shuttle HOT-539", "hot539", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3600, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 127, machine_at_hot539_init, NULL }, /* Socket 7 (Single Voltage) machines */ /* 430FX */ @@ -308,7 +308,7 @@ const machine_t machines[] = { { "[i430FX] Intel Advanced/ATX (MR BIOS)", "mrthor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_mrthor_init, NULL }, { "[i430FX] Intel Advanced/EV", "endeavor", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_endeavor_init, at_endeavor_get_device }, { "[i430FX] Packard Bell PB640", "pb640", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_VIDEO, 8192, 131072, 8192, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[i430FX] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_chariot_init, NULL }, + { "[i430FX] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_chariot_init, NULL }, /* 430HX */ { "[i430HX] Acer M3A", "acerm3a", MACHINE_TYPE_SOCKET7_3V, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3300, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 196608, 8192, 127, machine_at_acerm3a_init, NULL }, From 88bfee8e07b4e428f947487d49224ceb0d3ab8fe Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Sat, 30 Oct 2021 20:44:09 +0300 Subject: [PATCH 094/140] Add Winbox to recommended managers in readme --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 87b06018c..f351fb7e2 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,13 @@ System requirements and recommendations Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread, therefore generally systems with better IPC (instructions per clock) should be able to emulate higher clock speeds. -It is also recommended to use the [86Box Manager](https://github.com/86Box/86BoxManager) by [daviunic](https://github.com/daviunic) (Overdoze) to manage virtual machines. However, it is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option. +It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines. +* [Winbox for 86Box](https://github.com/laciba96/WinBox-for-86Box) by [Laci bá'](https://github.com/laciba96) + * The new manager with improved new user experience; installer, automatic updates of emulator files and more. +* [86Box Manager](https://github.com/86Box/86BoxManager) by [daviunic](https://github.com/daviunic) (Overdoze) + * The traditional 86Box manager with simple interface. + +However, it is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option. Downloads --------- From 295b6bd211fa799d2834793764de7996402be340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= <84271678+laciba96@users.noreply.github.com> Date: Sat, 30 Oct 2021 21:12:54 +0200 Subject: [PATCH 095/140] Fix character casing in the managers list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f351fb7e2..92fc718dd 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ System requirements and recommendations Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread, therefore generally systems with better IPC (instructions per clock) should be able to emulate higher clock speeds. It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines. -* [Winbox for 86Box](https://github.com/laciba96/WinBox-for-86Box) by [Laci bá'](https://github.com/laciba96) +* [WinBox for 86Box](https://github.com/laciba96/WinBox-for-86Box) by [Laci bá'](https://github.com/laciba96) * The new manager with improved new user experience; installer, automatic updates of emulator files and more. * [86Box Manager](https://github.com/86Box/86BoxManager) by [daviunic](https://github.com/daviunic) (Overdoze) * The traditional 86Box manager with simple interface. From 9b3b9c86b09adcdcf75a61fe1c0342ef250cbd27 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 31 Oct 2021 18:35:04 +0100 Subject: [PATCH 096/140] MIDI changes: Fixed MIDI UART OUT of the ES1371 using NT 4.0's drivers and keeping compatibility with Win9x/2000. --- src/sound/snd_audiopci.c | 17 +++++------------ src/sound/snd_opl.c | 10 ++++------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 4956f7742..62fd8f310 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -1703,24 +1703,17 @@ es1371_poll(void *p) But if anything sets MIDI Input and Output together we'd have to take account of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is enabled as well but not in the MIDI Output portion */ - if (dev->uart_ctrl & UART_CTRL_TXINTEN) - dev->int_status |= INT_STATUS_UART; - else - dev->int_status &= ~INT_STATUS_UART; + dev->int_status &= ~INT_STATUS_UART; + dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); } else if (!(dev->uart_ctrl & UART_CTRL_RXINTEN) && ((dev->uart_ctrl & UART_CTRL_TXINTEN))) { /* Or enable the UART IRQ and the respective TX bits only when the MIDI Output is enabled */ dev->int_status |= INT_STATUS_UART; + } else { + dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); } - if (dev->uart_ctrl & UART_CTRL_RXINTEN) { - if (dev->uart_ctrl & UART_CTRL_TXINTEN) - dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); - else - dev->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); - } else - dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); - + audiopci_log("UART control = %02x\n", dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)); es1371_update_irqs(dev); } diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 7708a3b59..6cd31f608 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -108,12 +108,10 @@ timer_control(opl_t *dev, int tmr, int start) timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); } else { opl_log("Timer %i stopped\n", tmr); - if (!(dev->flags & FLAG_OPL3)) { - if (tmr == 1) { - dev->status &= ~STAT_TMR2_OVER; - } else - dev->status &= ~STAT_TMR1_OVER; - } + if (tmr == 1) { + dev->status &= ~STAT_TMR2_OVER; + } else + dev->status &= ~STAT_TMR1_OVER; } } From 7bf6fc384401fb6d636f2866404dafd3dabea063 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 31 Oct 2021 19:06:16 +0100 Subject: [PATCH 097/140] Video changes (ET4000W32/i): Bit 1 is of 0x3DA (read only) is apparently required to make the OS/2 Tseng ET4000W32/i drivers work fine, fixes hangs upon reaching the GUI with said drivers. Avoid division by zero in the blitter of the ET4000W32/i under OS/2. Video changes (PVGA): Fixes mode changes of the PVGA1a, including the built-in video card of the Amstrad 2086/3086. --- src/video/vid_et4000w32.c | 56 ++++++++++++++++++++++++++------------- src/video/vid_paradise.c | 7 +++-- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 233783439..65dced875 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -169,7 +169,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *p) uint32_t add2addr = 0; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; + addr ^= 0x60; switch (addr) { case 0x3c2: @@ -311,7 +311,7 @@ et4000w32p_in(uint16_t addr, void *p) svga_t *svga = &et4000->svga; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; + addr ^= 0x60; switch (addr) { case 0x3c5: @@ -335,13 +335,25 @@ et4000w32p_in(uint16_t addr, void *p) case 0x3d5: return svga->crtc[svga->crtcreg]; + case 0x3da: + svga->attrff = 0; + + /*Bit 1 of the Input Status Register is required by OS/2 ET4000W32/I drivers to be set otherwise + the guest will loop infinitely upon reaching the GUI*/ + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x32; + else + svga->cgastat ^= 0x32; + return svga->cgastat; + case 0x210a: case 0x211a: case 0x212a: case 0x213a: case 0x214a: case 0x215a: case 0x216a: case 0x217a: return et4000->index; - case 0x210B: case 0x211B: case 0x212B: case 0x213B: - case 0x214B: case 0x215B: case 0x216B: case 0x217B: - if (et4000->index == 0xec) + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index == 0xec) { return (et4000->regs[0xec] & 0xf) | (et4000->rev << 4); + } if (et4000->index == 0xee) { if (svga->bpp == 8) { if ((svga->gdcreg[5] & 0x60) >= 0x40) @@ -761,7 +773,7 @@ et4000w32p_mmu_read(uint32_t addr, void *p) svga_t *svga = &et4000->svga; int bank; uint8_t temp; - + switch (addr & 0x6000) { case 0x0000: /* MMU 0 */ case 0x2000: /* MMU 1 */ @@ -783,7 +795,7 @@ et4000w32p_mmu_read(uint32_t addr, void *p) if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_max) return 0xff; - + return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; case 0x6000: @@ -889,7 +901,10 @@ et4000w32_blit_start(et4000w32p_t *et4000) } et4000->acl.pattern_back = et4000->acl.pattern_addr; if (!(et4000->acl.internal.pattern_wrap & 0x40)) { - et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) == 0x00) + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + else + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); } et4000->acl.pattern_x_back = et4000->acl.pattern_x; @@ -902,7 +917,10 @@ et4000w32_blit_start(et4000w32p_t *et4000) et4000->acl.source_back = et4000->acl.source_addr; if (!(et4000->acl.internal.source_wrap & 0x40)) { - et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + if ((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) == 0x00) + et4000->acl.source_y = (et4000->acl.source_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + else + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); } et4000->acl.source_x_back = et4000->acl.source_x; @@ -1655,7 +1673,7 @@ static const device_config_t et4000w32p_config[] = const device_t et4000w32_device = { - "Tseng Labs ET4000/w32", + "Tseng Labs ET4000/w32 ISA", DEVICE_ISA | DEVICE_AT, ET4000W32, et4000w32p_init, et4000w32p_close, NULL, { et4000w32_available }, @@ -1666,7 +1684,7 @@ const device_t et4000w32_device = const device_t et4000w32_onboard_device = { - "Tseng Labs ET4000/w32 (On-board)", + "Tseng Labs ET4000/w32 (ISA) (On-Board)", DEVICE_ISA | DEVICE_AT, ET4000W32, et4000w32p_init, et4000w32p_close, NULL, { et4000w32_available }, @@ -1677,7 +1695,7 @@ const device_t et4000w32_onboard_device = const device_t et4000w32i_isa_device = { - "Tseng Labs ET4000/w32i ISA", + "Tseng Labs ET4000/w32i Rev. B ISA", DEVICE_ISA | DEVICE_AT, ET4000W32I, et4000w32p_init, et4000w32p_close, NULL, { et4000w32i_isa_available }, @@ -1688,7 +1706,7 @@ const device_t et4000w32i_isa_device = const device_t et4000w32i_vlb_device = { - "Tseng Labs ET4000/w32i VLB", + "Tseng Labs ET4000/w32i Rev. B VLB", DEVICE_VLB, ET4000W32I, et4000w32p_init, et4000w32p_close, NULL, { et4000w32i_vlb_available }, @@ -1721,7 +1739,7 @@ const device_t et4000w32p_revc_pci_device = const device_t et4000w32p_noncardex_vlb_device = { - "Tseng Labs ET4000/w32p VLB", + "Tseng Labs ET4000/w32p Rev. D VLB", DEVICE_VLB, ET4000W32P, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_noncardex_available }, @@ -1732,7 +1750,7 @@ const device_t et4000w32p_noncardex_vlb_device = const device_t et4000w32p_noncardex_pci_device = { - "Tseng Labs ET4000/w32p PCI", + "Tseng Labs ET4000/w32p Rev. D PCI", DEVICE_PCI, ET4000W32P, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_noncardex_available }, @@ -1743,7 +1761,7 @@ const device_t et4000w32p_noncardex_pci_device = const device_t et4000w32p_cardex_vlb_device = { - "Tseng Labs ET4000/w32p VLB (Cardex)", + "Tseng Labs ET4000/w32p Rev. D VLB (Cardex)", DEVICE_VLB, ET4000W32P_CARDEX, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_cardex_available }, @@ -1754,7 +1772,7 @@ const device_t et4000w32p_cardex_vlb_device = const device_t et4000w32p_cardex_pci_device = { - "Tseng Labs ET4000/w32p PCI (Cardex)", + "Tseng Labs ET4000/w32p Rev. D PCI (Cardex)", DEVICE_PCI, ET4000W32P_CARDEX, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_cardex_available }, @@ -1765,7 +1783,7 @@ const device_t et4000w32p_cardex_pci_device = const device_t et4000w32p_vlb_device = { - "Tseng Labs ET4000/w32p VLB (Diamond)", + "Tseng Labs ET4000/w32p Rev. D VLB (Diamond Stealth32)", DEVICE_VLB, ET4000W32P_DIAMOND, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_available }, @@ -1776,7 +1794,7 @@ const device_t et4000w32p_vlb_device = const device_t et4000w32p_pci_device = { - "Tseng Labs ET4000/w32p PCI (Diamond)", + "Tseng Labs ET4000/w32p Rev. D PCI (Diamond Stealth32)", DEVICE_PCI, ET4000W32P_DIAMOND, et4000w32p_init, et4000w32p_close, NULL, { et4000w32p_available }, diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 5fd0aada0..107a1773f 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -231,7 +231,7 @@ uint8_t paradise_in(uint16_t addr, void *p) case 0x3cf: if (svga->gdcaddr >= 9 && svga->gdcaddr <= 0x0e) { - if ((paradise->pr5 & 7) != 5) + if (paradise->pr5 & 0x10) return 0xff; } switch (svga->gdcaddr) { @@ -354,8 +354,11 @@ void paradise_recalctimings(svga_t *svga) } if (paradise->type < WD90C30) { - if (svga->bpp >= 8 && !svga->lowres) + if (svga->bpp >= 8 && !svga->lowres) { + if ((svga->crtc[0x17] == 0xc2) && (svga->crtc[0x14] & 0x40)) + paradise->check = 1; svga->render = svga_render_8bpp_highres; + } } else { if (svga->bpp >= 8 && !svga->lowres) { if (svga->bpp == 16) { From b4ac1042dd75c94d13018eb72d757428eba59050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 7 Nov 2021 13:49:25 +0100 Subject: [PATCH 098/140] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92fc718dd..3dcf0f3a6 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ We operate an IRC channel and a Discord server for discussing 86Box, its develop Licensing --------- -86Box is released under the [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) only. For more information, see the `COPYING` file in the root of the repository. +86Box is released under the [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or later. For more information, see the `COPYING` file in the root of the repository. The emulator can also optionally make use of [munt](https://github.com/munt/munt), [FluidSynth](https://www.fluidsynth.org/), [Ghostscript](https://www.ghostscript.com/) and [Discord Game SDK](https://discord.com/developers/docs/game-sdk/sdk-starter-guide), which are distributed under their respective licenses. From 452e2348dabd640a915fba6ed335b13006e9fabf Mon Sep 17 00:00:00 2001 From: dob205 Date: Sun, 7 Nov 2021 18:00:18 +0100 Subject: [PATCH 099/140] Removes timespec_get() from Unix systems This change removes timespec_get() from Unix systems and makes it also possible to cross-compile binaries on macOS Big Sur or macOS Monterrey that target macOS Mojave at minimum since Mojave lacks support for timespec_get(). --- src/unix/unix_thread.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/unix/unix_thread.c b/src/unix/unix_thread.c index d95c337d1..f045d2820 100644 --- a/src/unix/unix_thread.c +++ b/src/unix/unix_thread.c @@ -101,11 +101,7 @@ thread_wait_event(event_t *handle, int timeout) event_pthread_t *event = (event_pthread_t *)handle; struct timespec abstime; -#ifdef HAS_TIMESPEC_GET - timespec_get(&abstime, TIME_UTC); -#else clock_gettime(CLOCK_REALTIME, &abstime); -#endif abstime.tv_nsec += (timeout % 1000) * 1000000; abstime.tv_sec += (timeout / 1000); if (abstime.tv_nsec > 1000000000) { From 82973668576ca0dfb4647e3528b797d5ca24608d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 7 Nov 2021 18:29:49 +0100 Subject: [PATCH 100/140] Changed Discord rich presence ID. --- src/win/win_discord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/win_discord.c b/src/win/win_discord.c index 61b300341..066c927d3 100644 --- a/src/win/win_discord.c +++ b/src/win/win_discord.c @@ -147,7 +147,7 @@ discord_init() return; DiscordCreateParamsSetDefault(¶ms); - params.client_id = 651478134352248832; + params.client_id = 906956844956782613; params.flags = DiscordCreateFlags_NoRequireDiscord; result = discord_create(DISCORD_VERSION, ¶ms, &discord_core); From 56e93959b4cbff21575763724774dc7fd58d0ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sun, 7 Nov 2021 21:32:06 +0100 Subject: [PATCH 101/140] Initial commit for multilingual UI, and Hungarian translation --- src/win/86Box.rc | 981 +------------------------------------ src/win/languages/en-US.rc | 975 ++++++++++++++++++++++++++++++++++++ src/win/languages/hu-HU.rc | 978 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1959 insertions(+), 975 deletions(-) create mode 100644 src/win/languages/en-US.rc create mode 100644 src/win/languages/hu-HU.rc diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 05990324f..cb2d306a5 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -14,6 +14,7 @@ * * Copyright 2016-2019 Miran Grca. * Copyright 2018,2019 David Hrdlička. + * Copyright 2021 Laci bá' */ #define IN_RESOURCE_H #include <86box/resource.h> @@ -27,271 +28,7 @@ #undef APSTUDIO_HIDDEN_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(65001) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -MainMenu MENU DISCARDABLE -BEGIN - POPUP "&Action" - BEGIN - MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE - MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT - MENUITEM SEPARATOR - MENUITEM "&Hard Reset", IDM_ACTION_HRESET - MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD - MENUITEM SEPARATOR - MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC - MENUITEM SEPARATOR - MENUITEM "&Pause", IDM_ACTION_PAUSE - MENUITEM SEPARATOR - MENUITEM "E&xit", IDM_ACTION_EXIT - END - POPUP "&View" - BEGIN - MENUITEM "&Hide status bar", IDM_VID_HIDE_STATUS_BAR - MENUITEM SEPARATOR - MENUITEM "&Resizeable window", IDM_VID_RESIZE - MENUITEM "R&emember size && position", IDM_VID_REMEMBER - MENUITEM SEPARATOR - POPUP "Re&nderer" - BEGIN - MENUITEM "&SDL (Software)", IDM_VID_SDL_SW - MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW - MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL -#if defined(DEV_BRANCH) && defined(USE_OPENGL) - MENUITEM "Open&GL (3.3 Core)", IDM_VID_OPENGL_CORE -#endif -#ifdef USE_VNC - MENUITEM "&VNC", IDM_VID_VNC -#endif - END - MENUITEM SEPARATOR - MENUITEM "Specify dimensions", IDM_VID_SPECIFY_DIM - MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 - POPUP "&Window scale factor" - BEGIN - MENUITEM "&0.5x", IDM_VID_SCALE_1X - MENUITEM "&1x", IDM_VID_SCALE_2X - MENUITEM "1.&5x", IDM_VID_SCALE_3X - MENUITEM "&2x", IDM_VID_SCALE_4X - END - POPUP "Filter method" - BEGIN - MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST - MENUITEM "&Linear", IDM_VID_FILTER_LINEAR - END - MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI - MENUITEM SEPARATOR - MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN - POPUP "Fullscreen &stretch mode" - BEGIN - MENUITEM "&Full screen stretch", IDM_VID_FS_FULL - MENUITEM "&4:3", IDM_VID_FS_43 - MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO - MENUITEM "&Integer scale", IDM_VID_FS_INT - END - POPUP "E&GA/(S)VGA settings" - BEGIN - MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT - POPUP "VGA screen &type" - BEGIN - MENUITEM "RGB &Color", IDM_VID_GRAY_RGB - MENUITEM "&RGB Grayscale", IDM_VID_GRAY_MONO - MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER - MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN - MENUITEM "&White monitor", IDM_VID_GRAY_WHITE - END - POPUP "Grayscale &conversion type" - BEGIN - MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 - MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 - MENUITEM "&Average", IDM_VID_GRAYCT_AVE - END - END - MENUITEM SEPARATOR - MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN - MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON - END - MENUITEM "&Media", IDM_MEDIA - POPUP "&Tools" - BEGIN - MENUITEM "&Settings...", IDM_CONFIG - MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS -# ifdef USE_DISCORD - MENUITEM SEPARATOR - MENUITEM "Enable &Discord integration", IDM_DISCORD -# endif - MENUITEM SEPARATOR - MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT - MENUITEM SEPARATOR - MENUITEM "Sound &gain...", IDM_SND_GAIN -#ifdef MTR_ENABLED - MENUITEM SEPARATOR - MENUITEM "Begin trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE - MENUITEM "End trace\tCtrl+T", IDM_ACTION_END_TRACE -#endif - END -#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) - POPUP "&Logging" - BEGIN -# ifdef ENABLE_BUSLOGIC_LOG - MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC -# endif -# ifdef ENABLE_CDROM_LOG - MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM -# endif -# ifdef ENABLE_D86F_LOG - MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F -# endif -# ifdef ENABLE_FDC_LOG - MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC -# endif -# ifdef ENABLE_IDE_LOG - MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE -# endif -# ifdef ENABLE_SERIAL_LOG - MENUITEM "Enable Serial Port logs\tCtrl+F3", IDM_LOG_SERIAL -# endif -# ifdef ENABLE_NIC_LOG - MENUITEM "Enable Network logs\tCtrl+F9", IDM_LOG_NIC -# endif -# ifdef ENABLE_LOG_COMMANDS -# ifdef ENABLE_LOG_TOGGLES - MENUITEM SEPARATOR -# endif -# ifdef ENABLE_LOG_BREAKPOINT - MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT -# endif -# ifdef ENABLE_VRAM_DUMP - MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM -# endif -# endif - END -#endif - POPUP "&Help" - BEGIN - MENUITEM "&Documentation...", IDM_DOCS - MENUITEM "&About 86Box...", IDM_ABOUT - END -END - -StatusBarMenu MENU DISCARDABLE -BEGIN - MENUITEM SEPARATOR -END - -CassetteSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_CASSETTE_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_CASSETTE_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_CASSETTE_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "&Record", IDM_CASSETTE_RECORD - MENUITEM "&Play", IDM_CASSETTE_PLAY - MENUITEM "&Rewind to the beginning", IDM_CASSETTE_REWIND - MENUITEM "&Fast forward to the end", IDM_CASSETTE_FAST_FORWARD - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_CASSETTE_EJECT - END -END - -CartridgeSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&Image...", IDM_CARTRIDGE_IMAGE - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_CARTRIDGE_EJECT - END -END - -FloppySubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_FLOPPY_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_FLOPPY_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_FLOPPY_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&xport to 86F...", IDM_FLOPPY_EXPORT_TO_86F - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_FLOPPY_EJECT - END -END - -CdromSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&Mute", IDM_CDROM_MUTE - MENUITEM SEPARATOR - MENUITEM "E&mpty", IDM_CDROM_EMPTY - MENUITEM "&Reload previous image", IDM_CDROM_RELOAD - MENUITEM SEPARATOR - MENUITEM "&Image", IDM_CDROM_IMAGE - END -END - -ZIPSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_ZIP_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_ZIP_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_ZIP_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_ZIP_EJECT - MENUITEM "&Reload previous image", IDM_ZIP_RELOAD - END -END - -MOSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_MO_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_MO_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_MO_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_MO_EJECT - MENUITEM "&Reload previous image", IDM_MO_RELOAD - END -END - -#if defined(DEV_BRANCH) && defined(USE_OPENGL) -VidGLSubMenu MENU DISCARDABLE -BEGIN - POPUP "Target &framerate" - BEGIN - MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER - MENUITEM "&25 fps", IDM_VID_GL_FPS_25 - MENUITEM "&30 fps", IDM_VID_GL_FPS_30 - MENUITEM "&50 fps", IDM_VID_GL_FPS_50 - MENUITEM "&60 fps", IDM_VID_GL_FPS_60 - MENUITEM "&75 fps", IDM_VID_GL_FPS_75 - END - MENUITEM "&VSync", IDM_VID_GL_VSYNC - MENUITEM "&Select shader...", IDM_VID_GL_SHADER - MENUITEM "&Remove shader", IDM_VID_GL_NOSHADER -END -#endif ///////////////////////////////////////////////////////////////////////////// // @@ -337,472 +74,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// -DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Status" -FONT 9, "Segoe UI" -BEGIN - LTEXT "1",IDT_SDEVICE,16,16,180,1000 - LTEXT "1",IDT_STEXT,16,186,180,1000 -END - -DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Sound Gain" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,57,7,50,14 - PUSHBUTTON "Cancel",IDCANCEL,57,24,50,14 - CONTROL "Gain",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_VERT | - TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP,15,20,20,109 - CTEXT "Gain",IDT_1746,10,7,32,9,SS_CENTERIMAGE -END - -DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "New Image" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,104,65,50,14 - PUSHBUTTON "Cancel",IDCANCEL,162,65,50,14 - LTEXT "File name:",IDT_1749,7,6,44,12,SS_CENTERIMAGE - LTEXT "Disk size:",IDT_1750,7,25,44,12,SS_CENTERIMAGE - LTEXT "RPM mode:",IDT_1751,7,45,44,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_FILE_NAME,53,5,150,14,ES_AUTOHSCROLL | ES_READONLY - COMBOBOX IDC_COMBO_DISK_SIZE,53,25,166,14,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO_RPM_MODE,53,45,166,14,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "...",IDC_CFILE,206,5,13,14 - LTEXT "Progress:",IDT_1757,7,45,44,12,SS_CENTERIMAGE - CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | - WS_BORDER,53,45,166,14 -END - -DLG_CONFIG DIALOG DISCARDABLE 0, 0, 376, 256 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "86Box Settings" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,246,235,50,14 - PUSHBUTTON "Cancel",IDCANCEL,307,235,50,14 - CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 - CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 -/* Leave this commented out until we get into localization. */ -#if 0 - LTEXT "Language:",IDT_1700,7,237,41,10 - COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | - WS_TABSTOP -#endif -END - -DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Specify Main Window Dimensions" -FONT 9, "Segoe UI" -BEGIN - LTEXT "Width:",IDT_1709,7,9,24,12 - EDITTEXT IDC_EDIT_WIDTH,33,7,45,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "",IDC_WIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,76,6, - 12,12 - LTEXT "Height:",IDT_1710,97,9,24,12 - EDITTEXT IDC_EDIT_HEIGHT,123,7,45,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "",IDC_HEIGHTSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,166,6, - 12,12 - CONTROL "Lock to this size",IDC_CHECK_LOCK_SIZE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,26,94,10 - DEFPUSHBUTTON "OK",IDOK,30,45,50,14 - PUSHBUTTON "Cancel",IDCANCEL,99,45,50,14 -END - -DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 200 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - COMBOBOX IDC_COMBO_MACHINE_TYPE,71,7,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Machine type:",IDT_1708,7,9,60,10 - COMBOBOX IDC_COMBO_MACHINE,71,26,138,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Machine:",IDT_1701,7,28,60,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,26,46,12 - COMBOBOX IDC_COMBO_CPU_TYPE,71,45,110,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "CPU type:",IDT_1702,7,47,59,10 - COMBOBOX IDC_COMBO_CPU,215,45,45,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Speed:",IDT_1704,189,47,24,10 - COMBOBOX IDC_COMBO_FPU,71,64,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "FPU:",IDT_1707,7,66,59,10 - COMBOBOX IDC_COMBO_WS,71,83,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "Wait states:",IDT_1703,7,85,60,10 - EDITTEXT IDC_MEMTEXT,70,102,45,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, - 12,12 - LTEXT "MB",IDT_1705,123,104,10,10 - LTEXT "Memory:",IDT_1706,7,104,30,10 - GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,135,100,56 - CONTROL "Disabled",IDC_RADIO_TS_DISABLED,"Button", - BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,147,84,10 - CONTROL "Enabled (local time)", IDC_RADIO_TS_LOCAL,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,84,10 - CONTROL "Enabled (UTC)", IDC_RADIO_TS_UTC,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,84,10 -#ifdef USE_DYNAREC - CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 -#endif -END - -DLG_CFG_VIDEO DIALOG DISCARDABLE 107, 0, 267, 45 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Video:",IDT_1707,7,9,48,10 - COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_VID,222,7,38,12 - CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,222,26,38,12 -END - -DLG_CFG_INPUT DIALOG DISCARDABLE 107, 0, 267, 65 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Mouse:",IDT_1709,7,9,57,10 - COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_MOUSE,214,7,46,12 - LTEXT "Joystick:",IDT_1710,7,27,58,10 - COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 - PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 - PUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 - PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 -END - -DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 201 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "Sound card:",IDT_1711,7,9,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 - - COMBOBOX IDC_COMBO_MIDI,71,26,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "MIDI Out Device:",IDT_1712,7,28,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,26,46,12 - - COMBOBOX IDC_COMBO_MIDI_IN,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "MIDI In Device:",IDT_1713,7,47,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,45,46,12 - - CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 - - CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,84,95,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_SSI,214,82,46,12 - - CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,102,95,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_CMS,214,100,46,12 - - CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,118,46,12 - - CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,138,94,10 -END - -DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 65 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Network type:",IDT_1714,7,9,59,10 - COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - - LTEXT "PCap device:",IDT_1715,7,28,59,10 - COMBOBOX IDC_COMBO_PCAP,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - - LTEXT "Network adapter:",IDT_1716,7,47,59,10 - COMBOBOX IDC_COMBO_NET,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,44,46,12 -END - -DLG_CFG_PORTS DIALOG DISCARDABLE 107, 0, 267, 135 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "LPT1 Device:",IDT_1717,7,9,61,10 - COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - LTEXT "LPT2 Device:",IDT_1718,7,28,61,10 - COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - LTEXT "LPT3 Device:",IDT_1719,7,47,61,10 - COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - CONTROL "Serial port 1",IDC_CHECK_SERIAL1,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,64,94,10 - CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 - CONTROL "Serial port 3",IDC_CHECK_SERIAL3,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 - CONTROL "Serial port 4",IDC_CHECK_SERIAL4,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 - - CONTROL "Parallel port 1",IDC_CHECK_PARALLEL1,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 - CONTROL "Parallel port 2",IDC_CHECK_PARALLEL2,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,100,94,10 - CONTROL "Parallel port 3",IDC_CHECK_PARALLEL3,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,118,94,10 -END - -DLG_CFG_STORAGE DIALOG DISCARDABLE 107, 0, 267, 203 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "HD Controller:",IDT_1718,7,9,64,10 - COMBOBOX IDC_COMBO_HDC,64,7,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,7,38,12 - - LTEXT "FD Controller:",IDT_1768,7,28,64,10 - COMBOBOX IDC_COMBO_FDC,64,26,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_FDC,222,26,38,12 - - CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,47,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,45,38,12 - - CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,64,38,12 - - GROUPBOX "SCSI",IDC_GROUP_SCSI,7,85,253,93 - LTEXT "Controller 1:",IDT_1763,16,102,48,10 - COMBOBOX IDC_COMBO_SCSI_1,73,100,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_1,213,100,38,12 - LTEXT "Controller 2:",IDT_1764,16,121,48,10 - COMBOBOX IDC_COMBO_SCSI_2,73,119,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_2,213,119,38,12 - LTEXT "Controller 3:",IDT_1765,16,140,48,10 - COMBOBOX IDC_COMBO_SCSI_3,73,138,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_3,213,138,38,12 - LTEXT "Controller 4:",IDT_1766,16,159,48,10 - COMBOBOX IDC_COMBO_SCSI_4,73,157,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_4,213,157,38,12 - - CONTROL "Cassette",IDC_CHECK_CASSETTE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,185,94,10 -END - -DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 107, 0, 267, 154 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,18,253,92 - LTEXT "Hard disks:",IDT_1720,7,7,253,8 - PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 - PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 - PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 - COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,119,24,8 - COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,131,119,38,8 - COMBOBOX IDC_COMBO_HD_ID,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,131,119,38,8 - COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP -END - -DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 149 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Add Hard Disk" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,55,127,50,14 - PUSHBUTTON "Cancel",IDCANCEL,112,127,50,14 - EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 - PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 - EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 - EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 - EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 - EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 - COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Sectors:",IDT_1726,154,35,27,10 - LTEXT "Heads:",IDT_1727,81,35,29,8 - LTEXT "Cylinders:",IDT_1728,7,35,32,12 - LTEXT "Size (MB):",IDT_1729,7,54,33,8 - LTEXT "Type:",IDT_1730,86,54,24,8 - LTEXT "File name:",IDT_1731,7,7,204,9 - COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,73,24,8 - COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,99,73,34,8 - COMBOBOX IDC_COMBO_HD_ID,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,99,73,34,8 - COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Image Format:",IDT_1774,7,92,50,12 - COMBOBOX IDC_COMBO_HD_IMG_FORMAT,58,90,153,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Block Size:",IDT_1775,7,111,50,12 - COMBOBOX IDC_COMBO_HD_BLOCK_SIZE,58,109,153,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Progress:",IDT_1752,7,7,204,9 - CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | - WS_BORDER,7,16,204,12 -END - -DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE 107, 0, 267, 222 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,18,253,60 - LTEXT "Floppy drives:",IDT_1737,7,7,253,8 - COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDT_1738,7,87,24,8 - CONTROL "Turbo timings",IDC_CHECKTURBO,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 - CONTROL "Check BPB",IDC_CHECKBPB,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,196,86,64,10 - - CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,117,253,60 - LTEXT "CD-ROM drives:",IDT_1739,7,107,253,8 - COMBOBOX IDC_COMBO_CD_BUS,33,185,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1740,7,187,24,8 - COMBOBOX IDC_COMBO_CD_ID,170,185,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1741,131,187,38,8 - COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,185,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1742,131,187,38,8 - COMBOBOX IDC_COMBO_CD_SPEED,33,205,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Speed:",IDT_1758,7,207,24,8 -END - -DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 107, 0, 267, 222 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - - CONTROL "List1",IDC_LIST_MO_DRIVES,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,17,253,60 - LTEXT "MO drives:",IDT_1769,7,7,253,8 - COMBOBOX IDC_COMBO_MO_BUS,33,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1770,7,87,24,8 - COMBOBOX IDC_COMBO_MO_ID,170,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1771,131,87,38,8 - COMBOBOX IDC_COMBO_MO_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1772,131,87,38,8 - COMBOBOX IDC_COMBO_MO_TYPE,33,105,120,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDT_1773,7,107,24,8 - - CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,137,253,60 - LTEXT "ZIP drives:",IDT_1759,7,127,253,8 - COMBOBOX IDC_COMBO_ZIP_BUS,23,205,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1753,7,207,14,8 - COMBOBOX IDC_COMBO_ZIP_ID,149,205,61,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1754,120,207,28,8 - COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,149,205,61,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1755,120,207,28,8 - CONTROL "ZIP 250",IDC_CHECK250,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,218,205,44,10 -END - -DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 154 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "ISA RTC:",IDT_1767,7,9,48,10 - COMBOBOX IDC_COMBO_ISARTC,64,7,155,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,7,38,12 - - GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,28,253,93 - LTEXT "Card 1:",IDT_1763,16,45,48,10 - COMBOBOX IDC_COMBO_ISAMEM_1,73,43,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,213,43,38,12 - LTEXT "Card 2:",IDT_1764,16,64,48,10 - COMBOBOX IDC_COMBO_ISAMEM_2,73,62,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,213,62,38,12 - LTEXT "Card 3:",IDT_1765,16,83,48,10 - COMBOBOX IDC_COMBO_ISAMEM_3,73,81,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,213,81,38,12 - LTEXT "Card 4:",IDT_1766,16,102,48,10 - COMBOBOX IDC_COMBO_ISAMEM_4,73,100,137,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,213,100,38,12 - - CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,128,94,10 - - CONTROL "POST card",IDC_CHECK_POSTCARD,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,128,94,10 -END - - #ifndef NO_INCLUDE_MANIFEST ///////////////////////////////////////////////////////////////////////////// // @@ -1033,249 +304,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE DISCARDABLE -BEGIN - 2048 "86Box" - IDS_2049 "Error" - IDS_2050 "Fatal error" - IDS_2051 "" - IDS_2052 "Press CTRL+ALT+PAGE DOWN to return to windowed mode." - IDS_2053 "Speed" - IDS_2054 "ZIP %03i %i (%s): %ls" - IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" - IDS_2056 "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the ""roms"" directory." - IDS_2057 "(empty)" - IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" - IDS_2059 "Turbo" - IDS_2060 "On" - IDS_2061 "Off" - IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" - IDS_2063 "Machine ""%hs"" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_2064 "Video card ""%hs"" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." - IDS_2065 "Machine" - IDS_2066 "Display" - IDS_2067 "Input devices" - IDS_2068 "Sound" - IDS_2069 "Network" - IDS_2070 "Ports (COM & LPT)" - IDS_2071 "Storage controllers" - IDS_2072 "Hard disks" - IDS_2073 "Floppy & CD-ROM drives" - IDS_2074 "Other removable devices" - IDS_2075 "Other peripherals" - IDS_2076 "Surface images (*.86F)\0*.86F\0" - IDS_2077 "Click to capture mouse" - IDS_2078 "Press F8+F12 to release mouse" - IDS_2079 "Press F8+F12 or middle button to release mouse" -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_2080 "Unable to initialize FluidSynth" - IDS_2081 "Bus" - IDS_2082 "File" - IDS_2083 "C" - IDS_2084 "H" - IDS_2085 "S" - IDS_2086 "MB" - IDS_2087 "Check BPB" - IDS_2088 "KB" - IDS_2089 "Could not initialize the video renderer." - IDS_2090 "Default" - IDS_2091 "%i Wait state(s)" - IDS_2092 "Type" - IDS_2093 "Failed to set up PCap" - IDS_2094 "No PCap devices found" - IDS_2095 "Invalid PCap device" - IDS_2096 "Standard 2-button joystick(s)" - IDS_2097 "Standard 4-button joystick" - IDS_2098 "Standard 6-button joystick" - IDS_2099 "Standard 8-button joystick" - IDS_2100 "CH Flightstick Pro" - IDS_2101 "Microsoft SideWinder Pad" - IDS_2102 "Thrustmaster Flight Control System" - IDS_2103 "None" - IDS_2104 "Unable to load keyboard accelerators." - IDS_2105 "Unable to register raw input." - IDS_2106 "%u" - IDS_2107 "%u MB (CHS: %i, %i, %i)" - IDS_2108 "Floppy %i (%s): %ls" - IDS_2109 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" - IDS_2110 "Unable to initialize FreeType" - IDS_2111 "Unable to initialize SDL, SDL2.dll is required" - IDS_2112 "Are you sure you want to hard reset the emulated machine?" - IDS_2113 "Are you sure you want to exit 86Box?" - IDS_2114 "Unable to initialize Ghostscript" - IDS_2115 "MO %i (%ls): %ls" - IDS_2116 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" - IDS_2117 "Welcome to 86Box!" - IDS_2118 "Internal controller" - IDS_2119 "Exit" - IDS_2120 "No ROMs found" - IDS_2121 "Do you want to save the settings?" - IDS_2122 "This will hard reset the emulated machine." - IDS_2123 "Save" - IDS_2124 "About 86Box" - IDS_2125 "86Box v" EMU_VERSION - IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." - IDS_2127 "OK" - IDS_2128 "Hardware not available" -#ifdef _WIN32 -#define LIB_NAME_PCAP "WinPcap" -#else -#define LIB_NAME_PCAP "libpcap" -#endif - IDS_2129 "Make sure " LIB_NAME_PCAP " is installed and that you are on a " LIB_NAME_PCAP "-compatible network connection." - IDS_2130 "Invalid configuration" -#ifdef _WIN32 -#define LIB_NAME_FREETYPE "freetype.dll" -#else -#define LIB_NAME_FREETYPE "libfreetype" -#endif - IDS_2131 LIB_NAME_FREETYPE " is required for ESC/P printer emulation." -#ifdef _WIN32 -#define LIB_NAME_GS "gsdll32.dll" -#else -#define LIB_NAME_GS "libgs" -#endif - IDS_2132 LIB_NAME_GS " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." -#ifdef _WIN32 -#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" -#else -#define LIB_NAME_FLUIDSYNTH "libfluidsynth" -#endif - IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." - IDS_2134 "Entering fullscreen mode" - IDS_2135 "Don't show this message again" - IDS_2136 "Don't exit" - IDS_2137 "Reset" - IDS_2138 "Don't reset" - IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" - IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" - IDS_2141 "%hs Device Configuration" - IDS_2142 "Monitor in sleep mode" - IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" - IDS_2144 "OpenGL options" - IDS_2145 "You are loading an unsupported configuration" - IDS_2146 "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." - IDS_2147 "Continue" - IDS_2148 "Cassette: %s" - IDS_2149 "Cassette images (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0All files (*.*)\0*.*\0" - IDS_2150 "Cartridge %i: %ls" - IDS_2151 "Cartridge images (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0All files (*.*)\0*.*\0" -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_4096 "Hard disk (%s)" - IDS_4097 "%01i:%01i" - IDS_4098 "%01i" - IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" - IDS_4100 "Custom..." - IDS_4101 "Custom (large)..." - IDS_4102 "Add New Hard Disk" - IDS_4103 "Add Existing Hard Disk" - IDS_4104 "HDI disk images cannot be larger than 4 GB." - IDS_4105 "Disk images cannot be larger than 127 GB." - IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" - IDS_4107 "Unable to read file" - IDS_4108 "Unable to write file" - IDS_4109 "HDI or HDX images with a sector size other than 512 are not supported." - IDS_4110 "USB is not yet supported" - IDS_4111 "Disk image file already exists" - IDS_4112 "Please specify a valid file name." - IDS_4113 "Disk image created" - IDS_4114 "Make sure the file exists and is readable." - IDS_4115 "Make sure the file is being saved to a writable directory." - IDS_4116 "Disk image too large" - IDS_4117 "Remember to partition and format the newly-created drive." - IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" - IDS_4119 "Unsupported disk image" - IDS_4120 "Overwrite" - IDS_4121 "Don't overwrite" - IDS_4122 "Raw image (.img)" - IDS_4123 "HDI image (.hdi)" - IDS_4124 "HDX image (.hdx)" - IDS_4125 "Fixed-size VHD (.vhd)" - IDS_4126 "Dynamic-size VHD (.vhd)" - IDS_4127 "Differencing VHD (.vhd)" - IDS_4128 "Large blocks (2 MB)" - IDS_4129 "Small blocks (512 KB)" - IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" - IDS_4131 "Select the parent VHD" - IDS_4132 "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" - IDS_4133 "Parent and child disk timestamps do not match" - IDS_4134 "Could not fix VHD timestamp." - IDS_4135 "%01i:%02i" - - IDS_4352 "MFM/RLL" - IDS_4353 "XTA" - IDS_4354 "ESDI" - IDS_4355 "IDE" - IDS_4356 "ATAPI" - IDS_4357 "SCSI" - - IDS_4608 "MFM/RLL (%01i:%01i)" - IDS_4609 "XTA (%01i:%01i)" - IDS_4610 "ESDI (%01i:%01i)" - IDS_4611 "IDE (%01i:%01i)" - IDS_4612 "ATAPI (%01i:%01i)" - IDS_4613 "SCSI (%01i:%02i)" - - IDS_5120 "CD-ROM %i (%s): %s" - - IDS_5376 "Disabled" - IDS_5381 "ATAPI" - IDS_5382 "SCSI" - - IDS_5632 "Disabled" - IDS_5637 "ATAPI (%01i:%01i)" - IDS_5638 "SCSI (%01i:%02i)" - - IDS_5888 "160 kB" - IDS_5889 "180 kB" - IDS_5890 "320 kB" - IDS_5891 "360 kB" - IDS_5892 "640 kB" - IDS_5893 "720 kB" - IDS_5894 "1.2 MB" - IDS_5895 "1.25 MB" - IDS_5896 "1.44 MB" - IDS_5897 "DMF (cluster 1024)" - IDS_5898 "DMF (cluster 2048)" - IDS_5899 "2.88 MB" - IDS_5900 "ZIP 100" - IDS_5901 "ZIP 250" - IDS_5902 "3.5"" 128Mb M.O. (ISO 10090)" - IDS_5903 "3.5"" 230Mb M.O. (ISO 13963)" - IDS_5904 "3.5"" 540Mb M.O. (ISO 15498)" - IDS_5905 "3.5"" 640Mb M.O. (ISO 15498)" - IDS_5906 "3.5"" 1.3Gb M.O. (GigaMO)" - IDS_5907 "3.5"" 2.3Gb M.O. (GigaMO 2)" - IDS_5908 "5.25"" 600Mb M.O." - IDS_5909 "5.25"" 650Mb M.O." - IDS_5910 "5.25"" 1Gb M.O." - IDS_5911 "5.25"" 1.3Gb M.O." - - IDS_6144 "Perfect RPM" - IDS_6145 "1%% below perfect RPM" - IDS_6146 "1.5%% below perfect RPM" - IDS_6147 "2%% below perfect RPM" - - IDS_7168 "English (United States)" -END -#define IDS_LANG_ENUS IDS_7168 - - #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // @@ -1317,8 +345,7 @@ END #endif // !_MAC -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// +#endif @@ -1331,3 +358,7 @@ END ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED + + +#include "languages/en-US.rc" +#include "languages/hu-HU.rc" \ No newline at end of file diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc new file mode 100644 index 000000000..8a0b4d9ab --- /dev/null +++ b/src/win/languages/en-US.rc @@ -0,0 +1,975 @@ +//////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(65001) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_ACTION_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Hide status bar", IDM_VID_HIDE_STATUS_BAR + MENUITEM SEPARATOR + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL +#if defined(DEV_BRANCH) && defined(USE_OPENGL) + MENUITEM "Open&GL (3.3 Core)", IDM_VID_OPENGL_CORE +#endif +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Specify dimensions", IDM_VID_SPECIFY_DIM + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Filter method" + BEGIN + MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA settings" + BEGIN + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + POPUP "VGA screen &type" + BEGIN + MENUITEM "RGB &Color", IDM_VID_GRAY_RGB + MENUITEM "&RGB Grayscale", IDM_VID_GRAY_MONO + MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN + MENUITEM "&White monitor", IDM_VID_GRAY_WHITE + END + POPUP "Grayscale &conversion type" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Average", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS +# ifdef USE_DISCORD + MENUITEM SEPARATOR + MENUITEM "Enable &Discord integration", IDM_DISCORD +# endif + MENUITEM SEPARATOR + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "Sound &gain...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Begin trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "End trace\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END +#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) + POPUP "&Logging" + BEGIN +# ifdef ENABLE_BUSLOGIC_LOG + MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC +# endif +# ifdef ENABLE_CDROM_LOG + MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM +# endif +# ifdef ENABLE_D86F_LOG + MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F +# endif +# ifdef ENABLE_FDC_LOG + MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC +# endif +# ifdef ENABLE_IDE_LOG + MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE +# endif +# ifdef ENABLE_SERIAL_LOG + MENUITEM "Enable Serial Port logs\tCtrl+F3", IDM_LOG_SERIAL +# endif +# ifdef ENABLE_NIC_LOG + MENUITEM "Enable Network logs\tCtrl+F9", IDM_LOG_NIC +# endif +# ifdef ENABLE_LOG_COMMANDS +# ifdef ENABLE_LOG_TOGGLES + MENUITEM SEPARATOR +# endif +# ifdef ENABLE_LOG_BREAKPOINT + MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT +# endif +# ifdef ENABLE_VRAM_DUMP + MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM +# endif +# endif + END +#endif + POPUP "&Help" + BEGIN + MENUITEM "&Documentation...", IDM_DOCS + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Record", IDM_CASSETTE_RECORD + MENUITEM "&Play", IDM_CASSETTE_PLAY + MENUITEM "&Rewind to the beginning", IDM_CASSETTE_REWIND + MENUITEM "&Fast forward to the end", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Image...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xport to 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Mute", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_EMPTY + MENUITEM "&Reload previous image", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_ZIP_EJECT + MENUITEM "&Reload previous image", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_MO_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_MO_EJECT + MENUITEM "&Reload previous image", IDM_MO_RELOAD + END +END + +#if defined(DEV_BRANCH) && defined(USE_OPENGL) +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Target &framerate" + BEGIN + MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Select shader...", IDM_VID_GL_SHADER + MENUITEM "&Remove shader", IDM_VID_GL_NOSHADER +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// +DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDT_SDEVICE,16,16,180,1000 + LTEXT "1",IDT_STEXT,16,186,180,1000 +END + +DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sound Gain" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,57,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,57,24,50,14 + CONTROL "Gain",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_VERT | + TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP,15,20,20,109 + CTEXT "Gain",IDT_1746,10,7,32,9,SS_CENTERIMAGE +END + +DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Image" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,104,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,162,65,50,14 + LTEXT "File name:",IDT_1749,7,6,44,12,SS_CENTERIMAGE + LTEXT "Disk size:",IDT_1750,7,25,44,12,SS_CENTERIMAGE + LTEXT "RPM mode:",IDT_1751,7,45,44,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_FILE_NAME,53,5,150,14,ES_AUTOHSCROLL | ES_READONLY + COMBOBOX IDC_COMBO_DISK_SIZE,53,25,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_RPM_MODE,53,45,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "...",IDC_CFILE,206,5,13,14 + LTEXT "Progress:",IDT_1757,7,45,44,12,SS_CENTERIMAGE + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,53,45,166,14 +END + +DLG_CONFIG DIALOG DISCARDABLE 0, 0, 376, 256 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "86Box Settings" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,246,235,50,14 + PUSHBUTTON "Cancel",IDCANCEL,307,235,50,14 + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 +/* Leave this commented out until we get into localization. */ +#if 0 + LTEXT "Language:",IDT_1700,7,237,41,10 + COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +#endif +END + +DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Specify Main Window Dimensions" +FONT 9, "Segoe UI" +BEGIN + LTEXT "Width:",IDT_1709,7,9,24,12 + EDITTEXT IDC_EDIT_WIDTH,33,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_WIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,76,6, + 12,12 + LTEXT "Height:",IDT_1710,97,9,24,12 + EDITTEXT IDC_EDIT_HEIGHT,123,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_HEIGHTSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,166,6, + 12,12 + CONTROL "Lock to this size",IDC_CHECK_LOCK_SIZE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,26,94,10 + DEFPUSHBUTTON "OK",IDOK,30,45,50,14 + PUSHBUTTON "Cancel",IDCANCEL,99,45,50,14 +END + +DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 200 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_MACHINE_TYPE,71,7,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Machine type:",IDT_1708,7,9,60,10 + COMBOBOX IDC_COMBO_MACHINE,71,26,138,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Machine:",IDT_1701,7,28,60,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,26,46,12 + COMBOBOX IDC_COMBO_CPU_TYPE,71,45,110,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU type:",IDT_1702,7,47,59,10 + COMBOBOX IDC_COMBO_CPU,215,45,45,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Speed:",IDT_1704,189,47,24,10 + COMBOBOX IDC_COMBO_FPU,71,64,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "FPU:",IDT_1707,7,66,59,10 + COMBOBOX IDC_COMBO_WS,71,83,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Wait states:",IDT_1703,7,85,60,10 + EDITTEXT IDC_MEMTEXT,70,102,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, + 12,12 + LTEXT "MB",IDT_1705,123,104,10,10 + LTEXT "Memory:",IDT_1706,7,104,30,10 + GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,135,100,56 + CONTROL "Disabled",IDC_RADIO_TS_DISABLED,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,147,84,10 + CONTROL "Enabled (local time)", IDC_RADIO_TS_LOCAL,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,84,10 + CONTROL "Enabled (UTC)", IDC_RADIO_TS_UTC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,84,10 +#ifdef USE_DYNAREC + CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 +#endif +END + +DLG_CFG_VIDEO DIALOG DISCARDABLE 107, 0, 267, 45 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Video:",IDT_1707,7,9,48,10 + COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_VID,222,7,38,12 + CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,222,26,38,12 +END + +DLG_CFG_INPUT DIALOG DISCARDABLE 107, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Mouse:",IDT_1709,7,9,57,10 + COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_MOUSE,214,7,46,12 + LTEXT "Joystick:",IDT_1710,7,27,58,10 + COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 + PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 + PUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 + PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 +END + +DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 201 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Sound card:",IDT_1711,7,9,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 + + COMBOBOX IDC_COMBO_MIDI,71,26,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI Out Device:",IDT_1712,7,28,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,26,46,12 + + COMBOBOX IDC_COMBO_MIDI_IN,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI In Device:",IDT_1713,7,47,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,45,46,12 + + CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 + + CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,84,95,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_SSI,214,82,46,12 + + CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,102,95,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_CMS,214,100,46,12 + + CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,118,46,12 + + CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,138,94,10 +END + +DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Network type:",IDT_1714,7,9,59,10 + COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "PCap device:",IDT_1715,7,28,59,10 + COMBOBOX IDC_COMBO_PCAP,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "Network adapter:",IDT_1716,7,47,59,10 + COMBOBOX IDC_COMBO_NET,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,44,46,12 +END + +DLG_CFG_PORTS DIALOG DISCARDABLE 107, 0, 267, 135 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "LPT1 Device:",IDT_1717,7,9,61,10 + COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT2 Device:",IDT_1718,7,28,61,10 + COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT3 Device:",IDT_1719,7,47,61,10 + COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + CONTROL "Serial port 1",IDC_CHECK_SERIAL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,64,94,10 + CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 + CONTROL "Serial port 3",IDC_CHECK_SERIAL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 + CONTROL "Serial port 4",IDC_CHECK_SERIAL4,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 + + CONTROL "Parallel port 1",IDC_CHECK_PARALLEL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 + CONTROL "Parallel port 2",IDC_CHECK_PARALLEL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,100,94,10 + CONTROL "Parallel port 3",IDC_CHECK_PARALLEL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,118,94,10 +END + +DLG_CFG_STORAGE DIALOG DISCARDABLE 107, 0, 267, 203 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "HD Controller:",IDT_1718,7,9,64,10 + COMBOBOX IDC_COMBO_HDC,64,7,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,7,38,12 + + LTEXT "FD Controller:",IDT_1768,7,28,64,10 + COMBOBOX IDC_COMBO_FDC,64,26,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_FDC,222,26,38,12 + + CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,47,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,45,38,12 + + CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,64,38,12 + + GROUPBOX "SCSI",IDC_GROUP_SCSI,7,85,253,93 + LTEXT "Controller 1:",IDT_1763,16,102,48,10 + COMBOBOX IDC_COMBO_SCSI_1,73,100,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_1,213,100,38,12 + LTEXT "Controller 2:",IDT_1764,16,121,48,10 + COMBOBOX IDC_COMBO_SCSI_2,73,119,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_2,213,119,38,12 + LTEXT "Controller 3:",IDT_1765,16,140,48,10 + COMBOBOX IDC_COMBO_SCSI_3,73,138,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_3,213,138,38,12 + LTEXT "Controller 4:",IDT_1766,16,159,48,10 + COMBOBOX IDC_COMBO_SCSI_4,73,157,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI_4,213,157,38,12 + + CONTROL "Cassette",IDC_CHECK_CASSETTE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,185,94,10 +END + +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 107, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,92 + LTEXT "Hard disks:",IDT_1720,7,7,253,8 + PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 + PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 + PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 + COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,119,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,131,119,38,8 + COMBOBOX IDC_COMBO_HD_ID,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,131,119,38,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 149 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Hard Disk" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,55,127,50,14 + PUSHBUTTON "Cancel",IDCANCEL,112,127,50,14 + EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 + PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 + EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 + EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 + EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 + EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 + COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Sectors:",IDT_1726,154,35,27,10 + LTEXT "Heads:",IDT_1727,81,35,29,8 + LTEXT "Cylinders:",IDT_1728,7,35,32,12 + LTEXT "Size (MB):",IDT_1729,7,54,33,8 + LTEXT "Type:",IDT_1730,86,54,24,8 + LTEXT "File name:",IDT_1731,7,7,204,9 + COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,73,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,99,73,34,8 + COMBOBOX IDC_COMBO_HD_ID,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,99,73,34,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Image Format:",IDT_1774,7,92,50,12 + COMBOBOX IDC_COMBO_HD_IMG_FORMAT,58,90,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Block Size:",IDT_1775,7,111,50,12 + COMBOBOX IDC_COMBO_HD_BLOCK_SIZE,58,109,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Progress:",IDT_1752,7,7,204,9 + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,7,16,204,12 +END + +DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE 107, 0, 267, 222 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,60 + LTEXT "Floppy drives:",IDT_1737,7,7,253,8 + COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDT_1738,7,87,24,8 + CONTROL "Turbo timings",IDC_CHECKTURBO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 + CONTROL "Check BPB",IDC_CHECKBPB,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,196,86,64,10 + + CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,117,253,60 + LTEXT "CD-ROM drives:",IDT_1739,7,107,253,8 + COMBOBOX IDC_COMBO_CD_BUS,33,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1740,7,187,24,8 + COMBOBOX IDC_COMBO_CD_ID,170,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1741,131,187,38,8 + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1742,131,187,38,8 + COMBOBOX IDC_COMBO_CD_SPEED,33,205,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Speed:",IDT_1758,7,207,24,8 +END + +DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 107, 0, 267, 222 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + + CONTROL "List1",IDC_LIST_MO_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,17,253,60 + LTEXT "MO drives:",IDT_1769,7,7,253,8 + COMBOBOX IDC_COMBO_MO_BUS,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1770,7,87,24,8 + COMBOBOX IDC_COMBO_MO_ID,170,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1771,131,87,38,8 + COMBOBOX IDC_COMBO_MO_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1772,131,87,38,8 + COMBOBOX IDC_COMBO_MO_TYPE,33,105,120,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDT_1773,7,107,24,8 + + CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,137,253,60 + LTEXT "ZIP drives:",IDT_1759,7,127,253,8 + COMBOBOX IDC_COMBO_ZIP_BUS,23,205,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1753,7,207,14,8 + COMBOBOX IDC_COMBO_ZIP_ID,149,205,61,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1754,120,207,28,8 + COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,149,205,61,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1755,120,207,28,8 + CONTROL "ZIP 250",IDC_CHECK250,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,218,205,44,10 +END + +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "ISA RTC:",IDT_1767,7,9,48,10 + COMBOBOX IDC_COMBO_ISARTC,64,7,155,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,7,38,12 + + GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,28,253,93 + LTEXT "Card 1:",IDT_1763,16,45,48,10 + COMBOBOX IDC_COMBO_ISAMEM_1,73,43,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,213,43,38,12 + LTEXT "Card 2:",IDT_1764,16,64,48,10 + COMBOBOX IDC_COMBO_ISAMEM_2,73,62,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,213,62,38,12 + LTEXT "Card 3:",IDT_1765,16,83,48,10 + COMBOBOX IDC_COMBO_ISAMEM_3,73,81,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,213,81,38,12 + LTEXT "Card 4:",IDT_1766,16,102,48,10 + COMBOBOX IDC_COMBO_ISAMEM_4,73,100,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,213,100,38,12 + + CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,128,94,10 + + CONTROL "POST card",IDC_CHECK_POSTCARD,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,128,94,10 +END + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Error" + IDS_2050 "Fatal error" + IDS_2051 "" + IDS_2052 "Press CTRL+ALT+PAGE DOWN to return to windowed mode." + IDS_2053 "Speed" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the ""roms"" directory." + IDS_2057 "(empty)" + IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "On" + IDS_2061 "Off" + IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" + IDS_2063 "Machine ""%hs"" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Video card ""%hs"" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." + IDS_2065 "Machine" + IDS_2066 "Display" + IDS_2067 "Input devices" + IDS_2068 "Sound" + IDS_2069 "Network" + IDS_2070 "Ports (COM & LPT)" + IDS_2071 "Storage controllers" + IDS_2072 "Hard disks" + IDS_2073 "Floppy & CD-ROM drives" + IDS_2074 "Other removable devices" + IDS_2075 "Other peripherals" + IDS_2076 "Surface images (*.86F)\0*.86F\0" + IDS_2077 "Click to capture mouse" + IDS_2078 "Press F8+F12 to release mouse" + IDS_2079 "Press F8+F12 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Unable to initialize FluidSynth" + IDS_2081 "Bus" + IDS_2082 "File" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Check BPB" + IDS_2088 "KB" + IDS_2089 "Could not initialize the video renderer." + IDS_2090 "Default" + IDS_2091 "%i Wait state(s)" + IDS_2092 "Type" + IDS_2093 "Failed to set up PCap" + IDS_2094 "No PCap devices found" + IDS_2095 "Invalid PCap device" + IDS_2096 "Standard 2-button joystick(s)" + IDS_2097 "Standard 4-button joystick" + IDS_2098 "Standard 6-button joystick" + IDS_2099 "Standard 8-button joystick" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "None" + IDS_2104 "Unable to load keyboard accelerators." + IDS_2105 "Unable to register raw input." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "Unable to initialize FreeType" + IDS_2111 "Unable to initialize SDL, SDL2.dll is required" + IDS_2112 "Are you sure you want to hard reset the emulated machine?" + IDS_2113 "Are you sure you want to exit 86Box?" + IDS_2114 "Unable to initialize Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "Welcome to 86Box!" + IDS_2118 "Internal controller" + IDS_2119 "Exit" + IDS_2120 "No ROMs found" + IDS_2121 "Do you want to save the settings?" + IDS_2122 "This will hard reset the emulated machine." + IDS_2123 "Save" + IDS_2124 "About 86Box" + IDS_2125 "86Box v" EMU_VERSION + IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." + IDS_2127 "OK" + IDS_2128 "Hardware not available" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Make sure " LIB_NAME_PCAP " is installed and that you are on a " LIB_NAME_PCAP "-compatible network connection." + IDS_2130 "Invalid configuration" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " is required for ESC/P printer emulation." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." + IDS_2134 "Entering fullscreen mode" + IDS_2135 "Don't show this message again" + IDS_2136 "Don't exit" + IDS_2137 "Reset" + IDS_2138 "Don't reset" + IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "%hs Device Configuration" + IDS_2142 "Monitor in sleep mode" + IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "OpenGL options" + IDS_2145 "You are loading an unsupported configuration" + IDS_2146 "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." + IDS_2147 "Continue" + IDS_2148 "Cassette: %s" + IDS_2149 "Cassette images (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0All files (*.*)\0*.*\0" + IDS_2150 "Cartridge %i: %ls" + IDS_2151 "Cartridge images (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0All files (*.*)\0*.*\0" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" + IDS_4100 "Custom..." + IDS_4101 "Custom (large)..." + IDS_4102 "Add New Hard Disk" + IDS_4103 "Add Existing Hard Disk" + IDS_4104 "HDI disk images cannot be larger than 4 GB." + IDS_4105 "Disk images cannot be larger than 127 GB." + IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" + IDS_4107 "Unable to read file" + IDS_4108 "Unable to write file" + IDS_4109 "HDI or HDX images with a sector size other than 512 are not supported." + IDS_4110 "USB is not yet supported" + IDS_4111 "Disk image file already exists" + IDS_4112 "Please specify a valid file name." + IDS_4113 "Disk image created" + IDS_4114 "Make sure the file exists and is readable." + IDS_4115 "Make sure the file is being saved to a writable directory." + IDS_4116 "Disk image too large" + IDS_4117 "Remember to partition and format the newly-created drive." + IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" + IDS_4119 "Unsupported disk image" + IDS_4120 "Overwrite" + IDS_4121 "Don't overwrite" + IDS_4122 "Raw image (.img)" + IDS_4123 "HDI image (.hdi)" + IDS_4124 "HDX image (.hdx)" + IDS_4125 "Fixed-size VHD (.vhd)" + IDS_4126 "Dynamic-size VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" + IDS_4128 "Large blocks (2 MB)" + IDS_4129 "Small blocks (512 KB)" + IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" + IDS_4131 "Select the parent VHD" + IDS_4132 "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + IDS_4133 "Parent and child disk timestamps do not match" + IDS_4134 "Could not fix VHD timestamp." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Disabled" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Disabled" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128Mb M.O. (ISO 10090)" + IDS_5903 "3.5"" 230Mb M.O. (ISO 13963)" + IDS_5904 "3.5"" 540Mb M.O. (ISO 15498)" + IDS_5905 "3.5"" 640Mb M.O. (ISO 15498)" + IDS_5906 "3.5"" 1.3Gb M.O. (GigaMO)" + IDS_5907 "3.5"" 2.3Gb M.O. (GigaMO 2)" + IDS_5908 "5.25"" 600Mb M.O." + IDS_5909 "5.25"" 650Mb M.O." + IDS_5910 "5.25"" 1Gb M.O." + IDS_5911 "5.25"" 1.3Gb M.O." + + IDS_6144 "Perfect RPM" + IDS_6145 "1%% below perfect RPM" + IDS_6146 "1.5%% below perfect RPM" + IDS_6147 "2%% below perfect RPM" + + IDS_7168 "English (United States)" +END +#define IDS_LANG_ENUS IDS_7168 + +// English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc new file mode 100644 index 000000000..6dd75e2d1 --- /dev/null +++ b/src/win/languages/hu-HU.rc @@ -0,0 +1,978 @@ +//////////////////////////////////////////////////////////////////////////// +// Hungarian resources +// +// Translated by Laci bá', 2021 +// + +#ifdef _WIN32 +LANGUAGE 0x0E,0x01 +#pragma code_page(65001) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Művelet" + BEGIN + MENUITEM "A &billentyűzet elfogást igényel", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "A &jobb oldali CTRL a bal ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "Hardveres &újraindítás", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Szüneteltetés", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Kilépés", IDM_ACTION_EXIT + END + POPUP "&Nézet" + BEGIN + MENUITEM "Állapotsor &elrejtése", IDM_VID_HIDE_STATUS_BAR + MENUITEM SEPARATOR + MENUITEM "&Átméretezhető ablak", IDM_VID_RESIZE + MENUITEM "Méret és pozíció &megjegyzése", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Megjelenítő" + BEGIN + MENUITEM "&SDL (Szoftveres)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardveres)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL +#if defined(DEV_BRANCH) && defined(USE_OPENGL) + MENUITEM "Open&GL (3.3 Core)", IDM_VID_OPENGL_CORE +#endif +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Méretek kézi megadása", IDM_VID_SPECIFY_DIM + MENUITEM "&Rögzített 4:3 képarány", IDM_VID_FORCE43 + POPUP "&Ablak méretezési tényező" + BEGIN + MENUITEM "&0,5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1,&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Szűrési mód" + BEGIN + MENUITEM "&Szomszédos", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineáris", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI méretezés", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Teljes képernyő\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN + POPUP "Teljes képernyős &méretezés" + BEGIN + MENUITEM "&Nyújtás a teljes képernyőre", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Négyzetes képpontok (aránytartás)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Egész tényezős nagyítás", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA beállítások" + BEGIN + MENUITEM "&Invertált VGA kijelző", IDM_VID_INVERT + POPUP "VGA képernyő &típusa" + BEGIN + MENUITEM "RGB &színes", IDM_VID_GRAY_RGB + MENUITEM "&RGB szürkeárnyalatos", IDM_VID_GRAY_MONO + MENUITEM "&Gyömbér kijelző", IDM_VID_GRAY_AMBER + MENUITEM "&Zöld kijelző", IDM_VID_GRAY_GREEN + MENUITEM "&Fehér kijelző", IDM_VID_GRAY_WHITE + END + POPUP "Szürkéskála &konzerziós eljárás" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Átlag szerint", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA túlpásztázás", IDM_VID_OVERSCAN + MENUITEM "Kontraszt illesztése &monokróm kijelzőhöz", IDM_VID_CGACON + END + MENUITEM "&Média", IDM_MEDIA + POPUP "&Eszközök" + BEGIN + MENUITEM "&Beállítások...", IDM_CONFIG + MENUITEM "Állapotsori ikonok &frissítése", IDM_UPDATE_ICONS +# ifdef USE_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Discord integráció engedélyezése", IDM_DISCORD +# endif + MENUITEM SEPARATOR + MENUITEM "&Képernyőkép készítése\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Hangerőszabályzó...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Nyomkövetés megkezdése\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Nyomkövetés befejezése\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END +#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) + POPUP "&Naplózás" + BEGIN +# ifdef ENABLE_BUSLOGIC_LOG + MENUITEM "BusLogic naplók engedélyezése\tCtrl+F4", IDM_LOG_BUSLOGIC +# endif +# ifdef ENABLE_CDROM_LOG + MENUITEM "CD-ROM naplók engedélyezése\tCtrl+F5", IDM_LOG_CDROM +# endif +# ifdef ENABLE_D86F_LOG + MENUITEM "Hajlékonylemez (86F) naplók engedélyezése\tCtrl+F6", IDM_LOG_D86F +# endif +# ifdef ENABLE_FDC_LOG + MENUITEM "Hajlékonylemez-vezérlő naplók engedélyezése\tCtrl+F7", IDM_LOG_FDC +# endif +# ifdef ENABLE_IDE_LOG + MENUITEM "IDE naplók engedélyezése\tCtrl+F8", IDM_LOG_IDE +# endif +# ifdef ENABLE_SERIAL_LOG + MENUITEM "Soros port naplók engedélyezése\tCtrl+F3", IDM_LOG_SERIAL +# endif +# ifdef ENABLE_NIC_LOG + MENUITEM "Hálózati naplók engedélyezése\tCtrl+F9", IDM_LOG_NIC +# endif +# ifdef ENABLE_LOG_COMMANDS +# ifdef ENABLE_LOG_TOGGLES + MENUITEM SEPARATOR +# endif +# ifdef ENABLE_LOG_BREAKPOINT + MENUITEM "Töréspontok &naplózása\tCtrl+F10", IDM_LOG_BREAKPOINT +# endif +# ifdef ENABLE_VRAM_DUMP + MENUITEM "&Videómemória lementése\tCtrl+F1", IDM_DUMP_VRAM +# endif +# endif + END +#endif + POPUP "&Súgó" + BEGIN + MENUITEM "&Dokumentáció...", IDM_DOCS + MENUITEM "A 86Box &névjegye...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Meglévő képfájl &megnyitása...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Felvétel", IDM_CASSETTE_RECORD + MENUITEM "&Lejátszás", IDM_CASSETTE_PLAY + MENUITEM "&Visszatekerés az elejére", IDM_CASSETTE_REWIND + MENUITEM "&Előretekerés a végére", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Kép&fájl...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Meglévő képfájl &megnyitása...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportálás 86F formátumba...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Némítás", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CDROM_EMPTY + MENUITEM "Előző képfájl &újratöltése", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Kiadás", IDM_ZIP_EJECT + MENUITEM "Előző képfájl &újratöltése", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_MO_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Kiadás", IDM_MO_EJECT + MENUITEM "Előző képfájl &újratöltése", IDM_MO_RELOAD + END +END + +#if defined(DEV_BRANCH) && defined(USE_OPENGL) +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Cél &képkockasebesség" + BEGIN + MENUITEM "&Szinkronizálás a videóval ", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "Shader &kiválasztása...", IDM_VID_GL_SHADER + MENUITEM "Shader &eltávolítása", IDM_VID_GL_NOSHADER +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// +DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDT_SDEVICE,16,16,180,1000 + LTEXT "1",IDT_STEXT,16,186,180,1000 +END + +DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Hangerőszabályzó" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,57,7,50,14 + PUSHBUTTON "Mégse",IDCANCEL,57,24,50,14 + CONTROL "Hangerő",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_VERT | + TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP,15,20,20,109 + CTEXT "Hangerő",IDT_1746,10,7,32,9,SS_CENTERIMAGE +END + +DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Új képfájl létrehozása" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,104,65,50,14 + PUSHBUTTON "Mégse",IDCANCEL,162,65,50,14 + LTEXT "Fájlnév:",IDT_1749,7,6,44,12,SS_CENTERIMAGE + LTEXT "Méret:",IDT_1750,7,25,44,12,SS_CENTERIMAGE + LTEXT "RPM-mód:",IDT_1751,7,45,44,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_FILE_NAME,53,5,150,14,ES_AUTOHSCROLL | ES_READONLY + COMBOBOX IDC_COMBO_DISK_SIZE,53,25,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_RPM_MODE,53,45,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "...",IDC_CFILE,206,5,13,14 + LTEXT "Folyamat:",IDT_1757,7,45,44,12,SS_CENTERIMAGE + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,53,45,166,14 +END + +DLG_CONFIG DIALOG DISCARDABLE 0, 0, 376, 256 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "86Box beállítások" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,246,235,50,14 + PUSHBUTTON "Mégse",IDCANCEL,307,235,50,14 + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 +/* Leave this commented out until we get into localization. */ +#if 0 + LTEXT "Nyelv:",IDT_1700,7,237,41,10 + COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +#endif +END + +DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Főablak méreteinek megadása" +FONT 9, "Segoe UI" +BEGIN + LTEXT "Szél.:",IDT_1709,7,9,24,12 + EDITTEXT IDC_EDIT_WIDTH,33,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_WIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,76,6, + 12,12 + LTEXT "Mag.:",IDT_1710,97,9,24,12 + EDITTEXT IDC_EDIT_HEIGHT,123,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_HEIGHTSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,166,6, + 12,12 + CONTROL "Rögzítés erre a méretre",IDC_CHECK_LOCK_SIZE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,26,94,10 + DEFPUSHBUTTON "OK",IDOK,30,45,50,14 + PUSHBUTTON "Mégse",IDCANCEL,99,45,50,14 +END + +DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 200 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_MACHINE_TYPE,71,7,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Géptípus:",IDT_1708,7,9,60,10 + COMBOBOX IDC_COMBO_MACHINE,71,26,138,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Számítógép:",IDT_1701,7,28,60,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_MACHINE,214,26,46,12 + COMBOBOX IDC_COMBO_CPU_TYPE,71,45,110,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Processzor:",IDT_1702,7,47,59,10 + COMBOBOX IDC_COMBO_CPU,215,45,45,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Seb.:",IDT_1704,189,47,24,10 + COMBOBOX IDC_COMBO_FPU,71,64,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "FPU-egység:",IDT_1707,7,66,59,10 + COMBOBOX IDC_COMBO_WS,71,83,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Várakozási cikl.:",IDT_1703,7,85,60,10 + EDITTEXT IDC_MEMTEXT,70,102,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, + 12,12 + LTEXT "MB",IDT_1705,123,104,10,10 + LTEXT "Memória:",IDT_1706,7,104,30,10 + GROUPBOX "Idő szinkronizáció",IDC_TIME_SYNC,7,135,100,56 + CONTROL "Letiltva",IDC_RADIO_TS_DISABLED,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,147,84,10 + CONTROL "Engedély. (helyi idő)", IDC_RADIO_TS_LOCAL,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,84,10 + CONTROL "Engedély. (UTC)", IDC_RADIO_TS_UTC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,84,10 +#ifdef USE_DYNAREC + CONTROL "Dinamikus újrafordítás",IDC_CHECK_DYNAREC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 +#endif +END + +DLG_CFG_VIDEO DIALOG DISCARDABLE 107, 0, 267, 45 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Videokártya:",IDT_1707,7,9,48,10 + COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_VID,222,7,38,12 + CONTROL "Voodoo-gyorsítókártya",IDC_CHECK_VOODOO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 + PUSHBUTTON "Beállítások",IDC_BUTTON_VOODOO,222,26,38,12 +END + +DLG_CFG_INPUT DIALOG DISCARDABLE 107, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Egér:",IDT_1709,7,9,57,10 + COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_MOUSE,214,7,46,12 + LTEXT "Játékvezérlő:",IDT_1710,7,27,58,10 + COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Játékvez. 1...",IDC_JOY1,7,44,50,14 + PUSHBUTTON "Játékvez. 2...",IDC_JOY2,74,44,50,14 + PUSHBUTTON "Játékvez. 3...",IDC_JOY3,141,44,50,14 + PUSHBUTTON "Játékvez. 4...",IDC_JOY4,209,44,50,14 +END + +DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 201 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Hangkártya:",IDT_1711,7,9,59,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_SND,214,7,46,12 + + COMBOBOX IDC_COMBO_MIDI,71,26,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI-kimenet:",IDT_1712,7,28,59,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_MIDI,214,26,46,12 + + COMBOBOX IDC_COMBO_MIDI_IN,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI-bemenet:",IDT_1713,7,47,59,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_MIDI_IN,214,45,46,12 + + CONTROL "Különálló MPU-401",IDC_CHECK_MPU401,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_MPU401,214,64,46,12 + + CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,84,95,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_SSI,214,82,46,12 + + CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,102,95,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_CMS,214,100,46,12 + + CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_GUS,214,118,46,12 + + CONTROL "FLOAT32 használata",IDC_CHECK_FLOAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,138,94,10 +END + +DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Hálózati típusa:",IDT_1714,7,9,59,10 + COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "PCap eszköz:",IDT_1715,7,28,59,10 + COMBOBOX IDC_COMBO_PCAP,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "Hálózati kártya:",IDT_1716,7,47,59,10 + COMBOBOX IDC_COMBO_NET,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Beállítások...",IDC_CONFIGURE_NET,214,44,46,12 +END + +DLG_CFG_PORTS DIALOG DISCARDABLE 107, 0, 267, 135 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "LPT1 eszköz:",IDT_1717,7,9,61,10 + COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT2 eszköz:",IDT_1718,7,28,61,10 + COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT3 eszköz:",IDT_1719,7,47,61,10 + COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + CONTROL "Soros port 1",IDC_CHECK_SERIAL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,64,94,10 + CONTROL "Soros port 2",IDC_CHECK_SERIAL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 + CONTROL "Soros port 3",IDC_CHECK_SERIAL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 + CONTROL "Soros port 4",IDC_CHECK_SERIAL4,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 + + CONTROL "Párhuzamos port 1",IDC_CHECK_PARALLEL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 + CONTROL "Párhuzamos port 2",IDC_CHECK_PARALLEL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,100,94,10 + CONTROL "Párhuzamos port 3",IDC_CHECK_PARALLEL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,118,94,10 +END + +DLG_CFG_STORAGE DIALOG DISCARDABLE 107, 0, 267, 203 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Merevl.-vezérlő:",IDT_1718,7,9,64,10 + COMBOBOX IDC_COMBO_HDC,64,7,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_HDC,222,7,38,12 + + LTEXT "Floppy-vezérlő:",IDT_1768,7,28,64,10 + COMBOBOX IDC_COMBO_FDC,64,26,155,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_FDC,222,26,38,12 + + CONTROL "Harmadlagos IDE-vezérlő",IDC_CHECK_IDE_TER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,47,199,10 + PUSHBUTTON "Beállítások",IDC_BUTTON_IDE_TER,222,45,38,12 + + CONTROL "Negyedleges IDE-vezérlő",IDC_CHECK_IDE_QUA,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 + PUSHBUTTON "Beállítások",IDC_BUTTON_IDE_QUA,222,64,38,12 + + GROUPBOX "SCSI",IDC_GROUP_SCSI,7,85,253,93 + LTEXT "Gazdaadapt. 1:",IDT_1763,16,102,48,10 + COMBOBOX IDC_COMBO_SCSI_1,73,100,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_SCSI_1,213,100,38,12 + LTEXT "Gazdaadap. 2:",IDT_1764,16,121,48,10 + COMBOBOX IDC_COMBO_SCSI_2,73,119,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_SCSI_2,213,119,38,12 + LTEXT "Gazdaadapt. 3:",IDT_1765,16,140,48,10 + COMBOBOX IDC_COMBO_SCSI_3,73,138,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_SCSI_3,213,138,38,12 + LTEXT "Gazdaadapt. 4:",IDT_1766,16,159,48,10 + COMBOBOX IDC_COMBO_SCSI_4,73,157,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_SCSI_4,213,157,38,12 + + CONTROL "Magnókazetta",IDC_CHECK_CASSETTE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,185,94,10 +END + +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 107, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,92 + LTEXT "Merevlemezek:",IDT_1720,7,7,253,8 + PUSHBUTTON "&Új...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 + PUSHBUTTON "&Megnyitás...",IDC_BUTTON_HDD_ADD,129,137,62,10 + PUSHBUTTON "&Eltávolítás",IDC_BUTTON_HDD_REMOVE,198,137,62,10 + COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Busz:",IDT_1721,7,119,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Csatorna:",IDT_1722,131,119,38,8 + COMBOBOX IDC_COMBO_HD_ID,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,131,119,38,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 149 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Merevlemez hozzáadása" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,55,127,50,14 + PUSHBUTTON "Mégse",IDCANCEL,112,127,50,14 + EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 + PUSHBUTTON "&Kiválasztás...",IDC_CFILE,167,16,44,12 + EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 + EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 + EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 + EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 + COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Szektorok:",IDT_1726,154,35,27,10 + LTEXT "Fejek:",IDT_1727,81,35,29,8 + LTEXT "Cilinderek:",IDT_1728,7,35,32,12 + LTEXT "Méret (MB):",IDT_1729,7,54,33,8 + LTEXT "Típus:",IDT_1730,86,54,24,8 + LTEXT "Fájlnév:",IDT_1731,7,7,204,9 + COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Busz:",IDT_1721,7,73,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Csatorna:",IDT_1722,99,73,34,8 + COMBOBOX IDC_COMBO_HD_ID,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,99,73,34,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Formátum:",IDT_1774,7,92,50,12 + COMBOBOX IDC_COMBO_HD_IMG_FORMAT,58,90,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Blokkméret:",IDT_1775,7,111,50,12 + COMBOBOX IDC_COMBO_HD_BLOCK_SIZE,58,109,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Folyamat:",IDT_1752,7,7,204,9 + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,7,16,204,12 +END + +DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE 107, 0, 267, 222 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,60 + LTEXT "Floppy-meghajtók:",IDT_1737,7,7,253,8 + COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Típus:",IDT_1738,7,87,24,8 + CONTROL "Turbó időzítés",IDC_CHECKTURBO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 + CONTROL "BPB ellenőrzés",IDC_CHECKBPB,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,196,86,64,10 + + CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,117,253,60 + LTEXT "CD-ROM meghajtók:",IDT_1739,7,107,253,8 + COMBOBOX IDC_COMBO_CD_BUS,33,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Busz:",IDT_1740,7,187,24,8 + COMBOBOX IDC_COMBO_CD_ID,170,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1741,131,187,38,8 + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,185,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Csatorna:",IDT_1742,131,187,38,8 + COMBOBOX IDC_COMBO_CD_SPEED,33,205,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Seb.:",IDT_1758,7,207,24,8 +END + +DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 107, 0, 267, 222 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + + CONTROL "List1",IDC_LIST_MO_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,17,253,60 + LTEXT "MO-meghajtók:",IDT_1769,7,7,253,8 + COMBOBOX IDC_COMBO_MO_BUS,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Busz:",IDT_1770,7,87,24,8 + COMBOBOX IDC_COMBO_MO_ID,170,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1771,131,87,38,8 + COMBOBOX IDC_COMBO_MO_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Csatorna:",IDT_1772,131,87,38,8 + COMBOBOX IDC_COMBO_MO_TYPE,33,105,120,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Típus:",IDT_1773,7,107,24,8 + + CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,137,253,60 + LTEXT "ZIP-meghajtók:",IDT_1759,7,127,253,8 + COMBOBOX IDC_COMBO_ZIP_BUS,33,205,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Busz:",IDT_1753,7,207,24,8 + COMBOBOX IDC_COMBO_ZIP_ID,170,205,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1754,120,207,28,8 + COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,149,205,61,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Csatorna:",IDT_1755,120,207,28,8 + CONTROL "ZIP 250",IDC_CHECK250,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,218,205,44,10 +END + +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "ISA RTC:",IDT_1767,7,9,48,10 + COMBOBOX IDC_COMBO_ISARTC,64,7,155,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_ISARTC,222,7,38,12 + + GROUPBOX "ISA memóriabővítők",IDC_GROUP_ISAMEM,7,28,253,93 + LTEXT "Kártya 1:",IDT_1763,16,45,48,10 + COMBOBOX IDC_COMBO_ISAMEM_1,73,43,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_ISAMEM_1,213,43,38,12 + LTEXT "Kártya 2:",IDT_1764,16,64,48,10 + COMBOBOX IDC_COMBO_ISAMEM_2,73,62,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_ISAMEM_2,213,62,38,12 + LTEXT "Kártya 3:",IDT_1765,16,83,48,10 + COMBOBOX IDC_COMBO_ISAMEM_3,73,81,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_ISAMEM_3,213,81,38,12 + LTEXT "Kártya 4:",IDT_1766,16,102,48,10 + COMBOBOX IDC_COMBO_ISAMEM_4,73,100,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Beállítások",IDC_CONFIGURE_ISAMEM_4,213,100,38,12 + + CONTROL "ISABugger eszköz",IDC_CHECK_BUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,128,94,10 + + CONTROL "POST kártya",IDC_CHECK_POSTCARD,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,128,94,10 +END + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Hiba" + IDS_2050 "Végzetes hiba" + IDS_2051 "" + IDS_2052 "Használja a CTRL+ALT+PAGE DOWN kombinációt az ablakhoz való visszatéréshez." + IDS_2053 "Sebesség" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP-lemezképek (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "A 86Box nem talált használható ROM-képeket\n\nKérem töltse le a ROM készletet és bontsa ki a ""roms"" könyvtárba." + IDS_2057 "(üres)" + IDS_2058 "ZIP-lemezképek (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Minden fájl (*.*)\0*.*\0" + IDS_2059 "Turbó" + IDS_2060 "Bekapcsolva" + IDS_2061 "Kikapcsolva" + IDS_2062 "Minden képfájl (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Alapvető szektor képfájlok (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Felületi képfájlok (*.86F)\0*.86F\0" + IDS_2063 "A számítógép ""%hs"" nem elérhető a ""roms/machines"" mappából hiányzó ROM-képek miatt. Ehelyett egy másik gép kerül futtatásra." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "A videokártya ""%hs"" nem elérhető a ""roms/video"" mappából hiányzó ROM-képek miatt. Ehelyett egy másik kártya kerül futtatásra." + IDS_2065 "Számítógép" + IDS_2066 "Megjelenítő" + IDS_2067 "Beviteli eszközök" + IDS_2068 "Hang" + IDS_2069 "Hálózat" + IDS_2070 "Portok (COM és LPT)" + IDS_2071 "Tárolóvezérlők" + IDS_2072 "Merevlemezek" + IDS_2073 "Floppy és CD-ROM meghajtók" + IDS_2074 "Egyéb cserélhető tárolók" + IDS_2075 "Egyéb perifériák" + IDS_2076 "Felületi képfájlok (*.86F)\0*.86F\0" + IDS_2077 "Az egér elfogásához kattintson az ablakba" + IDS_2078 "Nyomja meg az F8+F12-t az egér elengédéséhez" + IDS_2079 "Nyomja meg az F8+F12-t vagy a középső gombot az egér elengédéséhez" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Nem sikerült a FluidSynth inicializálása" + IDS_2081 "Busz" + IDS_2082 "Fájl" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPB ellenőrzése" + IDS_2088 "KB" + IDS_2089 "Nem sikerült inicializálni a videó megjelenítőt." + IDS_2090 "Alapértelmezet" + IDS_2091 "%i várakozási ciklus(ok)" + IDS_2092 "Típus" + IDS_2093 "Nem sikerült a PCap beállítása" + IDS_2094 "Nem találhatóak PCap eszközök" + IDS_2095 "Érvénytelen PCap eszköz" + IDS_2096 "Szabványos 2-gombos játékvezérlő(k)" + IDS_2097 "Szabványos 4-gombos játékvezérlő" + IDS_2098 "Szabványos 6-gombos játékvezérlő" + IDS_2099 "Szabványos 8-gombos játékvezérlő" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Nincs" + IDS_2104 "Nem lehet betölteni a billentyűzetgyorsítókat." + IDS_2105 "A közvetlen nyers bevitel regisztrálása nem sikerült." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "Minden képfájl (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Továbbfejlesztett szektor képek (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Alapvető szektor képek (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux képekfájlok (*.FDI)\0*.FDI\0Felületi képfájlok (*.86F;*.MFM)\0*.86F;*.MFM\0Minden fájl (*.*)\0*.*\0" + IDS_2110 "A FreeType inicializálása nem lehetséges" + IDS_2111 "Az SDL inicializálása nem lehetséges, az SDL2.dll fájl szükséges" + IDS_2112 "Biztosan szeretné újraindítani az emulált gépet?" + IDS_2113 "Biztos benne, hogy ki szeretne lépni a 86Box-ból?" + IDS_2114 "Nem sikerült inicializálni a Ghostscript-et" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO-képfájlok (*.IM?;*.MDI)\0*.IM?;*.MDI\0Minden fájl (*.*)\0*.*\0" + IDS_2117 "Üdvözli önt az 86Box!" + IDS_2118 "Integrált vezérlő" + IDS_2119 "Kilépés" + IDS_2120 "Nem találhatóak meg a ROM-képek" + IDS_2121 "Szeretné menteni a beállításokat?" + IDS_2122 "Ezzel hardveresen újraindítja az emulált gépet." + IDS_2123 "Mentés" + IDS_2124 "A 86Box névjegye" + IDS_2125 "86Box v" EMU_VERSION + IDS_2126 "Régi számítógépek emulátora\n\nFejlesztők: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, és mások.\n\nMegjelent a GNU General Public License v2 alatt. További információért lásd a LICENSE fájlt. " + IDS_2127 "OK" + IDS_2128 "Hardver nem elérhető" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Győződjön meg hogy a(z) " LIB_NAME_PCAP " telepítve van és jelenleg a " LIB_NAME_PCAP "-kompatibilis kapcsolatot használja." + IDS_2130 "Érvénytelen konfiguráció" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " szükséges az ESC/P nyomtató emulációhoz." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " szükséges a PostScript fájlok PDF formátumba való automatikus konvertálásához.\n\nAz általános PostScript nyomtatóra küldött dokumentumok PostScript (.ps) fájlként kerülnek mentésre." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " szükséges a FluidSynth MIDI kimenethez." + IDS_2134 "Teljes képernyős módra váltás" + IDS_2135 "Ne jelenítse meg újra ezt az üzenetet " + IDS_2136 "Ne lépjen ki" + IDS_2137 "Újraindítás" + IDS_2138 "Ne indítsa újra" + IDS_2139 "MO-képfájlok (*.IM?;*.MDI)\0*.IM?;*.MDI\0Minden fájl (*.*)\0*.*\0" + IDS_2140 "CD-ROM-képek (*.ISO;*.CUE)\0*.ISO;*.CUE\0Minden fájl (*.*)\0*.*\0" + IDS_2141 "%hs eszközkonfiguráció" + IDS_2142 "Képernyő alvó módban" + IDS_2143 "OpenGL Shaderek (*.GLSL)\0*.GLSL\0Minden fájl (*.*)\0*.*\0" + IDS_2144 "OpenGL beállítások" + IDS_2145 "Egy nem támogatott konfigurációt tölt be" + IDS_2146 "A kiválasztott gépen alapuló CPU-típusszűrés le van tiltva ezen az emulált gépen.\n\nEz lehetővé teszi olyan CPU kiválasztását, amely egyébként nem kompatibilis a kiválasztott géppel. Előfordulhat azonban, hogy nem kompatibilis a gép BIOS-ával vagy más szoftverekkel.\n\nA beállítás engedélyezése hivatalosan nem támogatott, és a benyújtott hibajelentéseket érvénytelenként lezárhatjuk." + IDS_2147 "Folytatás" + IDS_2148 "Magnókazetta: %s" + IDS_2149 "Magnókazetta-képek (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Minden fájl (*.*)\0*.*\0" + IDS_2150 "ROM-kazetta %i: %ls" + IDS_2151 "ROM-kazetta képek (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Minden fájl (*.*)\0*.*\0" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Merevlemez (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL vagy ESDI CD-ROM meghajtók soha nem léteztek" + IDS_4100 "Egyéni..." + IDS_4101 "Egyéni (nagy)..." + IDS_4102 "Új merevlemez hozzáadása" + IDS_4103 "Meglévő merevlemez hozzáadása" + IDS_4104 "A HDI lemezképek nem lehetnek nagyobbak 4 GB-nál." + IDS_4105 "A lemezképek mérete nem haladhatja meg a 127 GB-ot." + IDS_4106 "Merevlemez-képfájlok (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Minden fájl (*.*)\0*.*\0" + IDS_4107 "A fájl nem olvasható" + IDS_4108 "A fájl nem írható" + IDS_4109 "Az 512-től eltérő szektorméretű HDI vagy HDX képek nem támogatottak." + IDS_4110 "Az USB még nem támogatott" + IDS_4111 "A lemezképfájl már létezik" + IDS_4112 "Adjon meg egy érvényes fájlnevet." + IDS_4113 "A lemezképfájl létrehozásra került" + IDS_4114 "Győződjön meg arról, hogy a fájl létezik és olvasható." + IDS_4115 "Győződjön meg arról, hogy a fájlt egy írható könyvtárba menti." + IDS_4116 "A lemezképfájl túl nagy" + IDS_4117 "Ne felejtse el particionálni és formázni az újonnan létrehozott meghajtót." + IDS_4118 "A kiválasztott fájl felülírásra kerül. Biztos, hogy ezt kívánja használni?" + IDS_4119 "Nem támogatott lemezkép" + IDS_4120 "Felülírás" + IDS_4121 "Ne írja felül" + IDS_4122 "Nyers lemezkép (.img)" + IDS_4123 "HDI-lemezkép (.hdi)" + IDS_4124 "HDX-lemezkép (.hdx)" + IDS_4125 "Rögzített méretű VHD (.vhd)" + IDS_4126 "Dinamikusan bővülő VHD (.vhd)" + IDS_4127 "Különbség-VHD (.vhd)" + IDS_4128 "Nagy blokkméret (2 MB)" + IDS_4129 "Kis blokkméret (512 KB)" + IDS_4130 "VHD fájlok (*.VHD)\0*.VHD\0Minden fájl (*.*)\0*.*\0" + IDS_4131 "Válassza ki a szülő VHD-t" + IDS_4132 "Ez azt jelentheti, hogy a szülőkép módosult az eltérő kép létrehozása után.\n\nEz akkor is előfordulhat, ha a képfájlokat áthelyezték vagy másolták, vagy a lemezt létrehozó program hibája miatt.\n\nSzeretné kijavítani az időbélyegeket?" + IDS_4133 "A szülő- és a gyermeklemez időbélyegei nem egyeznek" + IDS_4134 "Nem sikerült kijavítani a VHD időbélyegét." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Letiltva" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Letiltva" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (klaszter 1024)" + IDS_5898 "DMF (klaszter 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128Mb M.O. (ISO 10090)" + IDS_5903 "3.5"" 230Mb M.O. (ISO 13963)" + IDS_5904 "3.5"" 540Mb M.O. (ISO 15498)" + IDS_5905 "3.5"" 640Mb M.O. (ISO 15498)" + IDS_5906 "3.5"" 1.3Gb M.O. (GigaMO)" + IDS_5907 "3.5"" 2.3Gb M.O. (GigaMO 2)" + IDS_5908 "5.25"" 600Mb M.O." + IDS_5909 "5.25"" 650Mb M.O." + IDS_5910 "5.25"" 1Gb M.O." + IDS_5911 "5.25"" 1.3Gb M.O." + + IDS_6144 "Tökéletes RPM" + IDS_6145 "1%%-kal a tökéletes RPM alatt" + IDS_6146 "1.5%%-kal a tökéletes RPM alatt" + IDS_6147 "2%%-kal a tökéletes RPM alatt" + + IDS_7168 "magyar (Magyarország)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Hungarian resources +///////////////////////////////////////////////////////////////////////////// \ No newline at end of file From 691e3029a876b12c2bb8b325d35d4c5c2877170d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Mon, 8 Nov 2021 19:10:37 +0100 Subject: [PATCH 102/140] Updates for Discord Rich Presence - Change the large image varying with build type based on 86Box.rc - Upload the necessary assets --- src/win/assets/86Box-green.png | Bin 0 -> 35465 bytes src/win/assets/86box-rb.png | Bin 0 -> 35252 bytes src/win/assets/86box-red.png | Bin 0 -> 57521 bytes src/win/assets/86box-yellow.png | Bin 0 -> 37482 bytes src/win/assets/86box.png | Bin 0 -> 35252 bytes src/win/assets/status-paused.png | Bin 0 -> 8460 bytes src/win/assets/status-running.png | Bin 0 -> 1863 bytes src/win/win_discord.c | 16 ++++++++++++++-- 8 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/win/assets/86Box-green.png create mode 100644 src/win/assets/86box-rb.png create mode 100644 src/win/assets/86box-red.png create mode 100644 src/win/assets/86box-yellow.png create mode 100644 src/win/assets/86box.png create mode 100644 src/win/assets/status-paused.png create mode 100644 src/win/assets/status-running.png diff --git a/src/win/assets/86Box-green.png b/src/win/assets/86Box-green.png new file mode 100644 index 0000000000000000000000000000000000000000..c1af649a1f6d513daef5794c1db68ecc6b595bed GIT binary patch literal 35465 zcmeAS@N?(olHy`uVBq!ia0y~yU||4Z4mJh`hI(1;W(Eev)=X#T08eLUg@U5|w9K4T z1_q6ZwG(YU4m-#kjSu$T8Y25f;n9SJR$CRc9%+Q?G__s|%eZ>*$tC@aOB0stu;5z9 z%5E>VnosZCE~_0}O%K>RX3w6ysC&wf{Yx$=U2A?^w`ceF9o6g{y+7Q4=wRZ4qjI9~r)%FiGFev!@U-#hKy_fImHd?48Qd`4cx5$Pkw zv!|V_oNsZ&Ym!rqpN!#)rX&3^(_`x%$CN}on5n2dd6qh#VE0kJY1T8Q@=UFmWwB<3 z)Kl)r>7wVN=Unyb-TLliyu_Jo?aXzTWn5*vJrpnyX1~b zxBg`@&-kmd_ujQb?gt*26%^jR_Qdu<5xYd)B~|Al6@A}@0Sx!fznEQg;DW9|L~(WY z+s9uRPXvUYHa~Ds(I9Tgo3DEB-@SeF_P+7je{~Fz*Nf&J+@)y9z`($k|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%Eig2Z}??r(sKp|1qM$S$B>F! zZ|+v^iA}GR|F!wM-7FoO=*gy1#y2OZH8e_0P@c1eH)_i=3Cg|Gxhy^-b#D*3ycb`_oI+8X`Z>`@Sdr!nQq^U+(Z=VEFL=_MXbk z_7lAJh_V9_6P7n9PBHr5 z%kIa|z`*cB`+eQ_-Ohit_kYq}`}#Gffy{n{VyKxqKD$^7o@E*Tzq!nJc8m)H!#Qbb z^Sm`t`?skxl>T7?srLa93}Aa2HZEXi*dk%}`Twf$y{BAR7#{2ioc;6sIfc*hzkcs| ztoP?Eb}cp1GwT@`EQ*UK{9Hfv|GewM4{rZp1sOX7L@+>XNOt6BIG1hopMjy^*|WrF z`(6AS@*j(X6eNJ%VF31T534PM#rhMVP?#xw_>8?Sb{n6YKx{Pn|J)3VuU{}8uylPU z&%khQ&YAx|kLrVLIRMJ+3=q2{xT_cpuBH5AWO#7qC(#)IsDggV3~1FS;ZJR7?|l;L*le1bK=CAwgCoKwT7|~&-ug+3KmGzLK4HVCOHNcP%1DePx&{~8>?v#Y}7%aQtbY0 z{$^aBez)_voH!!`LxS7~3_BnR4xFSRSqBm?4|;reu{_`Iw_Nzu!Gs5k7#JAlG-D4j z$9JGCd0^*3j1Wim3JziCnr)K_NbG!Gye8&F!5hKI%sX@>FACu0PdG}u1q941nW}Hv?$Jp@M=iHy? zJ@uKj5AvU3P3a5_4V#xu`Khma{_C@|vsc^gzuo(PKFGhp7U@5+7Fi4o3HMIS{C`vJ z^ZB1gu=&)tz zwG#5U6*{=$U*7fa^8aV|LuAjF zww~A4lszxLZvQ>s^mlh^+%=}JjkI0Q|NX(byC3cE6mG8OFlckTE36=0suurD{+T{j zhZ~%)`8O>(%K6h$pPIFS@AGe*U;S3F;O_q)@@sFuRxFq&xw+?GPWGJtYv)V6{KxSgNxiaASnOe_Wwfb$>+0#D$#+oS$rpfO9daZHwhy6UaCokA`+##30 zanGNX)A!%;o$YJ%_w%hySArirSa)~rcWwRoJ07Qr3qDvMcH>HZ>h2Vq}U)ZdHzn-EBZg5#>>6_IR8Gk{e7O|M4jT(-<=?{?g@cRFC1n3a{arZ4=N{IPbd_2mka`$qqs?@C&u2G0uiy5*{_*Fp91O=o z)?c4}^>6;YJvUw1)YQ~4i*>_=><&tg?dRP4$GmV}%8EK@`6IU{UwuUbDcSR-+S|%pX@(oV@atG_q=B;SeN?G zTk=n!{&}~(|8BlhG`Rj)@jH*jwl{47_7)w7zpA!x<14LMeD25TFa0)* zwe+LWZCfU<^Ud=Z4&=<7HLFOlVe=s@CCu|!{)R;3|HX4Z&VTDuqq*4r_HXUA_P1?W zp6yC^dRg)5$0=LJHq)GE^>2*+E#;|=vpc=ZeI7^Y|4ZHN*7J9U?W$9L7g(^Znq|s7 zaa$&ahC(bwMr-jt_5(Gi|MXi0$NjE6Ecd>~7-ashs(F77{Vn|ScW-$6uUS`wAAAna z;rYtH_wQTfz59&*2WlRkKRtcx>+5;(yK7#&j^15!#Fph*bU%YFBSXVaY)z);G5ifb zr~Q<_cJtf=em+^Q(&t^;ZoB^NEURt5dwy1!L9wqmCm3JZ zJa?vCRBqay37+z1m*cZ7 zy!*!SQT5xN_WaAqkKg^T=DlRVtHJ=Q`+NSK)W0MDs#W?Le`!tqr`7wVULBA7(DaRW zp8WLb_g32#E%o_7;r(2Bv(0fqQTwMXT>q9cVE6u8k5}66PqbfOV!!IRw_|2a|1S52 zc?=8(YOn?F#@CDnInVYRXWXy3@RFyz;qQ-SukYQfEvzixQmoh9ys`a&!rb`fx250m zN^IGGa`)z(%GV!F%{#6y-gVreUhSRU-Tk*7pS-?)ca7`SpVOy3|E!(*?{h}XglqO& z|6UCE|7X(Dh5uS_-vd9Aeg5{F%a-HP z^KyA>q5l7$yra$a*WN#|W%=`+-+s!L`ZwPCYudMe!=6Ihwmor2KUc=nqZ}>~k zEqMOa^7Fjw>(4$A7rmCB^26HsoS~@E*QK9zW7oU&H*Bd({(U8QVPUQI`R`YhZ$}>w zmz%ph_?f-_|B|SGw?HYP{?lfA;aB&6ZRJ1uI`S3g1quF_97WIS->>`jwfnJd@B1l| z`d?WxQoaSpp1Bg9_V4%ZB(=S})zZ%W-u?a9)79Zub@kuuFZt8^S+=b5WmQa7;qPxt ze}_-_KHYx(!YjrKUpY?LGHwd|&cVPiBNva&&R;rZ1}CPsgEsyi6n zp85Y7=Ml>}iN-%HC-3{PiZ}GM`?@Q|3nmY(}5ci`qPXF$Ky4U}*zLp<*{C-{U^XbMv z&VIa=8E>!eKlA^wk58UXy=}g({M?=Aa?Gut^|ik8czj=7|8r^RYjOL17Zxwr<$j>+ zn;iE}cZXd6hScqKO7GrJ&-)b4$zZS=vn~Z@GymzNpR(R6dF`&I@oc;O!6yR3zjLfO`(V1!pXPs&viFzHW9a=j`JMk_ zb%%AAf93D~b}QiizXQx~*>~)>6~2EWBYp3~W7X%LlwUvMQ+966^D~vom*WCXUAUh1 z%iGrZ({s}*jw^cp_rrT1``$LM;#l%k`uXJd{wtR|yjwY8f86yL%PZgWbD!Utk*@14GH!=EpU4Ilq~)7N~V6=zwhFG=GXaaOs`Fkk1E~Qd?k3{oPySDcsL|F`GK@90-Q16~OR%>Jpb`F8z}+zC}ICf~mQ z-N^3#-{0=ZdNGEC9sA>BK;s(7y}@G#*L-KND0{uOxw4j(OY+8?kMH&34WB%}n)=WG zZuR{D`RgbCh@aa&MKOMY(IerN=Oq8z&)KDZWqsx0*N^}4%X%HZoWD12>Fda#S2riT z&wu&v`O{uGrmfF|172|k$ke_3H|@`xOWcp^E3WIee-i)qRrh0+$i2sLr_M|_`lo#U z!}NXpTGRFKNcR7~a%=0_)7ek|*1meNamW9V>vccNwCwl)`1|?B#Bb+!|GD&~;n?$~ z7nPG-fB%r(=I)UESFxH+WV`-X0gXBQ3=UuKtLuTrY9Rf2NO$#dLeU+*9oy~qwb!N{ z{j}@t_oX})scx39L)OLLvP*yAJ@Zdi>zV(tFF$Y2uhUIil^&$Fd%E$S(|X)r)!+Y# zSh0WVH2c>N9{#Az{JHt^r#rz4@Bh2+dp~vIImv$q4_eIgvSsS}UVQV@x4*n;w~qU# z_BRCiH{ALd{7P`b`}5D`ttDPfkJ+d5Ed=Ia#a%A>z>VH=zaR~xAyz}+rWk9O|{Sb3}>*7CiU!LKd>=6 ze{I)Ny<1yXXZ>G#rv9Dag@6-FrWrl3G>$u!V{UZQa&y$|m-&0r?c(0GuCJ+l{jA=i z)PKePuU9Vaa5{CT{%@1&!n%8xk3as_ExuLn{O#v|(|4*nEZ^{_cK+O~`}Mo*fBt)V zrY_gL{Z6n#|NKjzo-w=*?_D3Yw5MLKf9cod_x}Ie@$dYerLQX3w!V+_e_Vg#Ox@dG z&F7BnF`M!9Z#kFzgld*2r%P8|P)@iZ$G$JS->Iro+QTG~JFqG$HsIW)epXlSJFIK5t0-pC~8#Gn5kzm%-l|8wj5 zV`neF+qcgyErDM@Lg1CX{kM=6{&uB0SL7>yy$rCgeX{Y|;r$O*wl3WFp^5uZ#f+ZQ z@n3qDF5LI#%gbwjr&saanYYgU+nVO@ZNIkWSJeLgtFfourhodSimW$wUo|AYq(3@d zTD|tR{+=x771`ARPtMfG{d>jx+Ieq6?U|DQrwhPJg$`zxF9B&!6_TWomoNIbr+x-{)<4iu_xHU(Yk*U~G8! zPp%L=xPv?#$nFfympg49BpUx;`hCOmp0dY#KWa9|&fd6g>j%;6?Z5b!zvKM6JZPEy zUe~%u3Hs+g=GY3He}3|@`l`O?lINo({~x~oeXG9zyjRB`P7+=_e`bd*TUd;c@viXo zQR3&npXNXId-}KUy;p=E9Jc?Xyzt)vcl%p)hg#3n7gjpT_4j_9e*E=<`}+?2Z7;C; zSW*0J|Hj>iKH2}td9(1t$B_N+{?~-B5ErRxn6l4DEm&=r{qdRqUT%FJ&Q@LY{L(Jo zOMg!+-a0w&L(cb_44JrhoD-(M&;P&g-T6;n&)M>Q`l)|sp*jNt_Tk~a-<(s7{zsmR zc+OL{&brm7e7W&0flu=O{_VeJzqI{!-(%)~Wp1&Ss@oF}FRZIdJ#)Z+O~2%g^d&z3 zRQ02-SJl{mxMqI#)!#p7*pt-$r$qfrFyH6?uk-pol`E^iAN^f;F=daP{oj@LJYU)G zecKkW|NXby&VR3&?_F8D=cydSR9i-`#~ZIqUX=1MRN857b=Z|twk-eN{j!J?+xukK z57y69*I#|R|6@aMSSp0F_9{kIp-vQZuz%z&;KjT3hAH` z1vlOAGAFJtzM{;?uwWXN4nf*p_5+I!Rqs!~{oumFFY=FO&#}H6clDp&-Rk(ej3P!4 zxZ?|JS4hwN|3&V1^W={e|6eceZ~N8sT!;VbQq9Zu9y9;n^7-!@zR%{${2RsbS3f!K z`}cD1SNUJtq;55no)oXW#GO6@Ly+$vi*v|K#jzM_$jaVmPxV>Sk5V z-o3w99dkeT$NX5a)x9A8Mw@-!wv1WTad)=b_U%8o*xKpu+4Q>KmPUeG27ee z-fi`D+IQ#Ql4G2EsA9$06VK1ozx}mznn<%~;U06Nf0>nUKQb`zoW{~^ylTtPcema+Cu;Y$clY~G>#dBg|Nm~))8<1Tndaz9o9E5B`ZxdXuB)zXo3RbL zO-}#KQ1x@~EA469_4FlWtU@9b_qE%l|NC5hQN8T_O6!GAY`^=LFMs?h^XGH@8n+ey z6RK_InbzCyb>Ax=yk!5k`u+dsNG<w@dv>enheJisJqT|2I4JuS9Rl;rzP4>iKS` z+Q0Vy-51swr2bm(`Tg^eT{n^wKlc5&_uI|C!D*TOca9ftZ{N3?XLb6~XTuY=44*zV zzde8c&}y@mUthktM_)gGy4b(Leooi-?4+Bi3;%pP|37lY|G)iq_qQ9=t9}P{Iod*B zaT-|ssi>J3#NUuOefpEfnKJ9;BoCBlY%~75*iO!tDd8KI(T2n)whUr#Z-s8HJNJiw zb+K!WfAvOnhf611mh*f|2>)F@Pdx}6fBTf=?q3(v<@tK|_v7k^`W0n+?C$?B&gUsT zcVK>Y(X;v+^BB~BeXRTQO})e7-a9UFF0ohAGE_?Nfj4J{^AK z=}vWr?bE-B_p5*3^FpL5B4xhM%>UQ-J^Z?G-`~x_`%-`QJ)OtU`~J1;;jbJs-p*s_ zJ#M)+-b$|F{T0x7!ml4+IU3&2!IBl#&VOV4QlwUOVjjcMGxh4{D(CF_zVD&m0wZJF znMM!)C#R{+`@gH(x%TAuHL|Z6!%n@aulc@rVcp$V;oIKn=g0r96wdE``ZxOV-~TVZ zYz)|+`AahNd9}?~mJ`#a9P>W)$G_xpg>LG<&z~G$NnVH)o4>yGXQjp$mWU0BwJYK$ zzw*ELb7RGy(|VtEPp`4us`rg!#aqq^#{U<;!;HwSM)S_^oAL4ea-aH@>JH~VJfFuPJoWnPE8pB7f3CmV?fiF^`5wC~ z+w03tZPzJYwoTpP+@I^K&VG3Q)qDQ@^Xw1wd!wK2|5Ca2`Q_JNqo(`&{`}4S@7VL3 zm=g*j)eJJbzg{~SBNveWzcKRe|Cdt|<=)(q4L>3I_D|e5r?%hy{`2|1ZogE0VSda8 zg?aCdAAfSRue-Ox`2W(LzsJk(-`-UlXa8P5e||O7lc&bbbyq)5`8Iv}^LdOn`S*PF zUAV74JLdno<$lW;cWF$yzU1Qs_v0T+UpwtpNv*4{{(kiJ#43g-AFsuVRi`~U1M+E{ zokfYp6>jq*k8QWwelv)uxY`!*|KMEtY}xm+_czXQ-D=CYY0gFatz~ZmjvMEkXKZ+X zWn1p;RoBkX{2z1-)V7P;f2BF$@-p8%rJfFK3Gw-D#|1KTtm2SVa&+Kq~RQ-+f(%Y6hc)pV~ zFf~mTI2dmikEI3vLXJWG`Wnu!i(+@L+IC*@{~X12Q;kpkw0*w(-QM*@?JL&*W- zH_p^gGyZ?`Q24PkKVQD>KlZl#t)F#|6PAU@-y_!^6o@z{da9` z^y`0hFSh-!HOcXBxOM*YyM4dk1w5a}5V=zQz%t+2PIIgI4q%-lnq2(1aqnNl#dE3| zuIQbg`Tv|~_!d3=)PKdt_FoiM`1x$pX{W!v+|!P{jTbb2?Ok=-`R}Uvzb{UVyWjtQ zpZPrhQwOFSeLO5x_J1e4)43n~)phfK9&o?izhC-(%>GyM@#5hYhL2uPt@7cq`uI6L zY+Z)z|K6VZTXxq~mv4K2!rWvExA_|WujiLMe;IBswf_C}%byt-&eU(UWpbPQ@%-sx zUY?INyFra%$kaHbzuMEhu$tk?_Zt0MTUVFszUKdXmjB}#YlEd(&N6#_{akxfQ_)v*KI*6bYmEG3SAf}=KPt!2e5}6Xf9l6` za|$kn{P3OP3w)gm+E5Z-19PZyDcV8iO#;4`{X=zS>PfjWP^>h25 zk`@1NPCUGD-oIxjcN~__u%G|(U&+;<=a=~WNlDLpUQy(>zp!4bKmE$@-)G+LziqXT zEz>6M|M$3?|7>`E{`vClP4D;ouTwY1Z8cgqzbfg=_xIk{m3wdGt^fMN&+bdX3h~&# zXMXI-sW(~ozx8+Y_wNrLxo-UTVg2#LALnv2Y+g6zA-LD#b-K9CKK+mP7nTOgKXuss zXSsRK+=%UZSGvpJWZaKGrEz{u)Wuy@=WL!omXxuPDBoXG`TC!j-RD)HT@2=ervu$I{)I_-S0AE=e_=Xw|@6q z<(L1qexG9T>F3*pao_*kSn_bz9b+YXy;iH!Gyfm^abMc_pRi@~^!exgV$b&kJ*$7X z>xa#pTN_uG)|Y<~Yx}kO{~vXyztSr~{f<4i&eVI}vzzT@yJ1sM+x~6t3TxjW3c>uU!revp$+e^x0-*= z%cdQB`?+A1?SVfwPkZ93ke(`zx?|HmGUtjUK{O2{+20`uA zZ{DD8q}OThng8wxFSw%2fOXndqB7ynk6on;<2Dtizy4*sI&7QX`I*n>6w1liNW60M zZ;6*X%CKu&poMYAE!@H`o44?gZK9QeA)WuDJ!#6{uTH4 zT&k|Ae*0Ll|GmvWe>tG;HRXFr#UWh`8S?Sy{Sb8F{}pD%Q`FA=EI zk)HYg&%94D>U(Q7Kigc~S9|UcKc9?7P2BJ2;?+!F(xblr-)4TC=U4oazx7Z3?ZscU zukR~1nEX1qzj6QON3IM1)qnqAx#Dy6`(n1bJ5$c7>!07n{rKzalHh0i>@)8ETYm2k z|D#`*O&2e}$-H3Wp6l82|95|1BD`wO;@O_;bE=r0e5`%-(EZWzr5|gm!foccUf*kR z#s1?-`;5JI`#~#Siq}Q|_`T5V^L*pKmY?H|-hA6Svwp$T-v=?9JUxF@KOMimmisHH zwZ+vc$IvTKy8PW|X!GjNPPMdl-<|Ii4M3AVlFv639kc(=VDaf^#s7K5H*W>( zw{d;3UbE+V-Ak5Ww)Mus)gDjgF&M92&r_OT|0eU|{q5$qelLGiO%8p$yU;e+zu(Vp zpXkS*zaB*A@qIo2_m}LxP{xEK+w$&8z3P=V-?py)Ft2&buX)w)JnQEj+3#QEW`BC- z-=JmtLDjChgXhZSjC0OonF27VTsQZ^1BWv{;?;aAmY?VA-Vrc3>vy;1U%5T2f4}eA zTWKxOPz%%Z=cyM<_4&T$t~`F!9ModIU-h{BXBcaP<+aya|JP2bW=ffDp5Ir$KI|LI zimBVr&*wiQhh?Zd^` z@wI$kAJ^}*zVbbPul~GuDSPgL>fiIPKH2|#@P6q>f%X37MLR54d5h`re&xPqtKQqb z#WB%>N6Wr`!twHRf8O7_{L3a~u1#IqvgEl{Oi$*CsmtHHSGDiwm-MhB&tJwb`S@q@ z{6Eb17cm$d-eAn{rEK+A=9`W`~$SnK!Na{stw){%aOy>Wc>JC!+e`~8Bf1Md~Vb_0Qe%m{{_RPK~ zY%{|%ea1BZ|JVK7e_ijh6MS|5*T?C<#8?|P>!d$0&%I@G<=?Yi>IXJF=bnRYeF-Q| zZ|=S)>U7yZ@8%_`Rq>mO(^vSf>6ZL@H1ns+xfFi3wWnv#{GW0m|9-uF>Vn;Szx{ps zmA!Qy)8)%+yNlUu_dox8YsgD!!o2}vhy7Fy*+ppK+Iv>|^GJKBFRJPCQZ`fS>=Ri5O zsqo2%-#s`urE$Mm>KgxLXX=#=<4^oJza~oZm0Q}b2`}ZM>X+qx{c`WyyHlYbf0V!H z{Q79i-%iu)sPFZ@ipu{!Pq)#&@_nfo$9KDry+7pt-PCsad1C+VYrFm*o`2u&(d*my zoF6{QpTqIB-1hmd0R7z`7Fo!=yDPQ+`uDi|yZ*mAQ!ka@9Jl^m&F8<`ch27tR!aZ3 z85CvzKEA9F&+V{fE_!DF`|R~SW>@x`e%z2B$RJ^yzT3T_#~$l~6p3Bz2TtGnx=tXd zuITi%Zvo|}Oy+yoGKsyvb8}an^TKwA^q-#srW^fgZf3vreZJA{<}Y#I6Ls%x)xP4t zd>+G6$=QGA{m#DhFt+|+@#C+a>!D{T&!?6oqzPxtSGWnjTEmx6$!<@|e ztix>;dourfU;1_Y@~_9stUk}@QFFg7w%E|_^T%Z$uUFVrEw-H(%)k8e`(x*SKe(vw zG`E^TCt?XZ1HwrL?;-i`SoM?3)z7@A+5O76`pZ(eKIx3n z|Id1l=f4ks7di1&()muo^nd;~BF4Yx`q|8LmA=;gOZM-~fcxJj_8*b`_rtq3o9TdM z-s5Avn|J-sy}fOzegAJgt22UFYLqio{0-grexCa<@2L9r9LbvMyA_7aa_EzWK+i^tNA5lwVfyB|Y1}xyE%x{l{HP z_o*^IkTJe3`F~RQo=2i%&WL zSZDrDdS-uGa#_gpGnJ2RKYNk8L&C$-FL5hRhA8p^6bNYBpOMd;nOW*HLjIW#9 z&1Aqo_ifMr4PLfP+w$(dQafCJ0?Sx*@jd1Ti^}&Iw|LCIvq`n(i!|roIXCrFes$Y2 z7P0NWzS`>Fxvm}mYxW$S$FTMNO8qtQr~dHoI(+tHiPrtyQKw#9uZw&6Bm4aNDIfD= z&Y$`l{=MbIcI&nFH|8J9PxWtb4PVRuwbNaWxAfef^J^mJeJjXWv;TqK-mk*Wz3!Jj z&)ip^U9Ixu`PUQrcb_a`>H)0?y1gy;ZT)$Xe|z6t`&T>V+w|@FssFs6uU2OW`SYF^ zvu9#Zd2W8<%65ly7NSPJOMA+5pIK|CUTTkx%f2DUwDmTB?Z2h-_%kg;wx8#E9=z*+ zWo7C44!_^e=U2RVxTSLa+b`;NmCxrc-1joq-eSG{^Eof`ZQlK?6F2Ia+j;5jyJdHe z{yYcd3bY7?8-zhik_vOW|nEvL@&0YUz zPSuW@{{7qA{{M+qd(&%;;uZz9S!;h|(MUN}{A_Q^jd=`*zX?c`{l4^T@jFgXJ9f%L z{j@*azhC?4t=Lu9y}mAOh5xd74BeML9Xu!d`4#s{tH<-F`%lSB|NU3SY;*lK(J+GbmE7-sN(qCQ8yXSAsV^}&*=w|1XkNGuq4{dk;|J-%@`Inz^ zR*&b;`+n)?*(x>r{^^RxFP{ia`{aH7^+xydu($f(MKWymPdy&~O7Mc`_1}iJObx|H zj`d2X|D3=1;=k&v>;Kg0e-+sAuuXc^x9ypimj(Fy`bxTdn0|h`H^})&i_Q;N%qX{I zkn@qepB=nxf7vlmEt|wv`@eDFx#eb$@1B^loG0XQh1%`>L}lUm*Vf0y**whq{qgzV zP(A&5@wsieS7vTMHIKjY@3|*UtIkK)d^L8STg}At>tm(W)M@+Q98-q*2;&nmx6i*`Cu zJi%x_yqm;lJ$G}J-PZTD>tpv%F_gF3T(d59QTv|y$mLTiSMQlGY?`aq{hrJF={PUj+txf_JV$z4yVKiGb2Qhz z{di$!Oh9R!<>&p7!u#;;={wWXFpZ)XvYh%~*%b30MGr#2+^sBG$cIx>2 zLU()1g|xc!#dZE)ZeFw4H)+nrQ!_uEn#Z*Dbo;p@;#Cqozbd@v+uwdZ|GoR$U#gam zL9w$;GE*?#I`F{ZBqBFWmR}$H##4Z|;e{;tpTW`Srrg|3PXsMVo4W z=A{4eJ|1o{f6mAAGk*si+ka6x;b7CX{`0@z%T+G=TflFBud1&1@#*KqH&x$WUwuVc zLHq9hlA4|B;L-WX-!4#My7FJD*3Q3vd#`%z!f)Oor+S{BDPO66AR%p8X}#s+xYcHl=RN&?X8OHqdyA5c z9Z%W6ZP$}8RolNS-FaXA&x+3#tMAmG`(ysjeR(Zk{sg0obGK%L@?H9=fOtXU`|3gb z4Z@fIUVHv_z2yTF1@8B2&%eH&cEVfo-=$9~>7Tr3{yp|{>6yCkor?=AtNuw#{`>QD zdYsJkP2JC`rSDI_l4IOzEBonN_2VCNB6jZj`t!6cvzIL+ z!?DoZXZusO8UJ1S^yg=@{CjWI4$rKU-vKI4P@1F7CyU><^sVofyr`;q`HrXL^*h1| zX#BJ?*uPI)ET5*@s|8O=i+>inV-)+(K)YJ zdb`@}$>X^%&WGIXcibgE_s_l0m%hEMDxbD~g_Qi~*UtfFp?~c}&11rzI zdEQgE&igh0ZDodx%6qY(Y7jC44_RGx?BJf)j0Gj9rwMS$E$K-=cR>H9;CGVaGd{P*nRjOo+AO|KT}KI?{YczpTFkRRQz^%&8wU8 zh<&B{fz7`Si))qkhuhlQ|NM1!$(e5#)r05WtKJV@qkQjmoW*=Mw!MY6L9wS!i0{*v z`o4Y2M*rWh-`|P7k(k)G?aJeXudA+|f4wgDZdJ|J=aZ|Mrc`m1@XKV`@4XVdP~-aq z4V(MCE87n|wEbAQ@6D;uwO?%kNn#Ir)*2Ng^X=-d z-m0jn|F(SX?eFF9b7lE^KhCXYOWA76BDSS|e<{CxTtz|ZHbQ8(I&W5+}VznM$tyaY85WA+)R&MSVlW5UU|OTXKgZ=0W!KRMu3#r3ow z-lru0%}MloKG|q(@0p6H9FkudPCZ^|oDqL7cDvc#ecybla?dw()}87ozis@ec~0c{ zABMst>+)_-H2Vu z?)dWGvR%9D-WJ3&Wd8ZOeuvIG`}A+Y&-Tw=_k4pbqtx>K+5W%(@hy4k{_je>q=9?d zz27TWechgS*Xr8y-Gz^jecPXZd4Ku$JHr3}t~>iDeQD4C6}iwvwz9JJ|Fhp8&z5g} zoM`ta{{hZfy=KMj=Rv*a+f6gIlb`L{ULGH#m>Tn&{oC<={k`A!8adAsHU8h~^Eu)8 zx^Hib=Nf-)m1A7`_4B7m=Qf-!Rx?juaQSO|#noS{Uf+Eo7*K7q^}P2h%?Z_BPabQ^ z)+hhhES~%K!LEwhx)1yR*e~4oTK?brpDmZ!d2YQwzVeE3qMDxk9GkhXk_-PbFTeEZ zhVg>U_Nkjb|6KNb`L{gYPu1_H$I88SZogeV;aYx;yQQIY3uV}B^pI+w9>nO z`(F)z*xI#G`{!3Ln^NT@QpHj7`K$N$)l+Vsf4p&HUF!K6LHv!!{^|X_7x9{t;moAC zhwl$c=j~XSRligHKu-EU_X#iA&P~8FqYheS_59!0{eJqt{NBs@e|-d+tm~TmI6Jwm z|Lr`~*jW%R50im*cZmd#1a?DsFt~M9;n`za@Wvg7cY{`b{6? zE}#46eyi-h#Xb3(TQslKPx$u#)|NlQnLm9qD^H#*v6qtkf9J5`)!y%Go`2k%lzPYJ zYsU#&l`gGnuPfh5PCTyPkX^o_{?qn)^(*mJ7rCAHerMIssE;eIwff3n@vUUde6Oz? z)st&YuFVZrzx?&(wz&0+jar{R?*6S9~<}?PJCCAD2H) ztzzK`Tc2-#@8!#Df6K2Q`}sBFYiw$ zyC=G1Wy?!yG?Qx4#n&U}rze@8f zoNe}9dAzXj&rjQDnwRGv_Yb?xoUoz(e!%1Wr0?^teY{uEUt`y>RJ`R=^L0D(EB}w@ zzR#8SxBOiHDJ16K58=1h|9?n+E52gl&-dH-b~sAO3$J89;PTS;^T{T6`CR$+mcsEb zGK;G2?mET3=ziT_{oPCQ_NcOQcN8yCOj?jHQiK3%JSxzFoKves_Z44RK`-qwAa5(Qfeuzi1Nm|H}75VczZ0v z-zvx2`&hSUe%qg#C9kW$b_y?y`|#vq!2Eqr9_^^iH;UbVgE`^CdC7B*Qu-ge$}fH7 z>9Z4^9$%6eQ}^WKx6j@)-?oBcDgNA-^H1J)A7Zwcd_Ver|9pd)`{b8j{+^y$`MA>i z`1OiEMa$~*rQ}ztJCwhDwTrz@?d|^QRZ1b>cuxG^S5o|}?!-K!zp>SAx9q;V%=q(Y z`lG+M9`pHKFM8j&HoV?y-TZUUXKOy5KmGsF zNk`XSf85xe)b{(sy^7j-cBQLIe{+lJX2t$Hb@c6N`7^d0pDMKXT>t%KmTBRRv!9r+ z#_n5GTd|C%KKb{QpZdM$-TE7^2rn?Po6UZqu9a>1r0<6 zXWxxiPyNBZ+*|Ve72yYmmKOd#&KExSe$$kn@0UN{fB(dk<3+Jn^QZ29{MqVn$(ziN zPaYd?{`ceJ;) z%gZm>bTo42|NkqY_c*?0-u0N9Rr~7CiU-}@KmGmh#jDu&#o2R8s*WG7w zMO-IB=vC{=Fzw$#X^X!H0-mI(r{I&ki$!niuXBhwc`D^K4eUHcQe@%(B|8~K7VV%m``d#wIZ`6aA z{XLX^be>@QKDqV(MbAgezUsd8dGnI#uUprizut5*!hi3NqYLZqPP}3K@bURwR&fhN zKUSzMOFrM+`M%OIvEf_v>%4vSFMn^oD6G)m{^z~>xjo_keqXx3b$QnBbNhbO8lHG< zU#4CE5qFz4Q$%6otF9~3^qGCaQUGr#-x z9L|M@j%pguHJ-e;_M`1n;v*S#x#{L%OLng8Z}M;`C~a`g4%kKdEizU1$Je0H;y!vEX3@|<7G z{g2FJI{)Ixna>|pyPfaa3K?&key_fMh5e6dv!m_pzq3^Qo_$Z`d;N!i*WZj^{xhix zc*64~C9x*-o5Tq=_DetBe_M4d`!Tn2`ljGzKh|;UcU*tJ{9omsc<wAz z{aJLQIN{Mp^{DUL7fks1|Dm@Y-`ADS{jF8?r+%E*>9iFsled;wpKhP_NWb#ou4|8H zzkUAl-t9X5E9YlLi0P-R-&-%-oy0%U)!$b3)&9@U_9Cz9t>&(KamwPKy58<3e;LBp zc7FY5+sb%%-plvTdj57)pSkjlWyX(N;g>#7m-{dK@&4({<@aX#h4VA~@H_d(c>YVq zfOM9b|0n*>e^B@gOTeE@EdSteN+fQx**^9f&r>4j*Th`hwg1&T2Fu6ujr*p~d>QoY z{}E^YcB}MX?AFQ4HgDF8>+g)+ecRsdYVVo^DB&x9aI-O=a7gz1M&D-L}86tG4XZ-rJ8Vs*f2v-SwaOl>PFL z9lvYebALVizQTP)|MK(ElZ;+92d4k?u zKLs@?-v2&XFLvGk`{L<+1s_!nKi5AhsD4(Tc!*_MFUpFE-9ly!TsvzrZW;*xJ$+`98MH>rOsat&OYe|8ohn zgwD8WW`~0gi>i5+O z*Zqap|1PXMw|TzotN*Wmy?)H6zfYrgeo1@ST2J$e@ZS~dV)oBI=KZfO?+WYR*y>l? z?$4h$Uv%~3AA4W-Kl)Mqu)Mu0>+$!c>!&+r$1Y-LIPk~7)by!R&1}mPf68N?=Krof zfH^Sb(^u8*{i*s$uv^iMGxf@k=Rf87-pK4c_xz*P^Ce#if4?LBJ^seN;HvzRRr@y? z+?zD#XZ*ie?>WB;FMmAy)%zdY)8y?Fm-hxL{J33q!J=Iv3hRZ5!?|6SW&@Kyi* z-}jHd{=X)@6}0hs!IPJzubpZgPc6Bg)${#|GHA49?Rjs{^vE}c8+QmFPhb4p^_}4a z(PQ6VezCE8{?DHOt9jh7N!Olh+RIOV`HPS1{QvvDGyk*Of8QCP|My{bbpL5j=>J`P+`Gtar`6#(_p<-ltAA_z^>V+3*sJipk3<*N#YyGgz4XI> z=KXU%HSa6y-q$K$jz96|x}E>tzZ==z>f>$xpL^02U|tosOec{7{JYc$dNS%B38Tu zkNiwnsIj-*`ufrD)0Tft4_nu9d$~_>;5m)={`2p5Pk-<~`~ADcs;f_1U!1?Hc-FgR zt_xna<-N$8HQgcLgK3jn>McKmroP3I>v)nk3B{J*ed4BUHSx&oz+?M5ttMMc&e+o# zX8D8f^Y8!7o3hf+mT%dvxxcD-Zya8H{p}UG z#;@sf&%YpmvjF|+x)wGKA->b+x}x8ul(ZXX17TFlU{zj@SWg= z55Hb7<*EDrQTgls_@%FRzWf>UqxQ_}{cm^sw|=bFo~`_u|G| zS;Bg{{HRZjrf_6U-p_r13u8{0r2l1Rf3X7tzmP2bEHxBZVk zPkQeE``oJHLqFavK7M$|cjdzW>#EP6Z~5qCzuYFh$^Z4SV2$*?&!3jPK0ouZ{+qwI zZ&jK6-J}2hpPPjJrt(OM{f~dW&OSfCre^-l9fm#r_XW={_d9i_{PNFv#($^2UcSX9 zHvZ^5$-Q$P_S@?Gs;u01?^4Bu_Elon!*|sEe`EiDdxhPef1eEgabCY1uzvaD^dp~B z?>GLa{dwZ~<@bk|U0=dHudm`AV?mtN{o?bTTVKDr9&UM%?aZ0-wm&x>Oie%f@!Z_4 z`v3d?zYI?NvwHuBZCff=vbW1IGMs5HJpZSD{`cv13f7Zr_S^xd-)_hR5@ZC^r|Fn2 z!>8gs{mY)W=-=PF``h2CKJ|VPC2cn9fiD>aj8`AOT)b*}Tuq>aytgew++FG1`XV3F_ z594(ibQM0^@Bcchy~;ntpP?KSPzRJC69(YmVwk+3kiTKhPy1bVX-}rVzZv}dU)Hnz zku8fRee}0w)asHv`(@7aFTdve+^?IOusVBv{kfm7zQp{fU0%g3dmyOIJiX-eYj4R% zlm5hfT{iRKpMQI5mp)%%el{k({7?J&YkKxp!u=nZHH~Xr>-;LJ>Oa2t_S<>yg5||- z^=j|xRX@+KVtVp?)AM-}bMFW*o^&xk?ZV#p{d#G8%IDsCSS7Xi^~6;ZhzTM^#dolAOF+yv}MSv{j@vr&m-&i zIp2QYoVnt-1havX(f`S3WkEiN_#2Xgwm3bOW0-oTUXyu_QTxxGPcQ%eX8!BXoS*Bz zu~=9HIR0wwc*1MEy!B)JT&tPa1>E@O?6c{qp8M;#$1|SyJF;g5>g~1PZ?``G!t*KV z*YDOOOVs~N{%_lpzx#2YLEU@l`yspc9h>=oT53_Tf6vNy9oy}%KA%5daDMZ?=L_E- zxqiH3+w086^~>4q%Ci6LwJ6#1@7K$t+8WoAc9NAE_cz+s#{4<(evQ@gvajBH*4jPmtIzW~+b%dGPWHUi^Fdd`fvy zn{Ds;y2DGiE)U;tAXk=DUUmMS!MxoM{**9CUE6ORyL-pwnd|QE|M^Y)rR9t3^DEQ# z%*(s?1{_si-c2&FtJx9RKdsqXj{ET)<^>yX-q@^`{;&G^oY>ual)mbm*q{E_bmQ{_ zSN`7bdK{|Fers;uJO+k80xAE*&A}-X;wQ)y`30_C=4HpP9ryXO>8@dLWYxK!cW#*` z+U(7*fBSm%%>PdQ4bAOrS{~>AJbym#`SU&g<}v?`^=(&Qd|jMoo?hjB{^z{>rDqCX z?tHZLuk5$tQ{Ix#_WwOIw~*DoI`!|*;1%aD_DUbF_?c|@_|DAP-Oulr*c{fH`M<5| zciQ9UXLT~SHRWZV+YmXu!S8VS{)cCtA3Ga)vD~)zgWGICZ;{FPOMBf`+CN6{&o3RS6LYD&p%`TaK645D87&y9uCqx{{&vo`Kh0xv^@R0 zX;rP^=X!V3o%%Qb zN6hEM_3uyb|GoTU#n~(K>(^H#+c@wq`TV!*&Ss^(`>%f~nzin|mf_y?dZes30TD0($@-EzZS^QJAIKjZoSN34l|>cy|!_ubFWUTzci|M$h0 zJl`2as&19&M@X;#ZoBcgTYc`YzdQa%7w*YQU3~WCvh(t#%Y+&B$>Rt!2kj{!1~ z1}R9^8W?{u6*HP#oPE9Jye*h6GkDm13< zMZo5M|C!Iuwe6^1@4tS3?(uK8-k#r9`|X>7-S_6%hb`=v|Mq?UzvAtuKQW(=&WqGb zow9qm?{&HNIX^!}oM*rEaj%lSxXs@Bn|-p0f4&^+{rWs!wOBsX=s&kkc>a~nr}zJT ztg!uaGURXZ+gN|@YTLCDn{2L?huS!YEqj0c)X#e*&BbZ^KGfc+{o^6=J;-f;^^=p0 zuddI$8@j)iIWC{UfD3ym2=dp{-E3zpp7o@epYsec`p?dHr7rFrX8@n-@_Ede)mECV zyHXyvetf%=-9fQ=*Smec4^>>QG;ja-c5^)U<2ixrWE{?G@~_+d^O(WEPsjgN+sJ4x zu6dGe{pjKBzUTLEUqAl%@8Xv~o?X_q-)fWoFMP>7hUT=U+|pD{Mj*6b?f@~ zB|*!opRc?1x>(Ehd+im;r@P<%Z~q}5Cd+;J`n>N#*Dp)N`oGqz4U{-vr&#yj_iu?^ zV)fVO(ZNe!Yk&XXVav$&_s_puHy$t8ygssDW@bIZv*t7ZA3Xv$3Ls@YB$-AfJ~;4t z<5$DSJ95fTSv>2hKNWLsZLILI%fG)}-?#6Q@Ph{jchr1cwd2o)g>Jtuzg@=j%ZSy3hVsJ&%N2^ zn^`~0Zu*|d#;^AN3VG|l@1uIw^ye;xnu~WQJwI2|boBf3k6-5P{rGFggFhul`z#jU z+o0;W{L<$|=9kX?1}EG9f5qG27S~G8*re z`_!jjcs?WCUV*RpnEh9V6N+#CH8Ov+7crXet-o(Y+0Tvca=eeFujO~#-mLXa=EWQ< z(PQuT{CsAx?teiT1?ChKxfk>=&-s=qbq^VsjsKj(Am%5tBgb2`tT zPbv5Bo_=6v|Ix?gN4a00f1mWoHg(2tUgJMI)g4x{JLKQbS#^Gr+w=1Ds$Ktnot*jR z%P+qyr3tIAXaA_Z`1bns>f?uRCs)4f{%!yH+w`6Do_(zPbi<1`t(g9=*uUYO&G}04ss~d_xc2X7_>gnrkMKXsCFn~ewm3eP zW4P}pdE`0oZgz*DlYhd$WXIpPuh3Y#p)S`_c<-A@-G_fX`8LDzt^AGn-TRjAem$T0 z?>6pa|3+*1j$)(#rSD@C|6J_<=O^+1*80CyZ-32Bn<8HIb9()E|LpJT_S5$~`4GPS zy59en^LNDKl0OFwqWS|9rHvRC@@&ubrkX{5gM&X3=0HgA4ApJ`Qn{quFd z-p)+lTT=UcZDm39n*Y7}d#rlOZAGiC{`9ZkHLtDGcCAgWt3>>#J2!-%8t?x(`{UQ( z-hF+iue+c7@m!AK<*(OvbxZ#JlKJ*NGP8E+ThBa;&pQ+UJpaebeBjCz(3agx_VU%t zYyF?qZ^Du!BrHDsxZ-XnyTAT{!(T4xv{~A=jC#8^>|5}B zp7=5Oy`Qxc|D2nh&-ZxtzYqL}eoU|bDVzA`_VgovD^F|xbCsz7VJy%8SpD5i;bYqC zJ8jweYHGh%%xwTw#LxT8ry8Grt-nX1=l|#IdqT&;mweW?FSS-*1sebRX>obY*<)Yc z>~njboqs>4wl;m*6+QcT)lpAgo3GEeN;_t~QvJl+<$f(6n^z~R{rP_X@48!G-|zn} zUHJX-r(p3TkH7D^Y8d+Oz|O*-?aSwJJZ_Jdx&A#kyH2Oa{?qdL9oJ9ae;;+{dT`bM zhx_}V|1Q<9N|lKJaPIWsAO7oZ2K{a>t~j22cHesM`}cRMJ5<$v{~+ATbnW``?b-f| z-@bg)ef#qH*Z#H))85>XjGuq)|1aZt!pG|Wt^EHa-jG39BmGym{dJ@Ny*W2Gr5^m> z7U%H}RPi^sLYgv=;z#YE&+Ba#=`lfWn~LA<1XUdqj7~2-^L&%H9^d1~E7cF=?oLYk zd^W$*`|Yo3@A_t5nDg`e?eF{CAN~9D?2LHU_4;pD4Hw^;@BMqW(cbjEDt6|-Pv*bt z)wdU%Uo(HcblfQk{#`b!ZQB3L>VEWT{acR5rqb71KAJv{5j)15{_pb7>-s58%fG+T zjhWaSJ8ABr=g;SfSzeAmX<~k6%G1T$RpRrPp019yk>CBYYG&2Fsfj-v?%m_Q*7ops z`O)+L?d2+rdcM!Aw5a=cS^e?XFUha7*DtU6H}CGI*DI?S9{ujWBVMhr=h;zx{>S=z zKHp8Od3Lq1(oULvUg5pX#d${aXY=d*@1^I>UwXg$+?#c7>*t@kJ-v$I z$=lb|RZMTrpO5sHd{I~X?AaFX$N%>JoVEHfcTn2%@ccc7 zJ@wx=&tDt+Kl|SAdj@rJrzZTn&Hnh`pPSs_?H}Xs{r_J0KiKWpo9Rd2)_>{$r`B`6 z>Sb%C(knezO<+C^3$a~_1}){H7u_FxpZUtVfFeyyorAn*?zRVcl`1%ubKas zo9FeME>0^yQuRA6`ESuNi}~kS|IXFiJf}Kqi5%nHDUSR8Ug1&*PmlCfbLd$SA*laXHu`-N*MnOHZH8+efn|5Z~6Ok zUtN}bD|tgZWsiS%uGX}<G$!RfzR}I#@P8Q(YrMXmp82t9{y+1NzwTVD zwdpzkb82|&$9?+s+H&heKh~`M!s2l~IQ_=;@bx!~-=2S|%l-JN|FMsE_kaJLSX1_@ zapL)NNzd%x=Pi%^(d7Lw?6u0Q7UetW&4-Sgjvw#UgH+ih3wzsCJl z&;@(L@ZI)vzufukck5AV_B`qD`I$9;SHJ6({2pKb`h0ugxgXDc{$HFD8TT*ZjEeo- zY3ntJCfY5BTib=hr?FwibZp@~^6we^%$5KQrmezhBSK$e*A2 z=Fa6sRgLWrbBomv|M)lk_~+;6*Vo7X*|YiFs{IQtf1Op$P;#mGM)mW#_up_U%dWpF z{iygB|GPfP_tyVUryu%pa{b>}iTMAWH!eSLQJ**e_^#rYuUCGkz45yL%kNJ!s~`Q# zy;Bh>QU5k~zr?Zgdmr*9?)kJub?etRWzy#qpI|E|{Oo%nNE4qT+8_PyEOF$Q@3 zdG7Q3)0a7qgWQbMUoB4$=5JW}>-+P048En;*Q~8~JoP7Jn|`W;ebw{uLqBBAk3a9z z_qS!5r}u^B#Mkr2R+h^DSC;R!?%5x^vRf6S`iar^(OU&cD>DcUptJ1zVFf zPraOC^#A9d*YY>wfB#GFw~^w1Ua}^?{`tCFpN+qNu$X$TfAaZCzdw7l*YiBi-}kQV zSCz=R@AoXVFaMlU<#T4)^G)#r#(#sWgZg`~7%SLMulst8`|hnL||L4Q; zN8I0zKd!&rxWDsj)vuWb`<{Cj{uB;Ao@5)$-#F)?eR1WQ|HbER_1FE6-)ow8fB#*P z@A|Rw+T8ckr@o(FvhPWiSiQivcYeq7o&SE+j`6>Hy#LBP|KP=S@BY47mo|TTwTQ^N z{_A_5nYK2b6Gykn!jnSSvc!9amzxIi;;*=S}T~p;4TAzD_ z8~+dPy?5WfK;d1%E6#vZG2tRc4pZl`{(k)Yd)WG}+tauGpIQ3)(2g%Lzy8Sl_WE07 z+g8(LbHSkb*B-ykKK0x7B-(0y)lO;oefQwABU-kMT(+!U&*S6bPJZyazW)D@Z!<2w zTmE|euQ|Ug_LZt#d%SOTyx6hwJx_HL|6G-hi;sU_^LLKT#Bb_zHyVFEzi@re=a1T{ z-!8ol&yR@z{VBM$r{;D&!>-m}vS(~ne*LWY^7{P$JC`3OY<~a!-NM6PpSwS7_)>Os z9@pKk;wDwKFTXF_tp8Qyq%GH_-_w`O(_e3`{H>zm{q1{k|7%yWGaOi?@Yy~ldRva< z?)?j&Pqqd%JQ4&Ul_t2*ZtyfPek1zKCu#eXm3k=^+B1LE{{GB$MAQ`%Xd@eCD)amxpV*5A@R14 z&*MJN`q4J!=R2D^4ZZk%HhKR0WS(F8x#N-LSJvCpU+pc6m3i;^{5Y%htLx=)Hv23; z&$s<|W1ZXa@~_9ZU!PxJV$1g{;AYVIsi*!uou~QoYy0eg2BI?Bqcn88`VUDo?rp|IDr#6VFNh-t*To`M$~GcuoI>_olwp{A#1|CO>%T-A4OV*Wju zT)4+3ZO`wW>4!EhF5F{f+g|5;CddD+@611+ulrxEy+5TYfycTy?v>_-2SshR*Ojlo zKe91oea!s|yD!!|k9)q7oKVG4(l58(J~@3^`>y><&(x=vg};68yZ^)Q$;SV8E$b-%S_4%-zC*>XI1mE|! z<^MZtex5C2{C}$Xk*}fixaXUkoe_TOqQU2R#$W!nonN^=<-_IY&*w2#g4(6i!>dG= zd@a3H{A_mK{{vpfw{NgjKL2O=+t=@VWf8ie~T-7(E0w)*Oz|$)pozaxVP{7qRIR9mj~NUn=f};ks zJEITgWq-e?+sW)qcd-Au=)T_lHNXfA>)R(eLxUx2?D4`~Uq~?f6E~Xlr`<-%qDl?`3bP z_kF$b!K`mKmNSih`X70G`Q+DGv%4P)AHVz~rRM+1$uDb8*s>Hov;Q{X#asIu8UJUc z{p-G7Zne*Nt49cHPl_R|5EY73!4{w`c-4YR{O5{@b%}9!!OF_ zoO|)_5VKJ zFkbNg$mGoG-M!oDFPy1=nqgn3!joQhOitMH^Lxwl42KI(>uzuP7+Ze#>Z`vWe{a~Z zE$60DVZF2YL+}V7`m|urZ8qEI=5@*`TKj%2VEXP+(s<^Lig+U@B3!HefiaJ@jd-7EI*#SuG8vy|6^+W%DemS)udnYzVz|ET;-;3 z6(ZFvPk3s=qT*f&8oa8Sa_;*wTi$Ci6YlL_{_XRw>TlQd-p}1Z+}^QjQxyno^ znGfcCT%YnwzIIJP-IBL=x9&c9db!m~_5-=rkG|RLs0x+X|37&Cs@VE-f68zDV-2i$ zSF_RG;ho{7kaKsY8~t25kJfe_ViTk_jY9;>Pu>F2)`+RZZ z51@m`jo)1rJra1T;5)y}n(Ch+{~sK@^)=K?eeL=y!V5NST`I@uYy4+vPu|9M$HaO* zIWO%uroa9qJ*%%i^~e0ok8qNa(_kJlaKveS$rF_GKfLB# zjd^Z;a%)fhxi#h7=S$zuEiU`}HG0=P@0tGs)BgqYPnz>mUvB=E|4XZQZv`)&@^ijc z>c8E07hcQOy83#{-H)IBPyAtK(0z^>eTmE7S_i!1EC8Li?kRaSJ?_^e1G~Skzqb^= z{#-R>q5sU! zkBT45-<`NkAwN!iZ+-IOuhWe-U6o_zjh}CPLUZvQdx`k?Q$ND1SVD}x@IGI0>6=Kk z!IW?H;fj-EPNY1aCp@=i$K{{j!&}e%KYV&x+eiQ9XZ{zTvsheKy-lz8{rxXL&mR|G z()0bwt*?c}-_Mw>idSWhJGEi?Q|`OM3qJj7d!0S!r~cK&FTc&NO?&%F`n~_Xdu_)z zZ>lH@|NFc9zJF^^ebxUnd+&2R=HK&x^`9sMgN_!K?qix-E&Kh?|Gr;u3)l}Ti!Qv8 zuYDbz_){Gb)6eG=AF9ZV`rkRlaec}^ZpoXEr+#1lwBJt5{{JKH%b%RiH!PE~d%o{h zvBLg+#uuJF`MY|JeriMi-O}#~zr$ZN2Hf1erzZByhWq=J^Zqlpp80?N|8@J7>&y4w zUr`r*|IagnbzfLc%zQs3aemb1b&`ZbEzh3)JOAxm?yR_YzVW}mSArMq`0u-P9=EY|dE3Y7`MWgd{g2-ME1ZF0 z!-^f4lMgc@->~j@#w^dFcxC(jie!$vb=J1a|4xqoE1y{Na^vH~Kl`4?OCDPuyT!1_ z-)7h1vg%(`dn&6OPhEKa{EGbfiMOU)wB7f2hBrP9g# zEpvXpUlSi5z5mp|>B?|HS#;9vaz7n2kJw0(*BRKGDZSYrO2iAFyyo8~KR-#aJL|5x?5CI18F zzg(a4sQmrP+P@oZ4UO+aPM^m--)OI8bNr<1*U!%nKk-5S^w*O!Kkun;^(j8LA-sxV zO}FH~+vQij>txLO`M)*(*V0?pzX$bqookSMdq?=e^>w@T_C4scKD6PA@PhhtH@|+p z8(zOhYv#v2|D5_8E`414MZjZy{+>O#v)=h1ejI%A$MVmsCwiaL;iMwm-oetj>UV;e9!*=f4f25y@Sq)e|B-3w-wrd z6?kD*+gGb8e9u65erOe6O7pt>13dMf>PvsE&hGxY=WoaviSnRl|8K7jZ~a(4O}96@ z`s>!jKaZ|BEA9S#&ieAh-rJiiKR^3b#b^0>PBqh?s;Ga~&EGgqNPe#Q^ZDcL>u>(N zU+-zF{pmON>0=YGgr$J1WNi-=ClPzdWWgRpS5CkB_&0)k>Ws zZpA#;-u64kkF8t&EcUHtdGdclR_fcIahCIgYps5B+iHK)ee>1m!`BO6ek}b}9#mVb zwtxO~^Q#7r?em^nGdSGFGJ$h}IpM^tZyZ0K$=4d`{P#N*U|(~6o58JFY`^TDLS6~@oy`8^YeMkzVoH;MHoKbzpm_OuIA(UwmYgqZR}1@ zJNDOC^1pa|Y3SQu`%2zK)YK~m-+Ni2_Uc#09pwivmp>N21}fZwrOmF?#o61J+ofJu zE|qrc_}h#xm;aT_dguRc<%HLhUu{>py8lby z{eaDBTPC|72l?ABygs$mFu5-N)DgQW#t$=pmj8RU&fwh4r{4WXpP#Ew|GCMa&fvR* z$FJ7&`;*?KNIaj%q^iE{J;&qAdbc8e|I*L98?}4?-zgvKKis+ck(Jl@pT3vm|38)e z%X|KZJhc3}RC34BX&vWmnf{%fq?%asDaB_0y5C3Cv#ytG{co?ak+To7VEFs%ap0*t z&%ZvO$5Q!umfZh256{n^Zv3_KfA~DnHuE(Rg2%QmyFS0>BlqLq!RH&S?|)h5WSRPh zkwI({c=!b}>jN2h$Y8Z)ICkdYW5dP!A8tCG761Prf1N>({m0w;WsiNYRkqvyd*Pm@ zygAHO8mT3_S1xy$R?TFyDKQr0tDVmszA3vWxBYwQF3aWkYekYgJNWA?STy)&md}~(y@4x$+ z`4|rHKf!ECIr1~8Mftf*7kX&)Pq^%l`bUp|k4;d~!fJq!(<%Afb|=-)n%f#Lpq z97?WD{>k28gk|MZ6$8ToiAkCA`t!8!uls!W>*E^sefGH2O^B4!H@fh{uE_R)3f7#( zz@Wo0^Z!Ss$2M_a%WHeSf1moA_10;uh2EB1%Y0`as(5{EZFg2ZBq4KDucu8*y^`i6K%}R z#gFa(8oht1hp@{t`3LP-x@_R!dGy5R$F|(tBB@RN`ZyC<0?*$|efQVL{yXk}KWO)! z?|;-qKhEFr?N+uZV}t8?><%$t^P2g8*{<*NC684xF)-i?dV@D->O1E#Ff?GKTjZ#O ztonisF{kIcaWW+Q`}^_ocAjlb%F8vC7%p^>s{8A_|0xpX@9m4X%>TZsxr>jXdk%&X zpyHGvfrn=|=w?NR30Py6f#FyH=#E(f4U8-UDU)&d0y4LQtYpiX9-#|q(cANQAN$TW z>;3ZCZ7(FHFfc5}vc3pZ%y^x1xn2J||34$cga1!4N+P5%gV+XH@%SKeb|4eOidnN~ z2eU9FEW*-ozQD}Dux#0~yq!aMS<`{l)=8`IiS}{iOEFr}0Ggzt^7&d5t zj_K)nzw5Q0DNnODEXRh?9Qb^Xz=mD8(MPJh4IbM5@9RpG+r_iM`+ zU;kcZ`#(cA8EWy-5Pghzy1*r?8W9n_E$1cwr+>b)&93Unn_Ql6diKZZ2U~Z`amVU^ z4c7k}q<=sC)$)0-OkY(^tzzQY&3@q8+UUQ6CO7W;|5KC0OuQMblBzS}o74Vzr~G4| zynTP>vNbRN*?;s7z}|J7lRKs)d^C`y+;tN;A$ ztaEJqZKMC6*JdtTwPnY9Qj0< zZOaYg|Bu&YE_(y=aHm~-``nGEzy3P2+&=dAulldowy%nBMmBU;oqOc^)B3yDT>K3> z=;6{|*{{E%e|(?3KT~`HIO(7yjaEt3jI>Ke|0kzi@QJLezdVn@*SP=iG~>q4e`B8i z`RV(5VO@SGJQCO47o7Za{&%Q*86l|}DYrC)O_;9{ku&puea(x7x1M(E28X?3+;HKm z##MFcvc2o}J)70I&HeAXK!}0ei|Ssz{3V;ZH*fFTZMU8p{r~*$`{ezR$7f)5W=G1u z#f7J*q*^Yv&pSVpl_6nA%D?09-Y-vFAM~ug1xxv_^Gl9l^1Pq=sein^&KJsV3;Zr~ z!j_rM^wqDPX#Tck=T+l!o`+xl)my#y*xQ<5{jXBXt5)7O4c3`g->>uK{mL`{Z-7(J zsXynHv84QNy?n*b_w_83!%pq^`?`F;bx-@;jndnzrkJb^*Su_*DS17}wmo*g=lb-M z3%*9>fO0}s@!wl<=M(?i`P|y??iQ;*^Z&-*zfay@AbbR~9yoMn$@>ROQvc0P`y*fZ z-zRzN=YIJ$=i@0a$(=#|4VQkaua!G|&1CV)d9PO1Jr1`28nnLk&pzob`yQ+1 z*I$;i@qNAj#(9VxnKxEX`6;iAC3&f>V{bU~|FAG)t+)aM14pQ*i(^Qs4f|OEzbad= znMW>tDm<;x7j5hP_4N6Za@&1AI-UNiZ5tl*ci9#1y~n=&lKEb>ZEgFZCI9Ee)!j_} zdH;FuHTBQ-@9XV(tEU?MPdM zQcr)XBHW_;45O5fN_{q{GVTzi+`zj;`6{M{gqg??WgDbQT$&+&KIs){%ddO z-Yct3@0UMLTWI{Q`|Y1ye>R=Ynx21qn{H3_-g^P|@z3^u`VMxay(5++*b_T1d1LCo z{~s5&XHD;qR$D)1ql`&%*r^-3+p1E+3V%i~@>{r&D{{{0ok z@BY;a-L1NvyY+PHzvqA7FYo*>J@Fy7DU!_>qzy7>{tsHVf910Crg>TWjI({`FXm?G ziMw5;G38&a;j4KJ-Mwf2S4{kwE`TKzpX~+3f5pj}`xDduw9WlFf6F`$Rp0ryd#Y9~ z|F!b^p+9vN`)8;a{eSHGY$myy!Q*x1$)(fHs%l?a?yy{Z z--Oxz<;+uw*Ole_k50=BJ%4iD@?R_Gzb-GC6W=^Herf%GpIhHUFIUCZ-Ao00bov?l z#aOxpiD@^qr~J&{K1cBM%+1Rr4{iJIBJusPapv>sRohn2d$qjobEN%#`*Z8n{@Z0n zAFJQD-W=47{(Qcs2(trgP{7}CblT7Jv(gyc*G@6a$+}}S{qx!_|CjnCg;nKk?s+|> zsxQ#?s{dcMmG_s#?&m)H(=;Y`z5C@e6)(RU{r~L!Yi7cMO1Z`hXpPyOtIng9R% zb2KiWd`~#>#+L|*cg4L|i#JrQn*VF-%DV2i-;e(^z46m9^Xm!QHG2EsY;t=){pb96 zqyIg^<)HNdkX8nyc)q}ORF0wB_OpG4T4jLcXR~)RzqOj(w-ua~7MB|1UR}Fl`LC7n z)$7yu+gE++xso%=|xT4(FWrJTvEUytRsN z%e`Z??$yp6uUFP}udb`BpA-M;d`}wavHcvJBzw`LjH~02B|E-z%-{aYQ zvtld}WBf++)E{F{wzGdu@9^U-{SOVd-pgNo{(g*n^Za_!dUwsw`*Uw^Gnn>MUUz1_ zS|^rjq7js%`@>%DJh`;z=8E~z_L*0>8D``!J@cRUdc6Fxy>a;~=Iei!Kl#V_B$n)Y zM&}FLo=;QP^E}?UbLYZ!{~x-`t&FvMd0uzl(`nIctIqF`+@kLEO+5bBC6DdfbHB=N zb$q>cUh~!9zgNzG-BYmNerc8EezEDxX8w<_zyG`K*H5GW6VKRpV{_-ZX}ZzBn%5+J zes;DuZoct<1_pzZ%a$+C1{E!9%PQAjmwxd%^`G+0dNE@xNyE5#okIGgU9rVn3=AKd z?-cy~svNujOufoy{{K(jm#Tu&61brWNl*)T)7thPa-1K`#lSE*<@UDRf3~*$DgPd_ zV~vLU@)g%(%UeILj{lqG&dAVkZO89-yN_p8Z_B&8Yej$i8GD;*Eaga=SQT@TKLZ1U zMEc#lzyFq4au&&d5 zas0hKWiHocJ?7!s!2o0xT&2WEVqE&l&q3ek|c$1+vgt`7{4x?EP{Eh6DV* z&*X0%#;o_6Nd%zY*og&j1RJNk7|9;^>SsJovBtnSU}adpC5P{B!sb z7QG8Ezb*USyk^1m*DIA67<3-(*POy|>ma844)uUW#(7WtarWMcIUxY**D$P5{>(3Y o2vaM>Yxb(2`Grqm${za99JSQw+`{dz4uL|?)78&qol`;+0EYQTqyPW_ literal 0 HcmV?d00001 diff --git a/src/win/assets/86box-rb.png b/src/win/assets/86box-rb.png new file mode 100644 index 0000000000000000000000000000000000000000..a29748b8d1b3ab51eecde6c0a89a3f08d6b632e1 GIT binary patch literal 35252 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 literal 0 HcmV?d00001 diff --git a/src/win/assets/86box-red.png b/src/win/assets/86box-red.png new file mode 100644 index 0000000000000000000000000000000000000000..0ddf9d3a444b5dbfb90f6d213da6fc026a2dd10b GIT binary patch literal 57521 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 literal 0 HcmV?d00001 diff --git a/src/win/assets/86box-yellow.png b/src/win/assets/86box-yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c74def72fdd6eae120d532b619ab357d84365f GIT binary patch literal 37482 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 literal 0 HcmV?d00001 diff --git a/src/win/assets/86box.png b/src/win/assets/86box.png new file mode 100644 index 0000000000000000000000000000000000000000..a29748b8d1b3ab51eecde6c0a89a3f08d6b632e1 GIT binary patch literal 35252 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 literal 0 HcmV?d00001 diff --git a/src/win/assets/status-paused.png b/src/win/assets/status-paused.png new file mode 100644 index 0000000000000000000000000000000000000000..e913fbf6c85fbc09228da5ba2a811ce0b6e988a0 GIT binary patch literal 8460 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 literal 0 HcmV?d00001 diff --git a/src/win/assets/status-running.png b/src/win/assets/status-running.png new file mode 100644 index 0000000000000000000000000000000000000000..f6cc5fec193c0507264090674deb51609ecade96 GIT binary patch literal 1863 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4iHr><-C@Gfq}6&$lZxy-8q?;3=9k`>5jgR z3=A9lx&I`xGB7Z37I;J!Gcbs$f-s|Jkje)J2DUq%E{-7;ac{3O@-i539N6%Cm)Mhs z!iw2J{I&J$4GN45E}RSsUJML@Obi`D3=UHm7#6WG2&ghNXpBmYhQ?^x7|jl&g~Moh gI2db(30sP@1H61Av{i%{7#J8lUHx3vIVCg!09eK$MgRZ+ literal 0 HcmV?d00001 diff --git a/src/win/win_discord.c b/src/win/win_discord.c index 066c927d3..54bdd4135 100644 --- a/src/win/win_discord.c +++ b/src/win/win_discord.c @@ -96,12 +96,24 @@ discord_update_activity(int paused) activity.timestamps.start = time(NULL); +/* Icon choosing for Discord based on 86Box.rc */ + #ifdef RELEASE_BUILD - strcpy(activity.assets.large_image, "86box-rb"); +/* Icon by OBattler and laciba96 (green for release builds)*/ + strcpy(activity.assets.large_image, "86box-green"); +#elif BETA_BUILD +/* Icon by OBattler and laciba96 (yellow for beta builds done by Jenkins)*/ + strcpy(activity.assets.large_image, "86box-yellow"); +#elif ALPHA_BUILD +/* Icon by OBattler and laciba96 (red for alpha builds done by Jenkins)*/ + strcpy(activity.assets.large_image, "86box-red"); #else - strcpy(activity.assets.large_image, "86box"); +/* Icon by OBattler and laciba96 (gray for builds of branches and from the git master)*/ + strcpy(activity.assets.large_image, "86Box"); #endif +/* End of icon choosing */ + if (paused) { strcpy(activity.assets.small_image, "status-paused"); From 9903f0cec170c9e368c978460b0ea9cc07210f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Mon, 8 Nov 2021 19:28:28 +0100 Subject: [PATCH 103/140] Fix a typo in Hungarian translation --- src/win/languages/hu-HU.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 6dd75e2d1..68a25c27e 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -789,7 +789,7 @@ BEGIN IDS_2087 "BPB ellenőrzése" IDS_2088 "KB" IDS_2089 "Nem sikerült inicializálni a videó megjelenítőt." - IDS_2090 "Alapértelmezet" + IDS_2090 "Alapértelmezett" IDS_2091 "%i várakozási ciklus(ok)" IDS_2092 "Típus" IDS_2093 "Nem sikerült a PCap beállítása" From 7900178a87ca9658fa2ad1af5165f955f3502892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Mon, 8 Nov 2021 21:55:55 +0100 Subject: [PATCH 104/140] Fix character casing in asset names --- src/win/win_discord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/win_discord.c b/src/win/win_discord.c index 54bdd4135..487157af5 100644 --- a/src/win/win_discord.c +++ b/src/win/win_discord.c @@ -109,7 +109,7 @@ discord_update_activity(int paused) strcpy(activity.assets.large_image, "86box-red"); #else /* Icon by OBattler and laciba96 (gray for builds of branches and from the git master)*/ - strcpy(activity.assets.large_image, "86Box"); + strcpy(activity.assets.large_image, "86box"); #endif /* End of icon choosing */ From 9914ad520c5bb7ac79bddf457b2b23174bd4047e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Tue, 9 Nov 2021 18:53:15 +0100 Subject: [PATCH 105/140] Multiple language-related updates Add the possibility to change runtime language, via --lang parameter. Also specify the verbose language code in the Hungarian translation. --- src/86box.c | 13 +++++++++++++ src/include/86box/plat.h | 1 + src/unix/unix.c | 8 ++++++++ src/win/languages/hu-HU.rc | 2 +- src/win/win.c | 17 +++++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index eca8544a5..a3ddd43ae 100644 --- a/src/86box.c +++ b/src/86box.c @@ -433,6 +433,7 @@ usage: #endif printf("-F or --fullscreen - start in fullscreen mode\n"); #ifdef _WIN32 + printf("-G or --lang langid - start the application with the specified language\n"); printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); #endif printf("-L or --logfile path - set 'path' to be the logfile\n"); @@ -512,6 +513,18 @@ usage: uid = (uint32_t *) &unique_id; shwnd = (uint32_t *) &source_hwnd; sscanf(argv[++c], "%08X%08X,%08X%08X", uid + 1, uid, shwnd + 1, shwnd); + } else if (!strcasecmp(argv[c], "--lang") || + !strcasecmp(argv[c], "-G")) { + + + //This function is currently unimplemented for *nix. + + if (!plat_set_language(argv[++c])) + printf("\nWarning: Invalid language code, ignoring --lang parameter.\n\n"); + + //The return value of 0 only means that the code is invalid, + // not related to that translation is exists or not for the + // selected language. #endif } else if (!strcasecmp(argv[c], "--test")) { /* some (undocumented) test function here.. */ diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index d413add7d..e28a40fc7 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -121,6 +121,7 @@ extern void plat_setfullscreen(int on); extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); extern void plat_vid_reload_options(void); +extern int plat_set_language(char* langcode); /* Resource management. */ extern void set_language(int id); diff --git a/src/unix/unix.c b/src/unix/unix.c index 286b937bd..7683dcd67 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -1220,6 +1220,14 @@ char* plat_vidapi_name(int i) { return "default"; } + +/* Sets up the program language before initialization. */ +int plat_set_language(char* langcode) +{ + /* or maybe not */ + return 0; +} + void joystick_init(void) {} void joystick_close(void) {} void joystick_process(void) {} diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 68a25c27e..f8fdbc41d 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -5,7 +5,7 @@ // #ifdef _WIN32 -LANGUAGE 0x0E,0x01 +LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT #pragma code_page(65001) #endif //_WIN32 diff --git a/src/win/win.c b/src/win/win.c index 6e397b98f..30f3412d9 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -1163,6 +1163,23 @@ plat_vid_reload_options(void) vid_apis[vid_api].reload(); } +/* Sets up the program language before initialization. */ +int +plat_set_language(char* langcode) +{ + int len = mbstoc16s(NULL, langcode, 0) + 1; + wchar_t *temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, langcode, len); + + LCID lcid = LocaleNameToLCID((LPWSTR)temp, 0); + + free(temp); + + if (lcid) + return (SetThreadUILanguage(lcid) == lcid); + else + return 0; +} void take_screenshot(void) From e2bdeae4ccb5a3b845e9c34987aa041d200883c2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 9 Nov 2021 19:50:42 +0100 Subject: [PATCH 106/140] Bugfixes to prepare for localization. --- src/win/win.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/win/win.c b/src/win/win.c index 6e397b98f..591caecac 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -74,16 +74,16 @@ volatile int cpu_thread_run = 1; /* Local data. */ static HANDLE thMain; -static rc_str_t *lpRCstr2048, - *lpRCstr4096, - *lpRCstr4352, - *lpRCstr4608, - *lpRCstr5120, - *lpRCstr5376, - *lpRCstr5632, - *lpRCstr5888, - *lpRCstr6144, - *lpRCstr7168; +static rc_str_t *lpRCstr2048 = NULL, + *lpRCstr4096 = NULL, + *lpRCstr4352 = NULL, + *lpRCstr4608 = NULL, + *lpRCstr5120 = NULL, + *lpRCstr5376 = NULL, + *lpRCstr5632 = NULL, + *lpRCstr5888 = NULL, + *lpRCstr6144 = NULL, + *lpRCstr7168 = NULL; static int vid_api_inited = 0; static char *argbuf; static int first_use = 1; @@ -139,11 +139,31 @@ win_log(const char *fmt, ...) #endif +free_string(rc_str_t **str) +{ + if (*str != NULL) { + free(*str); + *str = NULL; + } +} + + static void LoadCommonStrings(void) { int i; + free_string(&lpRCstr7168); + free_string(&lpRCstr6144); + free_string(&lpRCstr5888); + free_string(&lpRCstr5632); + free_string(&lpRCstr5376); + free_string(&lpRCstr5120); + free_string(&lpRCstr4608); + free_string(&lpRCstr4352); + free_string(&lpRCstr4096); + free_string(&lpRCstr2048); + lpRCstr2048 = (rc_str_t *)malloc(STR_NUM_2048*sizeof(rc_str_t)); lpRCstr4096 = (rc_str_t *)malloc(STR_NUM_4096*sizeof(rc_str_t)); lpRCstr4352 = (rc_str_t *)malloc(STR_NUM_4352*sizeof(rc_str_t)); From c892c521ea642cd5c406f5a6eab7159ba9f871bd Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 9 Nov 2021 19:57:38 +0100 Subject: [PATCH 107/140] More preparation for localization. --- src/include/86box/win.h | 1 + src/win/win.c | 9 +++++++++ src/win/win_settings.c | 12 ++++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/include/86box/win.h b/src/include/86box/win.h index 079463214..a986456d9 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -129,6 +129,7 @@ extern void do_start(void); extern void do_stop(void); /* Internal platform support functions. */ +extern int has_language_changed(int id); extern void set_language(int id); extern int get_vidpause(void); extern void show_cursor(int); diff --git a/src/win/win.c b/src/win/win.c index 591caecac..d7094ec50 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -241,6 +241,15 @@ size_t c16stombs(char dst[], const uint16_t src[], int len) } +int +has_language_changed(int id) +{ + LCID lcidNew = MAKELCID(id, dwSubLangID); + + return (lang_id != lcidNew); +} + + /* Set (or re-set) the language for the application. */ void set_language(int id) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 668487d00..e8e4f831a 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -77,6 +77,9 @@ static int first_cat = 0; static int dpi = 96; +/* Language */ +static int temp_language; + /* Machine category */ static int temp_machine_type, temp_machine, temp_cpu, temp_wait_states, temp_fpu, temp_sync; static cpu_family_t *temp_cpu_f; @@ -322,6 +325,9 @@ win_settings_init(void) { int i = 0; + /* Language */ + // TODO: Set temp_language here. + /* Machine category */ temp_machine_type = machines[machine].type; temp_machine = machine; @@ -447,6 +453,9 @@ win_settings_changed(void) { int i = 0, j = 0; + /* Language */ + // i = i || has_language_changed(temp_language); + /* Machine category */ i = i || (machine != temp_machine); i = i || (cpu_f != temp_cpu_f); @@ -537,6 +546,9 @@ win_settings_save(void) pc_reset_hard_close(); + /* Language */ + // set_language(temp_language); + /* Machine category */ machine = temp_machine; cpu_f = temp_cpu_f; From 0b1b116061f5e1146e6adf5eb67b58d82b445367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Tue, 9 Nov 2021 20:02:52 +0100 Subject: [PATCH 108/140] Enable the disabled language ComboBox in the settings dialog --- src/include/86box/resource.h | 3 --- src/win/languages/en-US.rc | 3 --- src/win/languages/hu-HU.rc | 3 --- 3 files changed, 9 deletions(-) diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index 7168ce5ba..eaadaccd6 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -122,10 +122,7 @@ #define IDC_RADIO_TS_DISABLED 1006 #define IDC_RADIO_TS_LOCAL 1007 #define IDC_RADIO_TS_UTC 1008 -/* Leave this as is until we finally get into localization in 86Box 3.00(?). */ -#if 0 #define IDC_COMBO_LANG 1009 -#endif #define IDC_COMBO_MACHINE_TYPE 1010 #define IDC_COMBO_MACHINE 1011 /* machine/cpu config */ diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index 8a0b4d9ab..4f05cb841 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -320,12 +320,9 @@ BEGIN CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 -/* Leave this commented out until we get into localization. */ -#if 0 LTEXT "Language:",IDT_1700,7,237,41,10 COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP -#endif END DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index f8fdbc41d..3514d391e 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -323,12 +323,9 @@ BEGIN CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 -/* Leave this commented out until we get into localization. */ -#if 0 LTEXT "Nyelv:",IDT_1700,7,237,41,10 COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP -#endif END DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 From 5616ffbed2850bfc661b92f853028d4058365960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Tue, 9 Nov 2021 20:36:07 +0100 Subject: [PATCH 109/140] Populate the languages ComboBox on-fly --- src/win/win_settings.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index e8e4f831a..c760302e0 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -318,6 +318,22 @@ settings_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn return(i); } +BOOL CALLBACK +EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) +{ + wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; + LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); + SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)temp); + return 1; +} + +/* Load available languages */ +static void +win_fill_languages(HWND hdlg) +{ + SendMessage(GetDlgItem(hdlg, IDC_COMBO_LANG), CB_GETCURSEL, 0, 0); + EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)GetDlgItem(hdlg, IDC_COMBO_LANG)); +} /* This does the initial read of global variables into the temporary ones. */ static void @@ -326,7 +342,7 @@ win_settings_init(void) int i = 0; /* Language */ - // TODO: Set temp_language here. + win_fill_languages(hwndParentDialog); /* Machine category */ temp_machine_type = machines[machine].type; From 11527d39b0f8d30ee0349913a2d325402473d28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Tue, 9 Nov 2021 20:50:38 +0100 Subject: [PATCH 110/140] Select the current language in the ComboBox, and change it's style --- src/win/languages/en-US.rc | 2 +- src/win/languages/hu-HU.rc | 2 +- src/win/win_settings.c | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index 4f05cb841..e08aad513 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -321,7 +321,7 @@ BEGIN LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 LTEXT "Language:",IDT_1700,7,237,41,10 - COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | + COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 3514d391e..bd9e7425a 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -324,7 +324,7 @@ BEGIN LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 LTEXT "Nyelv:",IDT_1700,7,237,41,10 - COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWN | WS_VSCROLL | + COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END diff --git a/src/win/win_settings.c b/src/win/win_settings.c index c760302e0..e46037e4d 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -318,12 +318,19 @@ settings_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn return(i); } +int enum_helper = -1, c = 0; + BOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) { wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)temp); + + if (wIDLanguage == temp_language) + enum_helper = c; + + c++; return 1; } @@ -331,8 +338,13 @@ EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLan static void win_fill_languages(HWND hdlg) { - SendMessage(GetDlgItem(hdlg, IDC_COMBO_LANG), CB_GETCURSEL, 0, 0); - EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)GetDlgItem(hdlg, IDC_COMBO_LANG)); + temp_language = GetThreadUILanguage(); + HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + + SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); + EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); + + SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); } /* This does the initial read of global variables into the temporary ones. */ From dafc429e934b37abf12a8ad7f7d7600612476610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Tue, 9 Nov 2021 22:33:54 +0100 Subject: [PATCH 111/140] A lot of changes - Fix the broken itemindex of ComboBox in the Settings dialog - Change from LCID to uint32_t - Rewrite the headers of the lang related functions (can handle the whole LCID as input) - Add dummy functions to unix.c - Add proper combobox handling in win_settings.c - Added a lot of debug calls temporarily - Reactivate every disabled option related to language changes - Move lang_id to 86box.h from win.h - Implement on-fly resource switch as discussed with OBattler - Reimplement everything language related in the initialization section of the program - Implemented the ladder of three points 1, what is the --lang? 2, what are definied in the config? (to be implemented) 3, what is the system language --- src/86box.c | 21 +++++++++++++--- src/include/86box/86box.h | 2 ++ src/include/86box/plat.h | 5 ++-- src/include/86box/win.h | 6 ++--- src/unix/unix.c | 9 ++++++- src/win/win.c | 50 ++++++++++++++++++--------------------- src/win/win_settings.c | 28 +++++++++++++++++----- 7 files changed, 79 insertions(+), 42 deletions(-) diff --git a/src/86box.c b/src/86box.c index a3ddd43ae..c67d01ff8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -17,6 +17,7 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #include #include @@ -395,7 +396,8 @@ pc_init(int argc, char *argv[]) int c, vmrp = 0; int ng = 0, lvmp = 0; uint32_t *uid, *shwnd; - + uint32_t lang_init = 0; + /* Grab the executable's full path. */ plat_get_exe_name(exe_path, sizeof(exe_path)-1); p = plat_get_filename(exe_path); @@ -519,7 +521,8 @@ usage: //This function is currently unimplemented for *nix. - if (!plat_set_language(argv[++c])) + lang_init = plat_language_code(argv[++c]); + if (!lang_init) printf("\nWarning: Invalid language code, ignoring --lang parameter.\n\n"); //The return value of 0 only means that the code is invalid, @@ -702,7 +705,19 @@ usage: /* Load the configuration file. */ config_load(); - + + /* Load the desired language */ + pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); + if (lang_init) + lang_id = lang_init; + + pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); + lang_init = lang_id; + lang_id = 0; + if (lang_init) + set_language(lang_init); + + pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); /* All good! */ return(1); } diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 4066036b4..a49fb198f 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -15,6 +15,7 @@ * * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #ifndef EMU_86BOX_H # define EMU_86BOX_H @@ -90,6 +91,7 @@ extern int window_w, window_h, /* (C) window size and */ vid_resize, /* (C) allow resizing */ invert_display, /* (C) invert the display */ suppress_overscan; /* (C) suppress overscans */ +extern uint32_t lang_id; /* (C) language code identifier */ extern int scale; /* (C) screen scale factor */ extern int dpi_scale; /* (C) DPI scaling of the emulated screen */ extern int vid_api; /* (C) video renderer */ diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index e28a40fc7..148b396c3 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -15,6 +15,7 @@ * * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #ifndef EMU_PLAT_H # define EMU_PLAT_H @@ -121,10 +122,10 @@ extern void plat_setfullscreen(int on); extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); extern void plat_vid_reload_options(void); -extern int plat_set_language(char* langcode); +extern uint32_t plat_language_code(char* langcode); /* Resource management. */ -extern void set_language(int id); +extern void set_language(uint32_t id); extern wchar_t *plat_get_string(int id); diff --git a/src/include/86box/win.h b/src/include/86box/win.h index a986456d9..da4d9fb05 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -17,6 +17,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #ifndef PLAT_WIN_H # define PLAT_WIN_H @@ -105,7 +106,6 @@ extern HINSTANCE hinstance; extern HWND hwndMain, hwndRender; extern HANDLE ghMutex; -extern LCID lang_id; extern HICON hIcon[256]; extern RECT oldclip; extern int sbar_height, user_resize; @@ -129,8 +129,8 @@ extern void do_start(void); extern void do_stop(void); /* Internal platform support functions. */ -extern int has_language_changed(int id); -extern void set_language(int id); +extern int has_language_changed(uint32_t id); +extern void set_language(uint32_t id); extern int get_vidpause(void); extern void show_cursor(int); diff --git a/src/unix/unix.c b/src/unix/unix.c index 7683dcd67..4a15dbfb7 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -1221,8 +1221,15 @@ char* plat_vidapi_name(int i) return "default"; } +void +set_language(uint32_t id) +{ + lang_id = id; +} + + /* Sets up the program language before initialization. */ -int plat_set_language(char* langcode) +uint32_t plat_language_code(char* langcode) { /* or maybe not */ return 0; diff --git a/src/win/win.c b/src/win/win.c index 30a73d048..1aa25a8c9 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -17,6 +17,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #define UNICODE #define NTDDI_VERSION 0x06010000 @@ -66,7 +67,7 @@ typedef struct { /* Platform Public data, specific. */ HINSTANCE hinstance; /* application instance */ HANDLE ghMutex; -LCID lang_id; /* current language ID used */ +uint32_t lang_id; /* current language ID used */ DWORD dwSubLangID; int acp_utf8; /* Windows supports UTF-8 codepage */ volatile int cpu_thread_run = 1; @@ -138,7 +139,7 @@ win_log(const char *fmt, ...) #define win_log(fmt, ...) #endif - +void free_string(rc_str_t **str) { if (*str != NULL) { @@ -242,29 +243,28 @@ size_t c16stombs(char dst[], const uint16_t src[], int len) int -has_language_changed(int id) +has_language_changed(uint32_t id) { - LCID lcidNew = MAKELCID(id, dwSubLangID); - - return (lang_id != lcidNew); + pclog("has_language_changed? lang_id:%u == id:%u?\n", lang_id, id); + return (lang_id != id); } /* Set (or re-set) the language for the application. */ void -set_language(int id) +set_language(uint32_t id) { - LCID lcidNew = MAKELCID(id, dwSubLangID); + pclog("set_language %u, lang_id %u\n", id, lang_id); + if (lang_id != id) { + /* Set our new language ID. */ + lang_id = id; + SetThreadUILanguage(lang_id); + + SetMenu(hwndMain, LoadMenu(hinstance, L"MainMenu")); - if (lang_id != lcidNew) { - /* Set our new language ID. */ - lang_id = lcidNew; - - SetThreadLocale(lang_id); - - /* Load the strings table for this ID. */ - LoadCommonStrings(); - } + /* Load the strings table for this ID. */ + LoadCommonStrings(); + } } @@ -464,9 +464,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) /* Set the application version ID string. */ sprintf(emu_version, "%s v%s", EMU_NAME, EMU_VERSION); - - /* First, set our (default) language. */ - set_language(0x0409); + + /* First, set our (default) language. */ + set_language(GetThreadUILanguage()); /* Process the command line for options. */ argc = ProcessCommandLine(&argv); @@ -1193,8 +1193,8 @@ plat_vid_reload_options(void) } /* Sets up the program language before initialization. */ -int -plat_set_language(char* langcode) +uint32_t +plat_language_code(char* langcode) { int len = mbstoc16s(NULL, langcode, 0) + 1; wchar_t *temp = malloc(len * sizeof(wchar_t)); @@ -1203,11 +1203,7 @@ plat_set_language(char* langcode) LCID lcid = LocaleNameToLCID((LPWSTR)temp, 0); free(temp); - - if (lcid) - return (SetThreadUILanguage(lcid) == lcid); - else - return 0; + return lcid; } void diff --git a/src/win/win_settings.c b/src/win/win_settings.c index e46037e4d..1a1aa12a1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -15,6 +15,7 @@ * * Copyright 2016-2019 Miran Grca. * Copyright 2018,2019 David Hrdlička. + * Copyright 2021 Laci bá' */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -78,7 +79,7 @@ static int first_cat = 0; static int dpi = 96; /* Language */ -static int temp_language; +static LCID temp_language; /* Machine category */ static int temp_machine_type, temp_machine, temp_cpu, temp_wait_states, temp_fpu, temp_sync; @@ -318,7 +319,7 @@ settings_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn return(i); } -int enum_helper = -1, c = 0; +int enum_helper, c; BOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) @@ -326,11 +327,13 @@ EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLan wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)temp); + SendMessage((HWND)lParam, CB_SETITEMDATA, c, (LPARAM)wIDLanguage); - if (wIDLanguage == temp_language) + pclog("widl: %u, langid: %u, c: %u\n", wIDLanguage, lang_id, c); + if (wIDLanguage == lang_id) enum_helper = c; - c++; + return 1; } @@ -342,9 +345,13 @@ win_fill_languages(HWND hdlg) HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); + + enum_helper = -1; c = 0; EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); + pclog("enum_helper is %d\n", enum_helper); SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); + pclog("win_fill_languages\n"); } /* This does the initial read of global variables into the temporary ones. */ @@ -354,6 +361,8 @@ win_settings_init(void) int i = 0; /* Language */ + temp_language = lang_id; + pclog("temp_language is %u\n", lang_id); win_fill_languages(hwndParentDialog); /* Machine category */ @@ -482,7 +491,7 @@ win_settings_changed(void) int i = 0, j = 0; /* Language */ - // i = i || has_language_changed(temp_language); + i = i || has_language_changed(temp_language); /* Machine category */ i = i || (machine != temp_machine); @@ -575,7 +584,7 @@ win_settings_save(void) pc_reset_hard_close(); /* Language */ - // set_language(temp_language); + set_language(temp_language); /* Machine category */ machine = temp_machine; @@ -5229,6 +5238,13 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) EndDialog(hdlg, 0); win_notify_dlg_closed(); return TRUE; + case IDC_COMBO_LANG: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HWND combo = GetDlgItem(hwndParentDialog, IDC_COMBO_LANG); + int index = SendMessage(combo, CB_GETCURSEL, 0, 0); + temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); + pclog("combobox changed -> temp_language = %u", temp_language); + } } break; From efc2c547a000a4661183f88df336a5f07e847e97 Mon Sep 17 00:00:00 2001 From: dob205 Date: Wed, 10 Nov 2021 09:53:47 +0100 Subject: [PATCH 112/140] Preparing macOS app bundle resources This commit adds the app icons for the macOS app bundle and a custom template for the Info.plist file --- src/mac/Info.plist.in | 38 +++++++++++++++++++++++++++++++ src/mac/icons/beta/86Box.icns | Bin 0 -> 169574 bytes src/mac/icons/branch/86box.icns | Bin 0 -> 194973 bytes src/mac/icons/dev/86Box.icns | Bin 0 -> 217773 bytes src/mac/icons/release/86Box.icns | Bin 0 -> 196323 bytes 5 files changed, 38 insertions(+) create mode 100644 src/mac/Info.plist.in create mode 100644 src/mac/icons/beta/86Box.icns create mode 100644 src/mac/icons/branch/86box.icns create mode 100644 src/mac/icons/dev/86Box.icns create mode 100644 src/mac/icons/release/86Box.icns diff --git a/src/mac/Info.plist.in b/src/mac/Info.plist.in new file mode 100644 index 000000000..e06b17ecf --- /dev/null +++ b/src/mac/Info.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSPrincipalClass + NSApplication + NSHighResolutionCapable + True + + diff --git a/src/mac/icons/beta/86Box.icns b/src/mac/icons/beta/86Box.icns new file mode 100644 index 0000000000000000000000000000000000000000..0068beeda30c9d8219a71b4467cd5e0dd35a9e6c GIT binary patch literal 169574 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 P-`20atMM!ST*W>6;$zm9zb78P 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 literal 0 HcmV?d00001 diff --git a/src/mac/icons/branch/86box.icns b/src/mac/icons/branch/86box.icns new file mode 100644 index 0000000000000000000000000000000000000000..a2631c66ed8764c3633af309be5422fd5bef64c0 GIT binary patch literal 194973 zcmc~y&MRhM`Z+f<+0clAfkUh_z|WnRONxtufq~c4!zGA;fx!WUIoKE&7*=H#-eX{3 zoSfB(zWA~HS4UB^vPcQK0Ug+BIyWVy7wXLNW%{aQ0I?Dbs?=@4ryt8kiXyt>Vx|;8E ziqHRLcrLa+^Jt&Kf)&f=b-C{Nd4}nET^sw|7tPX>_atOIOfh2YdjH4R?%jigpK1rv z{_f3}woN)Gz`*WqqnfeHbB~YBo}{cE^A7fssIH3X8&f_@K3;S7YL%~*sOmn|XDl`_ga?bO}lzo(ut?=i~=WL z2h+E2je(u_VtyT8yl$5} zul%iRCN+PUY9h;TyFM)Z&A`B5ks9Hd=IhI##lXP8!NAy_$-u(Ez`)4Bz#zo{0!#~- z;35tSm=SD{Wa`X>E(QkHPo6H0Ar*{oqxS~gu@af~{sYU(7l$t_S?DvX)hHlkhyKA7 zHBFDWhNrBPM3yY{JL$7xhKlHgCB8>ncwVloV2!WcWdC-f?#)Tp?tL}7ZrrzI@#4jw zYps46&-PKZyZq9`KWEpLv|G>D-1`|7D-gu?WA5C!0#^fH5!y^1a;$U;b0#k+u{e684_8a+IKDYk+R;A&=`gQB9de<&;`XCbF zTA*lG?$&Vr#M7rs*Jl}6E>lz%jGp~EaqsGLs@`f2{=C!oI;MUtUBM@oKKVwYry7HY z`s9-f8j^dCGcAAn|2l)wL6iR<7FHhn|08f`dd$UFRtfDhDxT^5_Vo;QkNuXqyn*%K z_w{SOKij(R)V;mhub6L5ShBC<#HLdd@4ZeBZ&f_dpw6)@R=2cvow9QESFe>FW(te= zg?>rYI?P$i$RNmgPD<`+A)LZMO>4Ho9+5YFd8fe$B8mcrVHT?hDy)-RKebLH|CZ3ZS z82>$ZwCK@|ckl1J{yg5VbhKmIgIMJ%T~A3(PG2Uk6D;-R<>@Nw>gulop6A8y4}10U z^3AG+j_>BrU(J4eVaJjPB{l^|xz5+>hlRYdjiOm(vlz~o*Vf)$xUigw*X~DV=d=WA zr-=_3W%5s@TjjHK)IB?=BqYJw)3vjA8k@zdmA8|$8KtGAU%h#ArlhpK-hTS|TIS`( zEc2=?qfg)4e?BJq;mdpTcHO*_Vy|ZUS)N;d`+=f^C1?M89d6{3sO6lKa-_t(n?Wz9 zs{3$Qd+r5>Y1dRL6rUT0cSzl|^Q-4w95sO{>XsqP4Gjlghb9&wrLC5qCQMbCn>>9& z(MtVKDl7Aqb_gueUdO)Z_PI5^4Bku!4ZhBBXlZGhuJ&se_W`wo!WF031$XoAy2kjj z!d9MlU-N}se=isvT<*sz%qX^}B&dDIXU+bDKW}f}{MtYyww&?A(}(Qes`qgV?1)mmOzGD7|Isw>w)}5nq49u;Fy@ zywYQj_pH3Wcz*5wywJTYXH4FFKkU8NmhW#%Lp#43(--%(KJj@)&o$3K)jaS%`&Pl9 zsqV4U^->?Lka;CDyKTuz!PMmrtu1|Wg~CTP-qrlNvQTr?Y5gOY*RFMZRzL6g=h*g# zTAl)V)|;a*KS~gEW;$Hgak1P=Qe%stL+ylyJ#kCV@-Kce^X^ld#*KehE#+mJ#=9W5 zI%l=_*Xm4`9|wLsVR*6n^GRoqP9=rXrKOfZ|M&8j-a4>k%fi_BEc?!%B1>dgPLwKa z)5(3v&bLl{_0IRDFVFvW?$lsXX{h|1|H=H-aLYHz2bx)|S>>E>9B*Q0Oyeqeq9~EwaoF7E zl09d{v)zaGZ3y|t{bAR}%8A#Le!p_nmtWmur`+0K)B0a@&OWEMwwNzZ?tC|u=$@0_ z`DCJgV@MgJlq~lN3HvV&L3=lC2!7%HR_R5s#O67R=X1&32%E*gFoWIZmT}Cl{c{ie zdL;L#f%2h{?eu6{1-oD!NclMT!n7Jn| z3WigwpaH2>0E%aZY&SJu1_teu&{n}*&Wbr#E8m~*QPKaTbb8X$yVH7kS$K}Uk!Wg- z%*!}+%X^ww(`2?;mzJn*+4+4LXGF_{CvlS;@~VHUq!>?lX4ZIbiRZlKxlS8+HXbw+ zIG}dp#*I&E?$N^_gEHvIhZeCzu+?|t3#+%{cF&woS3 z$49JMtJH)#pR7D`dGibfjyb<}tlG7!DpJihV20~Aky7cRW-J5%hzDuo_Or5~{Bz-Oe+r;^T@2ci%M4vdX#mJ+y|9Zt)jpiIB`)rUY zJq6cayWDiM6MeN+{($oTce~%0O`SS*Z{CvxwwKing>|O_^#8Ko-SgIzQRDwCR&Ftg zPr`g1d0jF!cW29;Q2Vsf-Hb!w<~&CxkFui;J70V?m~e9LLC$%M&F_V^Ze=rBC>}q^ z&b*49jWfYvq4w{oXIJq~@charWAWf##p7O|NqjF%_-(&TsQ!G`JT^HwxxFl=_Ul#I zcbD(R6rVMH_pn{wZ~Bt!??3r5*#G}|{_Z4I@2c33|K>4vtXs9JNPpjtN1UOt`)Yo2 zo)41W^X*plnb*th&i$&r$I0+ye*M3neGeuCOG>Ptuak3Yi)MbKacvUwoL498BaeKR zJ&~W0QDB^Y?v1aRWc_V*mI;M#{WiBK+-pCxkm(a+Gs}ejxN{45Ch&h}7GV7TvtiF| zhMyT%9JCKB&#QXQ{c&GE8|Q)VF7k8t-uS-D{{B^qOs0%qufjV&um9y6J$v?++TGcI z@4k;Yxh;2HB>(Z3D`s1nX6ITKT)VmM>m_f$6YDdsW|^n`-6cHl`*-%YZ{I$%OJDMU z^TDESJuj(-pHrA@)f#rKuSv~xw7GNR*Uw*0sf>&-W~^0j-)fN9@{C=9?SQaTGC#+n zch2%fXS?$A_kIaFz4&y!{O=jJXI4ahy8Hgt)g|-)Z8`nq?@QJb-`V89eiBlce`5Ka z9!`cn@uF;pyn_du^{T#T+%IpqabaQJmU&zH<#JsPoW7~V(~&fZgDGi8!Lc5``#)wM z{>1y{&xdwvg})IidafPWYA?Q0r{S}JZ149w$=|D8MUt~o7 zr2n0c?f1O??m7Ri@cpyHho@&UUlww3I)DAZTLsgTU!BUHM68}Fc(K$VrQ_Y#HD4RJ zySm=kNd%=R9uE}kZ9i1|JLckwz;`S8YYyDiRcd&>z3#CzpI`pH-PdK^vmSLPPck}X z&bi54Myvg~^CO`H_g4OSR{JqsfbR%{;sU2_uQaYFbrzntnS5rMzJAf$+wU`P?^0pt z|I;zS*yRMHl5hLtbmy`;3~wBbm(6!L(Z6Net%r|1dlf3!5^wBYd;1Pc?EUWt`FEYa zQ@>wvf8qOmKfeFl?{1U+RMxUcrLThH0CUR(g^q^TO0t4GO-t^sd9TnisqpDCxo@7j z3Zl#Y-@X5HJ^T4ixffFyY(8~=d(&BL>nPtot4}#xp1pl`OGDZ7mKb$e{!h&7j`qgv zR#>)q-BiEVp=&MfvHPBKH*ON&`*WIg`4f-u&vj?}M8%I=#%dkD+AZO*XM%L*#mM6#VNv>g4f*_>oHtBW#(~~mInb4xQx;#t&ezMXqFiBDjQvdYd{Zhw>IW7qe)|AjdmLRUJznXM@P z=+A=CU2=SGDzEj+mfYOhJ(>9?n_ywy>?0)ye|&U0W*{zWcZTEO1iz{d)<*&&els52 zDtlX$oGQI1{`|jB-1YD6ejZj8Qj(JHeyl8|?3{3DDYsOry@QVj3tz+LeUJBg&I?qv zdYL!nn7oy{m)p*c4yMe6RnA|PbT2JP`INH#>9y#)mVZxZERn3`l;v=^v)`h#<|@}* z`Kc$`gnh3#Gd%Lxv9I=f-gAQwM`G2wQcI31FbO*N+>vh8_SN->S|H@&ux#iizv|IP&!5p7nJpoH}yw#oLv$-pfZTt@Dw{ zU^HtK;7D{)_bZq&p`dEzr}{rXpWj`+ZqKE?dM)m=_;x9*%3655wSr^P;eLl5d@6-} zFLb_07xcepd{nZEzb!ey>e|kUlh_`gQsI1bNqJEf`>%Hm_jrXI_Pn3Oa-s3J zJO2F=pN`I5)?Mn>Be(i)(uwuro2L0nz27I_y|c8c+~@fzS z*#Nu4DNna|A70@Rdfr#glHWV4Bx^b@%?-%B|J2E*^OJV}g;IOMlou)lcR( zB3rJB=1g9AQ{!qw_bQK=yh{#85)L1>-F<~mu};O#>)<`xcN1ROaD0?AVDgCgC%dQS z*xy$r6Yj5jxZwGp)L`|U`Er?syO-39-z#WN7D`@WC2gU__juOl*X#Gc3o|j>v07W@ zUFrhS7t)(Gb(St^_}8_BYl48^VaqpSs7%mnkkSM+465<-6|8e#U0tV zPY4EmFN%7(cje5W)_JlQ?pT?%C_HN4R(9R~pYMD-+sKJE`s+RlE#SJFrLeAhm2<9- zery)o{5j?hy*&rh9iCjte5ar4>p#on7>$y}w?q&Rc0NE}}3?NKi;9v7PUV$0QB|mW}Q# z!B_VEW0-r?&51|AaUTbxo8gCl)%E#d`;Qd=KGs{-}LB36HHCO&B{;B(qn zo?XJASWthj^7+pDS&J5XD*ap0*6}uolkuD)|Dzik9Mcmc&RN)cH@H}+3kEjZA9fS$ zQAi0X>i2q?{o%y&^Bpq(<}SNzSU_db?smBJF-)7M9CKDH`pA5ZLF zRr#apb{{#vug$O3)_<*T!+2v&Y`fpV2;;2^TTZ;*7FhLb!IytMk~7LLZFkb^V1F6+ z{qR?XdB*Q|t_xoNe$sb+PEP)~2@V!6ZA_azrMCMO!U`DVTat@wVn}|bRsvYJP-Y9=CDUWadM>H<||9*ONOcTKXi_r znf6}bbt21esY@LpH}u!74qxuBrPa58l2yVtfdlRRy@FGNH3ZV%O}%%{%z>r$?8lY4 zpYHHqT5NHXCFXFz7v+zPQ>RX?oN2c0QtvMbse@lvbyzkS%y1ApUvg&Z`G0R(E>7Qd zr<1K><9W%I4$jxs$G?w?in^l``KY5@_#>xj;hm+@J7(B4saoYQb)NAPUeIsxqJG+G zLEb6rzcTFWp3HJVYwr{;iHslL7hej0`{{ZAqJk2$l<`Tw(Yhx^XwafzqC@A=jbQvT5Y-T_UeaMcgydWD$G>oDfrtZs(t6wRBd0a z7`^7gMN2q$CQq2D-v6_eg++-e(&e3Xb@}eCG4t6PKDJ98c<_1KqwE|IR-Z8PdtS@VAnrh1pi^7UPXaG#C=Je(t@yI=1$u z&TjkIe|O7n=N|j3@Tbnzt(EcIdG_zY%LEUk#{YS=>21GVlyTLU7g`(&O6|Rs%(`d1 ze#Ny#FW6|)Vi2jcKSt2(^ZoL^-=%-+zBhgOerf9JGyDf)4rrV`7He6!Xm{2xlkFQ~ zQdFPtC%@XUz~M$%+^k3yJBFzZ|MX`CJnZwicBR1PmChah<$t!io47nsjPLmVRFbh^ zvogmj)7YS9kq)lT#v_7?u|7*&Ogx1H1=QX>bUJ%IdC!Agd-txnqpKnJaMknJ7h$K> zW-Mvop15`P+KWs{_MJ7B6FFWstw`eGe(K*agR3Mb*mC!>^P#*Z_X}n@?VBj~?wJas z0;`lN>n#=5GrDUGErp%L8V+9Ib($b6z_F24YE$AxBD=bsPJSBmX_Gsne@&?mN}s3=(3X$vFE;jMjUwftB6 z_m#|g^s7&K-jBa#g6^~3c+X0usx-b=SR!E3ZLnfFJ4e!vD?%c*w)L zJ#*)r=QZa97!SAzG!)Lr{=Fc%f7J!!eLs%2&%V0ynWPGX@Pg060w!0YLwp_1#69Xb zF=2Ca==vipO80cXc)Kh%toK>WY9X(*Dc}>!_v_uOughc`t-HTw#$RQpe~P^lQ8u46 zr{~{V;$>2`VZ+C{xBKTuI$zijpZap{B?p1u+jC0YzuG3g5;*kixZLN^_vYyw4DX&F zSitsi&PQegd4})xe;&)5Go2`1>OX-&L?bu%Si-~=CJATfuKC`vr@`>(t>SGH8!t76 z95}S0cXvN~)CGnAHg#e`t~`QAg|}q?I4-auWMlL6GyATs{c&Y^%x;(3!+M=ervp0J zU#<{VW}4e6kSE^$B6LZlUTUw_qlc-lY!)>oPhts*Tro4vlWW?{n@m9~g*pRl7w;%0e+9 zBf@8r!-)+Cgyv4wsykm0z|k!;;l%CD*Lf@7mTvdHw5W9QmD2@BS(0>umMv=L{VC;o zBZ>c$z@wGi8|w~U*dZvHDI6%U&}ZgvmCP-A4ez7ddCS*IZM~6|B*<9J^JV#776Yb0 zW&y@Y3$|^$rq-muus_P;&iS3Y>>3&PY=6B-T9diMUh`MzNfq1VBlicbpq`@L1N7=uT{fb6B?bapIC1iv|yF#j$NR)uyc|N?T~lwUE^Zb+ zkrCS9&NH!J(9KFftzY4B?Yi5l=jOCcS|g+MXZBWxZ*ne%&*gIqFAC|ZObjpV`Ly%> z@&AwZ{b{(f&_hscftHa)!{?2%E-q=-Z>H~iZhOzuu-Ya4&}kpuLbd# za&`D*yXCarjqRKLUNausVaVh7TS9>$jX}QR0b_V*=u?Ig3vu3d-~e zbl(+!o@}s6XTJkWp#0?Sn@(5Tyki$MEtz$Ok&)3$$u*>0Y?2#)<~hbv#*JQQ_oym= zel;t#($PN2R@Ok+gNNbx`}+UCQ-YQ-vV1xs?5{Ha=_e&k#s_t`nH$apEf-s%94R7o zLLynLe`AI8=?yA%i!be5eI!y^+3W^Wf27ujUP z{JNj1=23o=uW{>_oDRLdU{Ory^!JR@jkR3Z(l7N*oYFCM`p&hFweL8a|C{*!{hWCp zpOvyJ%u$}*Aazn?5=+5`9XnRVtc#zJzq?kUtMF-8bKh0Z=iR|ykFA}U@wa}d>O0=Z zo8f2Xzkj#qN0KuStC8*-@wN*;raJvu`{ zWqrl*y^HQ1XydG0JF8^Yq63qsZNFbOwaambr`w$;CnsA^DZN{IeWu>sZ|(Lw7S3v@ zN?gR_smrnTq3B_cD~x5_3qEn!RJueTGiZF;o?xe@KQH6KfA*h>ok5plyC?N65aKac zyfdMH2kXyAc9*x>T>ss>X-)l7*9F#F``;cH-Bt5;>vgH;hbPMLF(`0%yrnJpq<~Bn zBg^^5yQ&O^z5L4eSI>C2Dxc-Rh4X3egzog;FnOn5_yxaKVfsT+4#v=(A`+^Hjco!H4IS45o_$2Oi`H_g9NL9Ep)o@f>~ctNP*EOCO7qH!HTp0 zV(ab8zdB3DD%{uCSsAu_TG>^z&5T@EXBO15Px!&!q=j|<9Uwxc6ZHIoW)O+Fh{{bJFUu}|p z@_Spz&+aRmJsAS>`{e(N{nfviub`JbA#Uw-KiNg94=Oe|FwB*IXH$RnX1uWBnL`tt z3N;e47?=X)Sf3GPQI6GIDuh)=~`Mb)VJ+2*LjuMLdZrdnXFw1G) zabIf1pvcEARunQ_p(=EKhSADG7xu;g)mhx<^ zQr3d~OSOAu{Mi0$r3|y>6phPjJu?QdhsROAxn_dXtkqlB@cgcqkkPhh z_$jQOAjFUty2~JN?bOXLS2?|8WIVxoLOq6$#m#cham^zulK;=IJ(KodXF^M)>(u0r zoC-1RlJip9Tr5}@Y(KG_yNBUkpvZ-voqh*Bg{P*To5?G);ez&)joH&p@2bqbt(N~_ zp=R(|rT2M>93H=p_tzXT>yy*Em^X)ANr6F7;^9NXJExnfc$v2gO0ngIe2dBz2~|mw zUM^5lBD>9{f|2XK0|O6ZrFrSOlI^da&3^ow@8rG$-Ba?9!xHxKoSUNCep$zJcln#M z2mZKk;5ebahR5ym;${Qk)LTZ%3`$M>ugl-%Olt4j^l_8PMyu(CRSQ1;F6h1K-gWxf ztDfKGpL-%Z|NVe)+?1=bX6bx7mNOKYv^zwRl%f)g#Yt#T><+o)?PC znmMHc@5*!sY)EGjT-i8Lsi850IpIrF1^-@GyPpz_1&L-1K@AD#D;D%mF?%+Hr>ytx z>Er$d?N9E{Kj9~@)OGXH>-!hP41WCIo}H{FaL|A^{6oshmj7zvAGa1Uig$gU8EaC= zV zcZHvreq`dNes9)Zi>RedWwD0$`!-)&Tl#i(*4=~5L5`p7r(}Iw|MZu1%w&P{WyQU- z;?4ck?E>mrJXW7-nqXs~GUZ^Tno>gd>_!)ceVqU1=suYo&(1Vq`?{`~mb2G5rf{!( zWF5b*?8A&4?fMA}M=PGXO#ED8n}1Dbw%xJY?pfP1WVQZgb6l-0S%2)g5>w2tH0^oSfkK5vpLdvf_NUzx zXyot?Td*hCCv9cT=07_F%#>^_IdtS0n7<@Pt$8&uzmxsJ{(CR}TzRI(>5$DNckR>y zt!PP=C+usxRyme4ZO~Nby??;F@g4JyD2|ki%UANx<5paf5_iyIe!fG)rQ27G3R|7R zeBLK_WC)(>etdjq{nfH!mWCU83om_N=d-xWWu}tzWRBcb!QB@7gA-gDuj((J^uzI# zQPbs&L(3M3N{My6=+OSLpsp`Xq4~bILi8$aPll4Nl8Ud57Z+!rO5J-qFYb^T$5sWt zFZxPTC7lkfdm`VV^5<78XNs!zv}(oc{68Jie0I(4NZ8hrST&Pv&BZHkC-v7IIjX|C zqkV;v(-8rd*pFXYhXgVYB%Szg?HD5PzGdxVk>yW`m2cZ~Xqh-~8<5 zJ@_RBQ@MX`+0D$@^Xt#^>6w>Ltg1Cmzc%IchRyMR6Z{%l72iDIEax(KAn-KMMPGqs z=B*3HVLXbO4p!~0B_H<+T-IY=6WgKi=Cy6^y&qGf^UBt1%ALEUHG9X4YvoecHfrzm zeQ8x_dt|}~r(avdB)A+G-BvVPYR?>UA@}JRj!h4N%543;nZ7{2Se|Mr7)3Ka+3hSJvOn<|* z{D9zOmOTs)IX4s(o;tG2oomIL8BT}quCo#hp2KmoXkNgE8|&-e+Q0su?iMol?<)(@ z^($At4E*bS_^w~!+u!?~m;GSf;<6@dra<)a-f50z&Sp$bw?&pV^O-j#D6t>9Aeiyz z?4(Z&<@$UQw#s)ep53}G_i(k|wvV=#kF&QdS>DcD_`L3I_PcsR_XVs18~6U+%3L}3 zt%%qO^MsZLx$vKXHtoKT@;q6kZxyah5A0>@+3jdkqT|%zxwYbnaOj&QY+{`aY(k%` z6_ohRWkVcx*mN|^t9^2>dU~Asq8(XH7L|*5bSB(dcT=&+YG%yFxAz|gHLhj9AnCO6 z@BeQneu*7#mT|dW?aKP@=A(&uZ)(5qa5$v% z)A#NG-BrtDV{|{*%O=}PGaD+!x`_Dwk~_yAa=tQ1x?9isw&|DTiTS-RAJ@kUHLSnh z>~B};d;7WF_L3V1kF8pHd)uyTlYM$uUodFPB{*}|{9MCqkW$S5f#>6z#g2LROphME z%guE{r{;g?I+ZV%Ux=T`{PH7p`tIc-mS39gobh|f?6}QQ?YiKPT@Llveuf>i`*&TJF<^hYeD#}I>Tz2duG4pY-s;?2u!Sd8OIur4_W!cX zO)nf3-{f^xawM*N#?Ta4boY^j*O}+tQ>+-=mg@2)-e?!pX!@;xS$k{X(VKben%vnH zH_M&qU^wxr?yc;C%clJy;q0qTeR2dY-J6)mnl5%duk7fi%g@fQney-1^Q5+&_r0S` z#97{*U=`n)bo6WJ3&~&di$eDtYfsJ!ft=%b%z+K}$nc*#F7@ZU(ol zC#+X8TwXazse74kxyNM37m@raJ`8rZ!xT5Vyu0;VOuua1u3LXyW*Z9dpSX44tJ!a{ z=T~DlrQGy6b!fwv!rA-0pC-*ue>L;rg}F+ztcCThxF0=nSDYXqZs2It@#Bi#nIHR( zvrOnZ!ug9)tuJK7^#ax;Pv7~o^d|q_Es}Ik+=1uNAMMB6T>MYRZ>(wc4gdaScg^zm zB@#2%dZjS`yt&HT|MN@UPnxe&IF~Q~`X=|+Ja2}V&kahR&V2RC^8T#G8I$}i&d0>f z=SiwQbT)ln=`!orYc{XpG{0LD?B@H@^Pgnujb<0i$qZ)_%h_Ih|FEYlJ+tWNn&oqD z20z)e+iqWbk^ij=m#x04ynlD;TLe?d^o8~EeK8-;|2q8BDL3n;aE15&LZ2(a{tNtG z^W_Dsaawjj?Bo7FNA-<;=UpwaRBl*v&8T~(ZsevTwJ*KnPieSs%Zl8RG4b_D|9zXC zI`bLIem{7@SNEY=zGS*e`uk!xhMWeU2TrA>TXTEoX$cnn-M3mUxl(d-?p?;l>2;!4 zlG^szvT!_HxqRNK)9dTLY{-(G^t^|m<_g!+pRIEqPAdLu7jx}o%>NJV_9gxH|8_`g zw_iWW5VO~ZaqVB(A~%M=TOUr=pYbg3|NZiv^)o){KDS$CuxaWUwKBdpkLy=CpL1jU zyY;a{ozTDhq(_=RAAH$u@m8gwaNh@+o9j+;H~J>ry!!Iz`z@0h)V>Mt;QMz=zrn(G zqW@}tYt96#`eoPD=Ipb0f8o;{&xQ{h)*G)+Sa<(-*e?g~di#oZH<&FaGu(Y!I{o!` z+1ZvA*F*WA^f2twGPr-f@Pt5WwUtwD?%Mpa-u)i7^FOgP%-_3O;PsVr7FXXnD?Ygz zyLD|i%Y*VmDOJ-Y_xYs#{HD3aMzm|||A4}zi=Fk;J$I$8wa!q}v1RRW;c_A^?@98Q1Jq|yQh$n;;9ti!@XOR8nrbX5@$@GlCyw9BM z7nwUA7INKww9EJ7uYU=5|Le6*&JCKNky$kgJinv<^1W|4S2u-9Tm5J* z-+z%`@&9f8y2LpQs+VVkJUBjSW@&TugLOWaa<8`V?e2GANUZSxY4iW~^S7~PpBMG` zoKlH3JDnqnUz2}j$?oRA3MdvLsf8K7N zTsbkmd(p)Cf8I?Fllz|(wf)38rJEEsgoMAKq2vs?1%x=f)JNrq}Dvbl%cP zUbw?d`l-<70|7UGdpp#nZ(g%+Fgitv~d{fz=nT85cWAdqy$-GA};nb6c0k zh2i0zH;w-`P8Up_B<^5$_vzHknK>D(E#^C)+}mFIY}w3r`tSBmcV~N8G`V(>*&mOE z-}vo*B%GV*uevLQ@#O^m>-C?`|G#r2cJUE?_9Xea=cO70qXbKiKAoQ3Sg`tK?LFo< zAAa7q|8IY1t@-^&_pXV(zai9;arW{t_l|StK7IPl$9uKvV1L%}jcT2xIh|K*9#(8y zH+z-9*V$Y0FXRdOr@yo-IWD{Hwge0N!jdpOGtQp^4qkD0r+V&o_!T30c*R_ywUG@O zH(q`7UF+l4GJmbZ#qOn6yH|N@j!NN8l;n*~yA_tpP@ULEgk_fAXy*OQy+^Ur#`N$36< z@`{DYqy3LhiQP=4PeG;sj@~jo^ZIvqT;~n)kinYNrEpYtn=?sej@Ii$$Vkzx$|nDG?z0oE^)R?x?gN3 zU&YYq5b?a3Wj*`OV-8>D_(kn#OE0-|FXXYoMDZhs#7YY6D-*+)IAzV-bKWHOM#k5l zm)PR3nOs;r$cK<9?*^>~i{N>~H^;0&q8x6 zzPbH&|8JkSOSsbiRa&gEPQ&Bb`Yd}#tD@y!Y^o&t)M~XV-nrhfSIleJy{E$0m;2$x zpLXYSmMr$0(w)rB+-u8k+j6_P*TMSI)RW&|)UW5OwVP9G{c`g0FRPc8zf#Zp&Ghri zQH}-LPmIs~-+1iRT*hBAc{{()tM1(`IlqcY(N@+?YKNAM%Hqp6u3Dd2`6BU%N<%Z} zyDu)2`aTG(-03xaooz>Phkoqc4DVfKNiWyO?cL>n#IE#nzzn{hJYQ|L{^GZ2|7v;1 zz-y6JPk_sEb%72RCWgQgDfS8Hel#)cY4J!mndrama-jXKJF(Ro*0Fc@ta`C(Zq0ph ztNBHT8+Zc_Gq#WIu{t}u#d-1Tj%NgZ9lqaGs^w^aU*}{Q!(qb zkg%xa;C+U3>+f#8zVq`rYyGcN?_PEkX!yO>tmoeo+q5$uncjJ&e>pqT`1rP#^;eE~ zul@6PrGVO=(_0=tXL%bv=WL0@+_{bU=jYrlmU;WGPjiKOnZMQrb%p=8UaxyAeqwo@ z;MzMIKkR7b7Qf{sv0qAU>!;@Ld*3rooAFR%m#3dbTFCE7pKG%x9d=lhcB7?Y0z=L9 zl<#MBp1-}da!TjwGT)Gk*XREHw%6s|+IIcRx70Zs_$7|bU3bxVX4#FC%a}J7>}402 z!}Zh6?x}mQwqeEmyK)~qc$Mc11?{}Q{IvM<-(h@04evW;<^~Jik2I`pt$B6Hk+mdj z=fU)yFB$tw=2!2tyg%JqgR#c{%fp@PC-_fh=Ul)q=zp=cv*uKPkB*+%Z+iKXWM6U zlGpy1NIqwJJ*L-S$-CnDzwbymXPZblTOG1l^Yc*S#*G^bF1m_;ed_j(`{K=g29kd^ z*RmG<{`=s-tE;Q4`>s!{D=9I{;B3g5nR; zGnw3tmbwf^KT73O>Ln~LsQ#!ndSa=~VDzK9=&$ia#)k)T8s;xN@5wmfpuIwQ?mIVs z3xntf%Rd+UF{FI>{$$>17q%AW&75@+2FqC-*#0-%*}7BO_Thn?=J}3iBpD|hyg#{G zPgqibkB8|;;?X$*43dACi>^P*`_jVP%v8r_{DDcKdB6Ji7&RjW83~mShbJ|PAuD04 zV>8`=ti5JtMN9>gu&M zk-@&FKAvej(oI(4x8AiQYG=kXhki=~f#3!mma3Xi zCLLDcVSA+MaPp=d+q&KFcG(4;Uy|O%{3|GLx%AOh z`cJ-Wny;*^oVf0O_~%1RGhU0YoNoSh!-ZGs8>}A+J~)21G&|viE<@w}eQV!|>-?X2 zTV?|50Sy7Bxlv5n*Vnzhd0_p{XR{`SS($1GKMzQVi(ruaQ~aWD&XU!a_DmLe9bLxt zZ=b1Ab4&X@CXa*mx6>Z;#9hA=B5$GaVSeeg$cKx%^lJZ$8M_ptm9X@68wf_P5S3Es&2n zYx3NNou$IW{^1p-8K0ZI*(R_$9O{udBjeGipU1OV-~^LHxaIGe%*PlTW6yZ7HXS-8 z%~pT!4YNdB_tfJT?D>{FSjW})Z>!bsDVrH){LP+FZNMPo@%%^WA%(N@4e!3K;jZMm zU>ug_R6LPc^9JYg!efhf{Ml)7tgQB&n1l7ZCwmq?WSCugW25@~M$RjrR!7bIk~p95 zOcz7NKkj&m%X3Sw--xhSck#oEXZC-CRokyebl6x<{rU2B{Q4!0pRd<^&Ogl9E`Kd> zzuCI`0)GF?sG!epBex3)Vr}9*#GaNy!9m3BtyCVdcHqTd9xnO zuKSZL&U0!uZ{r277wjt@%l_c#+P!XHmD9<`_dZSI%(P7WB{Sh$`=zbd<8FV6i5Fw2 zTzlvV@8Z|H89cWB4UyE?uzKGkjkZ(1O}!2jT#mtP#7rl@wfZR30OuIb$6FW2TZ=rS&_n4+R^Y0J6j8P%%4l^9-a zu}kou`{>ij;E1{?xrYWbCo2@#`-%Dpv`+s2fM0F(tttAKYm9vL6PDEpFO*P}SGQN& zt?sLTVRpK?(O0vluB-aQ`Yr6~$@5JMM9W`Yj+Rw6(^>xOO8>6SSLSgv z#4*<&Ozv-wWtY8C#v;V=X?1IGw`0?SD79YZRaU+F3CmJ{ORn2?-Alnk;KFnp(~Mfz zsK))Jy+5ZK=Q0|Ie&BvkYWIfy&y%GOPqH+L`~6$e#F$v{)AIR`%gw7)6^iXwMrE&B z{xg`%{#yYDyX>vfP|lXHCWfXSMefF`Yp+6H{JJy8N|!N!wVrF2RyOOmU0=#Fg;+kR z%BTpqY@f=X`)g_xOV)a>x<=ohxwVW^`&*?eU(Gbwbw2L#&fHT~iYzTJ`mTSP@avkF zK!#4FK#0Wj#krOSPuCup+YrCN_u$NBOKpRzW`&7|S=Q7EaZCxF_iE*tbMNCGIyJ03 za5R1XTdClNz(_`)kK6V+L@}B)9Dm6DhiiGI*5lU8_KVu*w@o(svN<+>^<%G9&k~*; zVBz!eWGG?!m*pK=5cc`_yoyCWUWZeYx*cTiX5E@}eUFs_i`bv5^_=Q|zTR&+t-o)_ zl52cEsfw&DUXKi8ShsaO^5)R+O}%W9={0@*uB^j!zU+JZ-@ovELi6^#()vH~9-oh|!jb~k zA1b~K>z1DUqVAvgQ)_*NSF_F4K+8{euW~eo)t+~9@Ht&)%~ztzuX#2`S${gBrXRPhTj0X^;wbJ7IxI@fo32k{mIZlObL++*O8gD+ zA6_K${fTXt$$256&YMyA$(_$;1?L0Ry=_-F&d>fNq4#-F!G~R(YmYG=eeAT{H@3w& zsQmYOIgZ=%5zkY~X7nrU5W3%T=Kt4^_dk`0GZo4({!gf0_H>rF+4-Qy( zsi*X+FL|(j*56GGGG79{m!;VsVA;Y{FMEJd({G>qs(PgrtRLK1*1V|xm|+;QI_&ZD z8KDewr{~-g%G+Zb#UL{2+4S=jK@7KEFL@{Q(5>dn!b3?CrVXDL_x*md)TyDQ`*;7Q zQ{7+Zn$@fDY~cEKd%5R~sv3P%zWt; z-5(2o*6x$vsw(QnJE0-&KuLkx0hSvK!BH{}W;=OXIoJMCbDVJDH%>E?6(Gb7y zVkx6yW5U;veIi_&G_Ew>5O3V~DttLh$YG^~?&7kU%%w6C`*&v--Oj9^`E%XRm9rUK zKbOp(ub#GZi}itfb$@x+b+XoFrhQ`2Ol6H?xTC_NRr|H*n%~X1rM{x#w*Ar8J7m*1 zWp)<^Z0`s3oA{7YZLmYdx6O=eDzIUr~Kq~k)x85YTshezj{Z4J2b$8d}J zzDUuf`A=>9BDsU*qZYmXy4EjCvZDE;e-`HimBt0?qEAZ{Hu7EiWjV+4LKs7b?bXWt zm%Qgo+gh3IpZzE8UG_e`4^}%E8#9*%39nxCbBU+I38#SANADQQ|8RcD)10BY;9FPI z(fF&A`vpF1I~yLIetQ-e=;<_DSIVMF5bTJU#x$$ zWQ)U@@(HVTzOGC*iIGqc*r2g!>VwNIJMtX<3Vm={q+6aatS)CX_`Q`~e%n;;`j5xd&u%qre9`fnDSpx2smGI~A3WbE^DeGh zZU5=KAFSJc-L*)#UvP5!|L`5>|0JJr*?+yp=WF?&U;m%Ie7^T(Nd2ycYwNk>S(=vj z&J0+Pf6}UvTUpp^Iuh?;SKF`0hJ2UTBZe>!q z`tRkT`3Khj+~1(UuuRQjmi&j4XUfc&C3bfP>(<}rKHr+~U|;q2)Q3yc+U{>J>HK}f z^SC0*nq|Mm|9{w}WIO9m!(1Cn+oCD&Uq&!@3Is$l+RvTzA!NbFX!%e<^W&#GzV7EL z`^55K;}+%ArJamZ*FQ5!Vryauy1iIo1(#eTGY3=SZa)Ey^S5`t?%VL}>UzHA_e+Ae z-jtbtTxNwR!y|XDx}_(%G+G_b2s}7ou`Y{q#|DEB@mq_RXIFLI-TP=m!TUq457(v7 zoT>|pX)507?0yeSTkl&DTRPdp_$Q7;+>I=#pj@j(-W1Jt7DXsHz z;fu8@huoYRx}vNV?%XKPujc>3_g$4^l~aR-6GLNTfaTMVN$jd$H=mYiU>0U^SoL?c z&Z?&PS@H`QjpV*x&8k!0@}qY>|C!hN#uxIp-~Rn=qT7zs-}rKjFPxUG`Ec;zMR$4L z9~NtG-A`T+zrSXC!HI?Jw?9|U)}MXuZ!2eG{+_>kK0K}e(Y~mP#a^sUN7(4a;_v;Y zTx+>qvKPb%Y$@8rruX;Z*N4{Ms;|4w=k0!En0Dy~H?Pa$zyqSaX8&uQZ4NK6+`9P& z?@LCFYi!cp8#z)6Lt6PmVmTgs{&Fzpb6Sf3CwmUQSO1SBMRN3fR&CE>IgsMxX=;Cf zDdEqOk58AEEcsfW_+bBWlYhF>^EpnJ-?x3Ux&Le~?*@0d$|d6V-|rM(&Px5U`~Kf` z?d5MJc>86(U)pft*^~A+d&_rx*yMe9y8X|S1s|vH6RCTC_q|>myBmXwlSA#42||I9 zj9rf}Pv5@I!br#Rr)lED-0~@rdJI_&_Ob`2A4yhNs+!o~>TsK*sigLRF7u_cTnu-F zSVCtV5#+ltL1Cr#qnQOjG*E`30;g8O{g&Xs? zrN1^`Uu_^$@t`sBXqV`>bEh*r9P3*$SGN0{K2^?}TVnTVVt<9z7C|=e>3Y1~aV04? zejW?{J4OD$`9}HO8$C`|b38jWec~Fs2ge=#nHuZ7IXp5RZdR~NtNp_(9QOa~lj~w> z`@9Q8)e@_wW0qbQeul*zm28!Defijp5J3$tO1J?)z}!@L~P;T5|Iz{%wn# zWxc$~;WhJ01&`&dD@7M*I$ryC^5|TZieE36U!NASIn6is*9Mhsci0y&o_aFff7iY3 z;y-47e{H${y77XC27ftYxBdR~VRO4Y-}>6O*>~@NX7Jt|5MQzPgG&9iwb9R2L!LLw z|4ERzYbsV&eck$$e@AYrR-)7L#A&TDza~w}m)XSgJ(7Qed{~1_zqTOL^tF+%J@m7Ca>JYBu-ly|_BpZhI>el*1Ge>Ugijg+5{RiCG=2xD0CY`@&! zrH3bf3zt&3q%>=}B**$&8J9+Ip_!Z;QVgK41Q5hS3tI2Z_QOHE*AO zdLJh_Z{xNvKMlm0t}!?*n8S8q!Bq|1;;E|L?is>X&7e`<4mU(U5S!1qGF=EK3Fi4!dRDt*}VwqLK@|MkYNf`bp;r>1N_;(9doq7dVsH!Cjx ziRW&LVCt4^=44#Pp7Fo@MnA8|t>yqB*$E6$f7I1{o?dvzAR~Xkn`6TKwotp@2e;Nu z^mrm#-A%<%fQ#~r0NVhtCs&N}dDs(Y2SjO4fT%l_7GPqezg$P><} zyI^_jT5s>q&#Nom-rCwI?-$R1ZTVqUo)3Zof7(7OD=%fpC^z1+iOFE*>7DgVbr~C@ z-``80uf4T?>OKa2g~eAn52v(#?3{cqu2JL<2b<+5^Y;?>1D2H3*z$hJWcc#v9&1Lp zF2ff4-CUJxEc|SjnngUcQe=4XH8_9u(##D;*|CP{)Dosn&){J^OLo8 z#i=}h-=(kmYxtbe(!QmEg|T);o9OlQ!@-IMJYfe|7$?MWWd8r+$?#x0D?`R5^Oq}5 zXYYRVOL}u`6@z?3SnS+q{--%Ucs287UaiWg&lRpaEZtSi65?K0nep=A(Yynfm^zr+ ziXs>|bgwbgoj%9-f*VV&Bq%>zI^dpX20)1-L=T{sSgiIAN*1s!o^^s@F41t zjP1FnbNA#vjQ!A&JI8a5PQ%;p|4+T{xhW%Kp4PMb$*$Lj)c>8`&$-wwd2u9n(V5Fn zg9Nm7zrJp9jlGpRJ@(nv1%GEvjt};;_4tz6@io!WCLyG|adE$GRFD2X!5wd>f1kda zF_QU#a8mirnJo8z9J~JZ>#mP>%m1E!xbr;Y0sRBs0uMeXpX2}V^wNe)ZAbN48ywcZ z-O}~m>WM&5OpSk=0y?*Fj|Nr~LWc~Wqw|}f} zUrrSJTw?o8*(SF9<gS7LjX?tE| z{4Y3>bo;;l_pPkmhg-$#wk%or7>{U4o;K5LBcFKiy~7Lex2LCU)Jtht3BWT($~5VH?F;XNOOJ7QvD~1 zhZY~bc9zs1#=O%KjCyf`n{)lI;l_oHFdt~+6y8SWfC>@=mX{(YeP z@{0?({dYWbHb3->(ev}^=?W9{d+p_09M)=m^EGKWQa9tA(frQoVhj>SjT^3*XedaT za!T>IJfB~d_2ZWK{ug2g)a{BKZ)CsU8?)(D%Y3~bJC{74TRx9l@Ie2!`*+WYS)8l8 zx3uEy^k}QRGc41a?f-^7Y;t;cG5=TpQ=@Ig?bFkFAAIAlUonHJ!t0+gkIaQU`(u;r z1Qq%e4!oIuY`TBk)!34YuBn$w&F;>9y-tLoy6&0r(PDGv%ALJoVGVOHG5<(q6meqM zA<8GPbMxd%&Ce&l?>WAB|BsvJ4>SAQzKQyN!I?Wa=GN{N7jDL1J^1|i>H{kkEZ^VR z-nul6SAzvIdL!|}KN{NJZ|{hzA- zvrL9u{oeJ@|6KZ$aV^5H7}#@ zYdw3sY~gvUpIKfyo?SB-S#?$;Q-DfM)0;?NYd*-km;fZAE4wp-ORhIZ;ukpP%mmAEbH0mo~ z=RQ1oeBX`xw{|~h;`Tb=EpVcJN{i#G$?LEFYb~22!PId7@Av!i({v(*>fZnPd|0!r zK*O)Q-su17_hQ=&{=2SDG-tf^|GaNO?W5Q6r*GZgX}PC<$2*G_hW%Hb_#d94*!N7{ z?d|y=vsezyUAD1s#-%*gBNe;Y9{h~rNQs)TW9|N^^jF&q*3V?yp!J_^@y9>MdK2ZN zxgRhD?7eh4dru69*{3a^4Zlb3VE(f*I%h$A;(PWvJD$g-7Tua%^iE!$Ip~BqgYf71 z?^g5O`hP!qzNmiZvjYKz3R{^>3=YJy*3DYJ;ZNele?7}3Lkn9t8p0eLev1b;bS_Qd zbZ8U(u6n`pje$7RL)YUi(Rur3uGvuZ)N8h;$TIW9W$e~(zbH8LS@t=s_;tnkwS4WD zi;agJ!fvhGt3UU%nYhst(PMQS8UHtG=u|W6ebc*aew0Qi;o@>Si3^XP%|gaJ}~1=558-!hXFy?v$`oy2of2^$3PN!RMQ9nHjH_{lswpkq@(skJ!4>P6dbCeKIv2>-XtzJrw=+NZg%5HI6>x z$$xKz&lUN1UAVu!G;Q8z54SYQ?yAt`th>~6!XI|W|9Mof#nv~X;P9=2J2TU(0z2jB ze~-Su<mMi&u|C)M%&cBBn7^bb!F=G<^zq)*n@tn%rxh$J!tIJFfhzQ-t zVN&x{+b-uH3uA-mhd1@V{QGJf`b9TfG5a7;CeF$T`l5-x9hFeT9Y?2-F9 zP7cqGb+YXd=C@M0Q~BWFL-F(W@_bw8wuRTemx@=uv8!}-_|q5pVn4s#EuX*P_ot^1 zKkRlOaJDxt~=B|MDOAJBhvAp{B!)@?I~OAofxZkcW^Yb1 zUFMXjmHHZB_`LjJazc3Y(wq62Uk=A!`L{7jBJ)DG)47jDm-p8`VSbqJB*yT_|J!qR z_9athyUkw5YLY5o7+}h0aiE+f=^3*@`~~Ctrnw?4Pdu5KeZrm!GVNHJ_GJ7X>-Rl!@mF3`bIPB=KGRM5`T5@;e_D9>DBnF>&(s-R^QFt^ z+tJ&3x`!<%SQ^Z?2*_p(k$iBO;Xw9+PvI?ZXV-Bs&S`0=x&Eg?K7Cr_`a|mdkETgK zczWScbojcElA!&bucI^9ep@bDdtLs)_IT~L{*}uZc&n8QI&~TTty>%aXMg*jT#oHe z)fqJPp9k;QWgC(F{E5O|;{{t1KXG4;G*;Tiw)p1OU+b0f;*OUxEZw=SUyzfjUy7r& zuVD?tH6aGQYYg1w-e=iw{8{qw^`F$RX`k|3T^f$7&EEcNQo5d~%dO|@KmGW3Vv^+1 z8+xTf+&i;)&zTZmUYoVg`e*-O%c;5dZt}_Xmi3dT3Vvts5IFhWz2T%4!*hlYLKjr+ z|4iI}DCTlbxaaox($MgyuepjVPM)rRd;Qg>qNsk$3w&QneHA$hs**y()AW{Y6=jHE zv=RKU)O@$)T`7b8B1{Z-!oEC>;8>EQ$+F1o+aHN*Hn9qNubs557-K(*e95$Byq~F- zJN2zQ6Gx*VA5)^dg9wv%UzFgDohN>>`eZZ3bH6%tx9saxy`Ehwj4}iJ^u1X*lWTuQ z-!sbG8?(TgZ^?t}8y^^b4)*nzDr}q|w!+%SX~9~CjMHJ9EDh2J)gLhKxZ)Wc{&$NH zSI(u&6#Nv3H*3B&oi zh6uk|(H~9vw`AQh-LrIc+|E<^-K;N_?O(0R{h1oYV*fEo{K2{dnGS2reV#GwGuhXC zUyI=utC?ONhXenEkA;&P<5M-hPr2H7PVIA|>cdr&6(%sOdiMOs6$=GlJzsv&NQO_Y zGdFD#n_|ZE@5t`8X(9V0R+K#Z_l(7crE&KP!KJmq3}URu80Tb_JYBl4!EaUzV_l@b zl>NEyf(Aud@rOJLpDzCUm(yX+E}M_^e=RSGuJ|eYzHQ%^#YUkXI<6WWBLBr#LHSphj)=}T`G2$9<-%v9&iTuxzIELFDCnVcgg#^7 znehK-zsEMH@z`znTRZjEHN&mUB zZGK))XF}iIX+FH06gtkly5v0h^J=E}1?skEmCxL6dTGwME2k)-+uz0CH~glAi_tU( zOWqZl)72PlGUFM8_D#Rcd;grc!>YPl0X)vL??=R(QC{=ytB`GxXV0wd(~n*)7ZRyUsTDjn|BbusDFu<}p1@pvlMnhE?t6$ZnRF_g zaANTDc^C9nf5GZ$kC^s8dcyt3O5%yT{jZ6uT0>WdO?|ji>V*e`!HzF$802&2a4mUe z_0spi=cc3b4JVV$8ADT_PSz8sv{)I{mIY$2keCo`tN24SjWR0Hs_DXmv&jnLv8Hce@^~eC1YpL*(11Ef1yC;4uy#C z3+%I84Lk)>6b&RNzy8c<=5T!J0sqG@0}~?{gqY$oJ^tO8du{Gvkpk@lf0ik4=P|MQ zEdJw?En~~goWsd3Pp>ylpQj<)82CNdF17H;Le2S?YdM%}Sp2RkvhdjEF@8v0{C@wR zrw==?@6~(r{iT0(;IZR}=9%Pgt(&~;Ucv&_6)Tl_-EaTVsXt=I!3Ge@PhjFDY z`OA4b^4YtK$4~G3_O;+sx}EU8@=KnHr`x{%TNJeN<=!cO89OW*V;|@Qb??7wvfB95 z5w+}WlODMp`!7pW-m#mKWG?o_?fZ8A6~{JkbDVNZe8{r4Cz|!bRg=a~&jgtMRiF6f zZCM=2VIjTiSFkA4CJvUOpGr}^+O>MWKc1Uc!*Tv-cuQo@rIiP({$2}zwNvn|`U2)4 zOTW8S4fKhW~MHT$g9KVGNHkCvVnIrM0ee&fV#%2sxF8FW15xBNK%ul|n2ER$#P zCtsg?wrv)}jf}Ky%O{H;d}{Z_EJ7~fh@e{hzE;@}4H9ShZiwr0DWA7_{*tdk+jv*M zY+~A$6X7>r28t;%_+|(k6Fi=~;akBG`OWUDHooUz;%r>x@b9)J`zkSpuM9g)_CH!V z|Jg*l>#=)w?~-nf|m;)E?-`W(G8*=*B~p8BwRby#ccZ1eWkDeN(2 z5uP_bIWd}POUvDTaC!PBd#0s7^KLEQ$9Vlo#dZIiyGU+@)UcwngR`~HBrz#}R4BYT<3HvejOUEIdMXY%}-iN~Km z50kU!wVwEefAm^Vx6QA< zb|CFQddwe&xHZfU?q;^Z8JUbTcYO?Jy8UP|f38NI^cw#^9kctD-<&(OwA6;*oAFkf z<_=TG+kvllJ1ny2P^+7^{pG`^XZv!_oyuck-}17(=S!!<)&#DyPaVq__@C#KX}jAX z%gJEqx%*iR$BnZQbyc(9zb|Z-3h;UmsVdIIU^?qPQ#DuKq1$y|8~$FKX%iu^ZQag$ zXJRiO`lfuwNzTsxl&=6EhXCi48-bjPU!%Jl@2%4;G5@bSS$A8{%QvFhhj0FW`~DcC zn=1?Vb2+=TYiIiAE=*JxH7&apa_r3S4JY{Yx1L{M{b1?SmC1e#O9LhtEC|sO@Zs2@(81lgbb*7!jq{HKC31{Di#l$2R{LK6)~WjFA_dd` z!41M z-}_(igY>$uYy0jVU|MW;OXG6M@ZNVk&)3I3{u1+8xJWVKzPJm+jfu~aFT`(CF)_>6-DWQ> zJ16_oiT*amyVc^4AD&$9lx%OEGo?}V?l-G1cPH~jKP>!zxZ;iZrbitgO`NXTFBA3Q zbo+kSx<|sdCX&T2bVJhOZ>7rq)pyQC?fLcltVveVhmCo>OP9THP+dC9{OX&zB|*35 ztJ~UK7Jm?G&bs%~ljTebZ<{~8{^NK0>eaR0(R-^(O?UDcT{Y5u%$gOQqW*pL^n$bN zrLC_$tYx^rG2Q&#ip;9Ub9Q18Op_L={!q?1CKvNwg-Wb-vHxQHw69d0<;eT<=XoH1UeoC(;Tv_oEseL_&ai{=vG0sozZrVv zmsv+`zp{s|%*1m0YUa7sHy(NW*_+1vJg`1SIzDw@``PC=-f1tYul(}U#PY%Oy>$+I zuN>l#Ww-jfEqwCjmmS~57mCc?u00|0{;_NM9O8fO{^w}F!R{@w-TJ`R!z>3jpKtxJ zg|T|EF5kNCXDy`VbQrRjGR`#gN*lkmVSCXVcHxn%jpCY;Q-Xbaiata~JdiieZYcO! zbXBn3GWS1otW51@DG?B;~Y&iYDQ`zjxuEI42HyDd3~@qO$!Kl>*3_RQEQMKN`q=jlu;e?MIg|3`Y2ppkT>ShpgHEqUG?RCCw;s!j{)_qM zqBFXK85q_qev}w4yTEh)nYB?{vo!G|G8K!;p)xa z?FY`WevvlFQj5>nT*7zLL0Opn&zeo#AMEPQ-}a}8Kd8@aIDR+tLG!$`r!KE7`f%Ap z=kE`3vudm8gq?-=|84C5Q^oQ?5w1d*R0Ca*1y=nIo_K=;r<6Aba8c zrul3;PQU88acptxvEy^qSe{(A>z?rC`gNljTrK*o3TGA+{EN{FyUI$uSgM%V-{)MwaUvbhS$H% zerUY^_inztOHynNAP`O<`$}Xp`ABW|q*{lvZ8Th!N;jWi}Mt#Ig(~o|eCffZzUjL>nTazU# z&tm33gJY}>x*HyDIk4=f9WTSb)8%>JbGMb>{uo^@y~2|7`7hnuhm3D;Yl~eL>i)L; zgJOG2{NGpM4+TE|G&rHO`{UQg%8Knb*%m!jQ)qZyID2~wH}8`8-;cx(A3qbHbXm0i zu7t1^moDSHx}|z=_50FF$ z-~WFBcdZ=jEa%tJXSV(e{C0BF-}nken}07BKMee>xZ=l?n+MtD-`qE{xw0?gNW_+x zEcfjzvfeB0$#~fGVQzAqNRuwtuRs5%s$10NpT70ky+1;VgYnmauLi$XDtPEN99#VQ zZq&!E4AIIGzu(C7Eftut>Sw$`dD_2kQ4L>exf*`1*JotZ$ozGs{F>{+2MJy*EVHgU zif*-A;B~P6_N1c^tBjw2H{{)S#N=@jGhaLpn?ViNo^u~}eqd#rl-_S?mb01JL(Jy0 z&yLs2X7AB>;LcI=>h62JRZD1?O$OKP>*bk@K8c;oV)yi?Doh-wsZIX4BOOx?kwwv@3UT-KA2x7{9yCRjlb&WG_F|n_u>yd z7L)Jp!ZW?MYTnv^@{9T8`E2Wq-u6G+pZjr9!Opuc+9fQ$-ALv?d^bb*MgNB7-269_ z7S?>KOj&I4c4O4;?{?MgwZ5C{a*m$*(A=$G#(iM9F27Acowh=){Xs^*dSS%}f7Q;m zFwE|`u;$;33l3#dWku`e+uqyrqv^hmnYHA{m zU1I)q_>K38yM3AMoDyfgxT@L2Wy-r+-qUH~mrDtrvG?1DZ8f*o=YDx;_+W)@l@V(K zZ^PC9MZpuM=G^K|c+FY2Y|&KbfP=GF+y5(EzFafJaZaN6^}vsBzE5M`yNTgeLp@X5 zZpni!rVRU@oaR;LResQ|;ok6*X@Tm76U%t*jsEV{TKy-DkztiK@1Ok)f0q5!H~#Q` z>-&9t|BBDsUiV~rcSTb#zOw6cM4RQ;^L5`ge`x;ujX(e2mE|ESdo~oMe!R=Tyz!ji z6om<)57f4OJ-wEpdd+jE?xPOEVQ)AaW~a{%__06Nu;9p}obqD_ZXPeX@rY#s!~ekZ zcGBOB84GUbZlC&K{;L@?q-=gZnf!3s{Qr04tZqo1xP328H)64lozj*!&)Tb<=&RlX-jv3*sN7zu5Zd{?`4eOkb{i zQGfT~d0N$-d7bKfm**eP()p7)UG^r!t8GWQW&fz}c_jK!;c}k*&lB!3tGTam&Yb30 zt2D<-XW88Pe?K4ow*Q;CT@1E`&V*&%l*3Ft?`@lneNmbmwmYY`s@!& z9F6~byZ^6{<>>)x;R1e$p0Vz_leeRxcg1vgdzu@ zsrO5T>gP=Dsu!4kxHkSU&l7T*7V~HOeVxYpA!_by)0o#DIKQQ7Gxr()hgM4qr_5Nm z&Hlf7g2Ds#7qUOZ$}Su!>9Pp;aih(WQKNPlUt->#`ERzFyh*(;n3B3*T7AQMealj{l+;x|JIY-iQz>{*c9w!Hy8<}RoQs#ZCj>vEJCK_53fhRXuVtR zzuKN$wp({~1m*>0EY#P$WOn1^j2o->P3JrWy zt)2fe^7Wp~eNhX{U^!Eliqipt@m1(^!V=CIN>zKNv!r;>enCNQt|Q8hLbE({&q0} zmql3^ZplBKlJ(!}fO+}eidh1zjA0Dt#I099EviYdxS;vt@lV!utC!vSsm9oFEc@2; ze%6HZTmHKBBk<#ngtez$$^FZZ=2y_N4yE$*6aD)#I8-Dy7;$*1MY2C#tF81!d4 z&v0-4al})dhxe(c1j8Y5*|dzMenZ%OI% zorUY0<=y+XJzrj!%=y5h`_N5!RLjPnu{`_VRrY~5M^Cm_wO+2d&gc4N46QDjzc%(y^>5^o%`A8&aO}A{`wo_Z zOH03Mb}REQx60Fs{$qK&p?G=YLyO%n7lw7QGXxdx6Weg%++A-omR@_lnEN4CYxiEb zb>lS4tZm;`CDBJ{$BQP5?y0_g z=;*q?op&>z?LQEot|e}&_RsgAzg}UZ?Aw0f*h3jfpXxv9n_K;`oo~NG>VvrC*ZR}0 zXLjW+cOWF57rhM`O;h=(-s#g&&Qz6>KGraKGliwg1(tORG|gYK~bN zL_bJh;LCL2Y<=FEip5LB8V=YW%iMmox;uCOH;xI%>nz0n7qHJ_y>Kc-E&hPooLyN~ z3Cg}<4WBOl%UOAJ?uSjnr}A!cWX+w&^x}(>zQ}fFbBp-}LdO>$e|mcQ`4clDem`(k z+R5oYb@D+z$1>Ke+Xk71T?fh@Y^=~@I9Zg@`(^o;H|P1-(}e%@?C@mBFh}pYrFmU%-y%Sc023(It%}On!Z0IIMH5s zL+QFZqAPsln|lv!WBwhOVz_r|K*-iN=WW>2r2q8n$mBf`$?)K@?-MZx9`k61JASU9R3u2w?u35-ua3`rl{7w*rek{CzpOs z&zx<1ucmENw(k$4VlKur^_lzU5s;OaVyCr_}3X{fi#%VXd$Tb%q5<9o$)Vfoh z|971IU%5(=U1RlSp{Kq_{g1aSxM}XUbivluzWZYoj%@t>n_=U}D@+%*vn;=~J|;cQ z!r=0Q^blbdhh6*&WVSVWi#6elP)OZQLZd_Obz z$Kt8=_4DnnJ!gBa$#k98W|y$J=+X!Mk-|1tXHH1uOrKL0Wx4j{_Zc??wv_z8 zdwAcm@Ov9_e*N-iv98te=U7(~(cZi4HB{i z{U^e3yXD@G*^Sf859;cq*}nWUpY_0@rj57UR#!BbElk_-{2}i?19Rczr0-9dx8Dga zS>*TIn`6fN=gc9yqURY(TsHop%_FtoMNXrHEE6c8CGDL=QCmad8RJr)w z{G8{Pt;5!G?e=-R?}*E@)s=fBSYK-~SbScKbmm$Y-wl_4>{0eaCP9 zWNL^v|5bF(h~><+=|P{}Kdg>>8Ej}3uc*ILW9x_Yn~Zyt7nHjzx4$oC%TwwW?W!p@H1g;0? z1j5>M8%r7bp0ictTR%E+VS{DS;d@z+m&|Jo%U?WKi)Dq}w#oSn`nRGT+T8*9P z+_G2f{)K;UMDC=me?Cv;Y+h;%heW}jfF6%MB1~f6WgA`!rg1PF5HZ!Ymh^noW508v zMx@-GjfQtptiSxSREwLl>v`Yq!*<%?yMCTGIUxIYvHu&UDFOlPtLsD_czv4~a%sx+ zzc(L(_Fe{>b2jY0bw}YSo5HFYjc39haBu|Oa6KLtWp`y^aJl7T{_=%$i#~rb_HU2Q z-)kCEaFA8?fhxz7;IKmqUr%1&T=(n`2SZ&||AVXR>q>u|4)$NVOa9`~JNILm;@Hb4 zzN){xox#&X++cE&ucNT~xi!((bH8k7*naz<>|Y7t;(9;vU4Kr;mnpIo$nN>Vrl|Vh z_7AVi_Oh$1)^17BKXCiap2Kg_<}>d(ZO`$bUHIu<)onKE>`kwH9A-{_@=`(I&{Ea| zypnUd8STy`_O1W?@8(wf0__Le_y61aq3!?Uy${o@9Uf0zUz57y(<$xRr+-!~?$Zjt zpxhbdFC}kZ%E4eJReQ+qd}aUH=@Z@0{8eQ*CRA)+J7?w2{qq=p{A?|(-dMlqNQ;8> ztasa5&+Y%=QrL4XxonTw+V@+`8Tz;9GwH?eFxm6&;n#-@*2NRHGp*nCN-Ms5#<>|A zvMLrGSiC>{|2OGF=J)sA(m%J1{hH|Ev_Fp+oems&YW9HR+p^??lbRiGvh|pjyp!AA zUjOgeeX%c}?n^#(sA^!Jy(h?gu6yn3@b!M4g7X?)W;L4ZGwAh^I>xe9dS#5jk)#fD zc`=6gmpdOVWdG|dd*Kk*jt@@O3`b7c<~Q$qDpox&FYoE8snd=;dN^bMlf&A3W!f6s z*f}&`h%T2~@SIi2r{3)88iNnM4Ew+OFRRb|rhbUQYR#(0HUI7XIXaBDy?F3I>6qAE z4fhGj7iH?5c1+&%ZB6aY+{?BfSNbN(-O{)Asos_#9P zfA`>mU!2F!39^-?XC|pWl&CHZ&*p7tyBwQ%uKCWAXG>lN$3L_C$s`u+zrT5N(EZ-$dmm0TZmYJ(;nJ@I5e!@9f|n&1N^wklp}}t7XZ!8OhBt5X z`R~`i{~gm3yeRXxe$@QQjc4+2{Y}rEmd_X^as3O6gS_BIGry?HDbJtV8y{wD+#i~~ znYZp&=p92({+UbyYyFsGIBpb1$%ys|6lgaHH!@7NW&5)J?ycV5pZ%9b8a9+@_TJr5 zS-j(z-MqrzclQ@;Fn;dJ!J#t6UzXwE#v8}0f9Oou`+w_t-u-#YpFNnCb*{gl>%gRE z>DS}GMl=4KnjjqUt7+nVj+_z!29C|z;<_B=b3X0*@KZldX4}QK+BHi)uBnxJqgd_y zsbzZA>^xltx8n5M2N&J`_u%{CZEJ5IntkufvV!Mx%h`^#SoS-tke+_br8ex(_V>3W zzwQ0u{V+b)T={_hLH@%z_gxF8>LjHz_1S!u=?v>QQy6ag|K!8!)*Y^DCicnJMyeII zhW{4!-~2j_dCv0-UXNEVjceS0Y|-miO-1WXckY_)!uqE`pgV)>K{}Jv43=MQXFD0$ z)juRL>X`bT;AigumA)+kSfqNEpWdy#6O%?10&`>(ibGGj`;=F)+xQ zgU$kAV*W3>yR7AQd~MK=<;CatZs)`v^v#M+Z&>{Aq@Lf?hsU+{eEryPn4dfR*1<*Q z@r9`tUk=N2W!Kj@SG?JH{0@`A29tSL%!?W``48Ox{HMIFdfiXQA1fQ@|1*yjcrE?6 zSkXbXxbuzxsR{$F?9&i%9hUt>$So0Tblc~&--h(e)-1Vm49^Z z*d&D=Nc`rJ*UV`u%rfJ}o<*l8o#X%aw)*h0%VDkN_v^eZKCY|Z=-<3opswz*Z{l@7 z>!>>!#-$IP6{_Fv_KzrhCYgAD`+nm)8BO_fuf}HlZPDkjHUHiDAZOvlvvs!)-<)x( zzbRsV_T0TJPnx>VWH1`^8K1K_+#Sx^$P%i%cFqk^cD2jD1YS>l_I_1zF4y&Yu0G5R zv)*%UnJpCFaG%L=U1r09r>#m4Vj^yYBwh)-WO&;Aw$iMy=Sw$Ue6dAwd0&RL{>!U- z|1#C?Jk2j~!++WSjGfQi8D<3k|L`|0K43}q*ZmKdl_v@8Mt+FV+)eM7Sl&3> zx22U~cG|-=vUYrr{&w^(nYG`F^+R~$T0XG@H@E%zzmortwfbb%hRum#|GqH)SslK9 zUEk8x(Hk7fTUpFKe}3}VbFtQ4VL`#ggdYj|4${X>7!s1M={+}*=jPtQ!MsK7SL9w- zi4WE%PZh1=w_h5$DZ7S~|JCBJH=nA1VE%RKN&kc8a_0`_zrFqaXw2_q#tR0^?4#?} zZO~`Tt^c_3q1ET+i<1x@8S~e z58Zy>exGlwYuGQocbzDMK-#%oq4GC3%)T$qSSi%d?bMKv`K$WKiJQICn=UeP&Cr!C zzMJpEy*X4|VY6FQ~k#CR=@pM{};(F*s>!x z;@7sBCzHQfZ2I^_cwyq~>4&)4{^-umEq1hFW(Z(f^F!v|;X*Bjx$4(#pQ!y&V>Wpp zc7V0wXGYD;-~M(f!4j`;tKHU&jF4fgv*uWmIL$qIb}h%%GRtXAjc!86XV?1{*MI7n z#>ezf=RmQ~?{xEOnFLww(q^-#T5le1X&1Zq*?4}YO}0Ge(=;azhD$}f3RgWg&O4LS zKkI?VL63;2sP2*@r!yJFnl4T+RnYA>IPmkz!Be|GY}k=ex$LjwjSFrsZ(nilt9!WR zW&4I_|L5h^-}qvjHedJmHru9RhuJspZg6$8o_cx7rAbM(2j@kx@bTN;kYl~&wWodw zb7RxCZTqHPX6$gg{)NN8v(&DkmF>&6eAB24TT7Ym?UFG~Ot{Y{vvIw~ZH+U3^7qYL zvDld5>zn)H|JQ8U$2ntbz3k<5HQo=K^%UOPXFO=niOk-@2UeOx=V2@-wm@ z=kR1a-M>w?>-O6f`uc+2Q%2F1UGUBonP_q;2XvXHJ%dle_E=ovpi&Bzj@y) z_k_xM7Z1dro6K=3Ii}Q={XwOKLX>2~`SZ`e>)dgD{<&^_PQ1+~SL;5*{aGdHJFf5B zvHMx=`_Dmp{ygScXzP%>E>ZpEt__=2S`z-tI30g+`#;+uhuZDsd{WUlikDpuDAdwA`)wfP?)0x40T?>;8Y2{?{a6KIQJ8jCx1y{4s8Q0!z^`|$vne$ewHgq5E-~E@R=HAcesj4z! z4EEoC*FVpxewH7#?c~h}_vy3Q+WP+1oVR^kaYc?fuVRCS)_jRS509_fTbH)+$MlZd zKUcBy&NI7_e!S-GLAlL@bo-z{B~nsqFS^LqE&G)X^r^d(Bq&hK$h{8RCrkL$0NiwTP^)9LR0HuJ+o-ECqHbLMX~O`E;+ z*t~6~ocBc|Vm4|0Si9tEt(MLfO_2xd_vM=1tKcg=+*tDK%g*z)=gQZX1@FIqJ@Mew%eV^yxf2B<#*rZYVCK|H`PlVzdd!!j*p+`%YW8?f1~%f?d#h$ zx^I5J)s16{HBVz%VyxG;I*h4wN|@1%O-$ZWeXOU-G!_?4Q@@bEyFNBhXlBBJpMZY}uHCp0)2kQdH{qHu<|7zN3 zoimR+p)T*fAj6-WUz&3nPM&>zjv;ORJF6o){BPGAvu+farOO`b`9R_&=a*H%StlZv zvix6v&GOc9vm2jF59EK{y7HwL^Z%vpGGgzdcd6)X7p^OPZ}Tv{E&Q6Q&aUb3?HeSLz=g0N{N<#$e;XjGr4(HPLM zi$O-r$xzo|!)%2QyYIgi`N=U;EsCQxDK(%X9r3w3{n{vxS6UR z5c+YU*PgF_)3f$@TYs#W%625F@oX!@29p2-^XI-chkkIdv48!0(Q3o3rDfsDhG#FY zy*Fub_^xB=f#>Hk-rBm<^};WQ?^?GXou2c5lErg*>#tiD~GwuX^;8aJa) z-rk7hr>8^9xlel)Y?w8(uQ*%rqwU6D>Wozf`xiC5s^Zz8zAoqbrJMKPSO3wiIlTM+ z+=KH!XtFOq*Vr1o-YV|%?EAmM9v_*$zb5BR@A9_IZ=TG&|L1gm%l6wgzviwEYn7GR zmH2~Y>f(z&@{fO4HB3uk-k4p$oxk;X0&jJx#KQwMaeZ41KWSu}Y;$4{$XLfOyO_O3 zO6HQ_{y>f&g$@7B-?${rd7r+5fmiWEb$+EcM|ixfo;$}3Y2(kb%eTK?GV%1|ZA!e6 z9KQRmzxmLA@#C(05l5eFud{rS9REP_P?vCL;TP-OXBuA?EKp}^;4_f@v1zYEi8ITw zRJMJ)-|w)M$^ZOwbNCvQ2Sr)Fj0x=f9cDC0Sn0`dXvAlV`7`nDX%Gytc;q zKmYAb`_w_)`o@{J zU1Cwcz@^g`_dL$Zw}fy-KeAZvd*H>RSq=H0|Lxg*{^q3rUuH1d3Nw7+R&3~3aOl3D z<=%8Zz3IWZv*+6%=PJIlv9?WjXYt&Xp)L>*uE*MW>BH%@Q$Oxp6W8wg+IjhvUu^&S zZ@sj;pDI3gDffp@3qzl4bSwO@{rq1?ltpCQ^S68jEKR+OKStCY;-_YlD;z>%p~VvOBIbl-}>Z*0TGIlEdM>Q=b11 zi%@u8oa7@KuqH)8Mn)x2x@+BU)eqf2?WL;=a^9`X`g?j?Ug-g+)gm%+yEfbVHXYcP zePGq^b3c-%_zUtZc=>$$-t&_uJo`A8*>0Nho7t6T&cvsDIXe0KP02?2iodV-hOqrp z@i}`l_?bgIOG8z&!iK+>lYie*-aec6?stZa&+qsCbLabz{6^(&^>p2@E161Tc1Qgy zOw&~mc~Y_Hz#^r0lU}dWZfR%ypLg3mA^y2W<9{#X?~D&8v(=a{UAtFsy{TSK(iUxg z#}Dk^X1(L9Hvg|1|992(yC>t1318=tnBE*7HK$~)azr5G?X?`A*6g{y-Mv}IAuexA z*`8M}+gaAx{;$bbX1;%O!v8N5nQKKEUVT?HKHR@${r5)|3m>hn|F!&Knl;N8IiZ|Y z1^tbQM_QQp6hE9+<}Y8^P;fvtTmSf-^8d9DC2CGH``Fz#n_pQc`(fqvPPb(->U56Umik5MaLATBdQ zknur-Z`JRQ{`I?hYQOsbJHlAoZL;X8iI2pGJNpE$KCAWi6^O9QT>PahiSu$QyuKmIMqp)i7gb(XyrXGmAql@=`ZGC%r$NUfNhO;M3IHs<-`%L4^ zCkJ{s8p;}KT<1KWCs8Z^r`_JBk$u+T*A=Rba<>BgzR3Q_Tz*AdwA7 zKbP-J2g8fw3c;%v&24z;e)~cW>!Vc(8KLXq|IW(X^?dK+J(9VfE_v(Cz4)zdui@H> zyniehgSeL6WT>6$*|7Ilu>I5U*F3>B%MS9tPg{I8aaY>ajb|ho1K$2nIKukrihN7m zSr_><;f~EWzxjM9Q@j1*x5$Dlp>THd$bTiLSMR$uas8J!<>woD4!o;0TVeW3kAbc9 z!RNK{#*DY>&Ypk$D{i{k-0WNH_xUgPHx4xSXH084z4?yY`h!8{b9VAAnE4=3_I{dm z?mZ5MvzOCnKQzAk&*#pKzijpUU%sAohGqSgYYTo9`!TGE+PW(H9%J1cyNP#A8)Fu# zvZry)F}~_|x{)vQ*qj*V8C?PrmtLE{+~8LgS{QVB3G4ER1hq!b=p5De(?KVUAM)v2 z9{>17+q*fN8Fop==-sa8`yxEy>b>(R(O0*%o6ciBup#cI#ky|2T`S%z&*4n?www3G z{IaOO8w+dGALy7Fs4r*Od}6)jO%taF?)F;uw!OK^ux{tGS#c9*P4UzIki6;psoopW zD?eX6>&ZA_9pjp~y}S10Wme6M5cW8I_UJED=UFBzr{7xZH)9La%O$e2lNfK!UcX?j z(&?<#XDv5QZ`y9P$j|Pu$@SOa$8F>vOa9rr`&F?Y!hbxLnhyDG^H%z_GtanR8r=Bu!kZ;|X1}c;20c&R#PDKHc=4_$$FJ8M`~Cmw;r&59 zk6%1rZaXh-owm)2?+)=t9D>$j|j5J>gcf!4xS2h>U zGf zV^Sc;6U+Y&adRVIhiqd=>;1a(;hDyp&mF`VHrMkO@f)$H^)eUxF>I-Ry#DU&xsgOE9E4_mUeGk@N!{<5%aB6DoLiFGtX z@t=DSlhw1Yt(p0F@rk?hbwU2yW-{Sc@X4ZwVI$Vpnyo0&u>X}Blf`n_! z7&L!~>txiqe(lY#N#<`0o3P{ey4_aGzFvCVH+xHt{>!uMQ3hM4Kfc2HO7-l^3sJkv z*6tE1dwVOi?YHEMso$3O$LdR!SQ|ty(AqxVT&j1$S*y?s&gQKDO7yyZ-QeZDnyJoG z<(Y4Hp=tSEndR#O^)tUUO>1$O%P`~JJmKERI^G{AXBqYV&SG5hVEOc0TP}HjaGu^h zgUNjF3VypU003f`TYL!{=Yl_|Ci$bmiTxx?_FXppK)+^Twn0@Mbk~HJ-ZJF zrax+V64xxh?^`bK0{JM>jQTlC@(!<}98Up!!rX$*h4%72gOkI-%B{9jL= ze{8vTzTJgarsqp~*(R3X*=$_uQ)z#IKmT_U;})j+yW8)SZ22;`{LaGcyTT8gbgq6< z{phto%i+?SFUyo`t-d^C)~&d5y3mRLy7#QTi%f$Lr2qNLWWQy(P5FYNxwG|tyw13` zbm@WI)LqxFdS4Eb@@l_!|Nmk8iZAu`-*->FGx2`ky_yBAldCNK4EIhqsdjz+WBOj7 zyWDG^{k$Gmog3-Kc!oMu`e_yO*H4yz!ewb(KTBhC#Ef$u9sq25;VF{JWl>8Jd zm1&{7yg>a+NZE|crODohrK(?*AKI+dn`N`qeTVR@RmQPVi!Ss2Sb5kgV!6|T`wy1e z+eS0LVEwUE<858Z4%vc}^WPi_Vw=v@qqOwL>Tf$|7VKRR9w3(&^?Ek*#WSGJC!}R-g*7-e_Ya6U1_s*Gbd4ZcRrt0KUzci}{*Dr4f z`#V$f!{vWlmNNvi?r+dn^SGov@7LNE=eY(MuFFMxx6GX!R~oeP=#+b1az7_uY>9hy z>!R1`tF6zubbsADU3l%|qS;&W-U+_gwtLxL2K(GCvzgAQ{Mf7iXXdKcqCc!N=W{QX zUTyXK{Sv#>OWm_C3GJA2O>^&*Wv?!oUsR5NdG|udO|7*rFGz<(^{iZ%f4496df1<~ zG}#{ut!J)YY})gnoj-UR!!o9SA+NVrEt_YT^;qdqiJ~ft$b2qd^@yK~XSY3ZTzd1g z9iP_PFPoOs`dp4~)zp6w*wA^ziKfOhy^#i-aTVP8G{^M&r} z%)O&A_kxJ+mik-QSALoNZGpP?BJnS5Q^TzMj@>;Oaa)r!V@aOYpXK~IUt&uxx~i^x zdFH30kw;p+r3QD2F2geJIw^nsgj+LBbl%Qiw)A1#1&@5Q41T4vao-99GGFdm_II{c zfvb0&{<@bNn&jn5zltPiJ-FWb;@JA8{Zj8+!nXRE-s9}enyJ;BwI^!den$Yx*j>ITyb)*q>A z+jlwKVY$j3plcl~wIy(AU~l;CIcwsL9XE^DUfIFcdoAT};QrwKRr3Y>mlsdIm{aci zbke~L z(7m2pv9D47-xg7Zy-fAHxep#)zxzY!gX_IPOT)wWN4c$jaP`Z}BhQ)6#(mr9wfgGU z7cI*}qvl?DnLhI;N8OK`pRO*+J2*eWgPYm$ij+^IJ>d$*jaVY9E9VZb_r?}y@ytjb5F>-e_pIxuDZJ&#h8Rhg^K^Ddh0 zax1>_ZN~DyVgD~lueonhefRjwOS4Z^tiHZP>UovV_W00QYu`-`yKa2<&f*U>ksnrn z>Z_Q{dO`QcYYx9@Y6UA}O#Q6H*I!*9Yx{I*ow|8U)IKS{*V_8N*`>^@a^}vzrf%QM zZ)N-I_N!Z08v8yK?Ui_5lDQ-}^q1-UgXe#Eb0_S2F#T9V#@xq;t~Tyn_a-GX)auC6 zwVCdyDOWo+63 zGNw6tdD`+5!t(pJyh$lx@ZSCF!mJ**TXCi_OJmC)hrRX@dvAL7<`Q$seCwTdlRtX@ z+$)hT+xv6ZE&Y9Ae_MlD>!)4_d3@>4-C4nD?zm0z!-)XJ% z;qm9!;y+lGVm%n5S>IM{-^Km4%ddRxvrEOT%uN3)-&^Fr`2MZD+V_;}fiTgZG1p(b zc+rwGcfDSMzlMQlldtWbmKQ!jcQ$8oubnw-=Knwb|6`)JO7GgrqO;L!_jMEYxpFlx zm-SzLt^BXldGXb)GqS3<{`uE_3Kl+b#(lGWs?*_f3flYcx*waFJ}>gw^82r}g^Lx6 z6Z#4q8GlRln)g5OdMmO(OY^nFjLSys zY;&0}{rOU?^?l2=vl$D6-MWVcT~$F$(x zspnfN4>tbftJ5nIWBB|i?0oZ^Hs;TcpS$HF89Ib-o|iG;JEQ)g_~2%S6WeQ_IXpQ~ z!)$-}9FxNRe>0hnHU8wN)2k6<`1x)AcbOUMA3Q%~UUols`?Ajr^X~7dymwz_wY-FN+fHHORZAG8){yt$JNvjqi;1hvJ8u7$lb6Ht$chl9^Hd zpgr=x{k7nA9P4;k5>SuXH?SBzW`E-ui`$p9w{8g1;qJA)$-mdKG;i9~%aTq!g=Z8v z`68zTItZ#UjUKZL*x`=iI~j~=r>dd&XlG5d+5$LxUkJ*nHJ!XIOnElaX_D7G|A3bJ&^qBq8WA;an z*&jV-fApCB(PQ>UkJ%qRW`FdU{n2CgM~~SbJ!XIOnElaX_D7G|A3bJ&^qBn(qsQ!z z9L*x`=iI~j~=r>dd&XlG5e#(?2jI^KYGmm=rQ}F$LxL*x`=iI~j~=r>Ajj;RFfcF`IR?2qF)}bT{RiPjhOYmN3=BR085r6?j7Bh{ zfr0ryn9<76`M-&w^M3r|8Her z`u{(mVH=pq@&A9owmh}}{{vbe!fGJNR)*&P3<2#7jbM`T|Nn*nhW~941>2bZ|7U2} z*2usO)5@?dPpuIm3DV8bpw`IH`oE2VA)x7h2SZc9G_WK3ApTnO_GNo`F#K=2!|=ZWEWyC!ac5^k0Nc(xP!pN@JOUcFiGh64mkn}l zp9k2}5E~lQ!18Kr5P6S=J|+)_oelq)b~XgGf;`ax3W}xxNLUU7Z)7GLnlLbQob3$o zbLZuf;$mQ6;Pv!y31VPiVgO+dHUh*}aIA9e7GsXo=H2Xj`icV!vtjcZv0h^hV1*3ye+99>EsWq+CXnkio1*|$)%@YUnGqDv3=A3u)AutlI52p+IEGX(zS+w?V{Yiw=YQv|x^q}}LQ6}F zih_8j0*BJQ0}OFHI+E(`>b`AxoVrW&$&`R zi*gaClQ%~~w=Po=XOXYMcZVI5Lnc{0*Zvl_f9{;ptmn4NUxi$?46UDkd`?q6HN5SMJmYWUx4GaZlm>9-w{(aBr_@Bzjsi&uX)X-*WX%G-#THJ9!GJTHWi;VgI z|2%iz8P3GU`>w%BlR@@_pb0C;8(>Af4I&K}-S(vHF?v@2Y-akjFAK6DauS>@MQ7%3 zWJ~;4`g|MDkNL0Jgf3v!y|#f$!&yq<^xX6is-+nw%3j&fNbxAx5OJ zFMw$Y!;<%l*umlg0!+f}jG7F|f7TxTbNmN$Mg>UNfvwTZsNUYmU4t=*;ZOQReTciA z5||VeSQC2eHqH1i!MHxL735A;jvj^2`jV9;tCuqL=-rd@g$1@dNbMB+<{AGrnAbf7 zd)!yaAaI6#fd?Z4XC%lTkbYqfMoosrUp5~7O!L$I;)*q=ssE(VViT;P~% z5SZb>;lU{JuwVC?{UL_c)gavm1O#WSI3vGf2}45*s^Hc`rBH!-Fy7V{zBd?Hn@>fkS$6OT&!% zYzJ?~3|@U#cp4Q4srzKy_0ybl$|10Mi$M;&z%ZT3z~s&qFOb(1SXvyyl@(YQJo()D zb2`Hka6&pDp{Vf8-sZtl1|ELD*+Du)N-i5fG*|2zg-V8I?krlfywe=-Cy z+-hE21xwx+LODDb3+8Jd|HFPNc1aAxdoNU2_I+s8FS%4=Ri_ukVD(Qpvk8{_ZuK{a zFdPm!v;VJs%&S0Qhs&?QjN2vD$hn?j%de|pYoo4a2_J=p#|sOVB@88Z)GxNc4D7LC`o)^? z#PAviOs^Fm<6ou=h4Wp6g`mDR_{8D!Bc4HPs@KOy|G(Npd?Ual%-P8KpZkEzuNzh2 zFfoM%u?%f3Aq;gYDd1RfN>BnNbfucqy^Enakg>g?jTe!t#atfXk0l zRqimSfV}a5VIs6taduv?ef#!`kNWT-|WTc5%9thWDBS~KH})Wb-?21 zwO_tfb80;H9^2u@aO_^5>Vjy8=AXv#PuUud+=$R*NN(Qk1`n)dpqv!^quqW-`oGiD z_2ui9zjEZ@XxygopqSxB$&x7z(Rn*t6|GLi)&Kq4e9nD06I*NQ6|SWWJyKVsJfQYE zJXcU)T~NI5=!P_`_2FEGIPF2L+7WZU+2NR z{msdN>p)yW$>Zd{pPP@}=zYJ$66Ei@92L+0A2Z))xaY#s>2bI2>YJTQ(`QYXQyZ|i z4;F)I0uz`n@OZ_FC_lUJD(@XE%Ji6rafW@*{OgNl;wYNkmVRgq=^*Anv>Vgn` zm?w5|F={fze%)yTE@K^@D;|)tH~#F^@V#@gY&6Rfh92F2QnAp0Ixqv2czqJCF97Lo zeCK+=xJrZ}{@veqwU0kq7Hcv*{=EAYJa4`cX4GW(-QqqKq?l2Wfoa~w>Syn3Z=Ebt zV+vxh`n)?M3?iez;wHkV$)L=&-bx&l#Y*&<4C-dsPAj^1W_tB}i<{@19Jn0PYx&Q* z!Q8O||be%dtim&N<(Tf_g}P*Pw`$oY8v1<0A8qWTyMsP<&q%?3`tTjU%6{rh(z zGe19n!@YEu^H=u17iGMa*s0Dpzv|{Y2L~>P@*4HCK~PUSL<`O^;5txT|51GF!3oi^ z-A9jyYL#Bqulaep)b5=2+s3jf$+h&|Acn3T)d7<&JAUB|r51&-WnPdRU27cJj( z?#F@Or<+9;S$2sqp8vD=ef;W3HU7)_X7~D)_iqNJxXAm?n_(rkffh%PH0y(S{oQN& z9#*T(bKZQ@;{Ltur!|?@|CwIT>AUj#TeU8y3tEfkKW5CI+`nkUuU)Taz52MreDBJY z7Ob3&ehvrL|21ANowq~L=FlC@gS+_-kyWxs9KAe&_Gdu|p1MKuSb;)O7lU2%*j z*1p{?x>U{T^O<|*AHQlaS++L(dLI8f>VByEZ_8!&K|OU#4mxNmlryk0#_wcN{>yr$ zUYldXHGgS|J?a1MsmsmIe*XGn>TXbyyZiI5Nj4}#KvnW#rv;aNg*&c&Z=WB`F~!;-=E&7L z3yulg4)O+7HR~CER6WvAmjlI(8z^q-?a#(RF&BFMpu=R+E?@cSFU#6BEo-p>BWNUUrx`k{@N3sR=ekW@!P~t zM;Y0G2!j~b9V7>ywB{v+fn9LAH-nw*g8WDmYm!~8~Z{T zZXNyME_$}{;HfE0B214yM9)nRVp*f;bzphenvAWh9Um8G|7m7>zgU264)@2e_s(z4 z4&Nz%{`b6_+pYB8F6G$LHRn;ZVV)#LYf_o)8K`66#s9$~L+P;d3o?y2SMV4gin6SCvO_=0oGdhZ)Q+w^bu+I?^S zCj28VcMhI@4ppsXxblcfX7$pTDH3#%MSq`s3+Wg|Dyq`nOWv^}zJ%`~A;f|E{Zz=9pPkcZSj8+&h~e zw=AExeEMwnRrCJQ1^d!BG_&z8y*6<`*$9VPV(-YFi(6b>KQs zAQ%E}c!P3bY{!8PZ3fF{{@1ED&p6l+X}nza>5sEf6194E;q$e>cR8-RpLSZZz3yYC zzh(CS;AuL`vI2geum2jp@K5LCi!3^CQZKr5N^JSKk1KJXL0ru(3wy(i>3jVx&u-W! z-_)qJd|RWI20b^oxVq!jt=)yeYqCClTYc+VMO*#ZW2?Vxu)1g9RO`65 zZt8X;^?QsC^_n|`>f1l@%>5O$)!ruT&EKNG2K(pjY(KUv@6Vy1JV*dd3MG(&d28}N_1W)bJ9gdcIyAl7zV)&_>oep1n<{_SRmTphd^7*29ADjHk@CHu^ltNR5YjfX})mj!RR9QuAfzjxR8|B(-}%x~x0 z>z7Q7{=7c#rp&9v3qK6=9-q(l z?EXB_v@k=2ZT1Ph||It5aronj4|6qB;&-@tiYz=k3 z?576Fw+{CRZ#HjxFIl>3x&7v=r5}6#&ujhI^Z(Va-i6E35B^Dzt`VQV>+|DjKUXH! zB%HNBJNvuo(!;IlsZC`o?`bnH<5<8VaD9!E!yZtYa#|3{vV_5;d&(ntQ(c+m)-r}C zGwLI^+3#e~VC;Ok`C5L$_EUc@n}5pwqUuw1O3>RWc!p`+tMzXVetj=lvvkFI-G+~g zMIQV%{l6*k^sDn*=P*1ge#3p+d2;moK1+t>KkqWGd3pHHN6C(@^%7g6x%I1buQ!>N zcQ4+#{p#@~KF9M94UaP%oByaMb9qrsFjI#!r$eQO9pf44XMIf%j;Y&3-n;xxL8Inf zgSP+MH;S5U&(cL3#fq7?Xdh74jpyKKOcR{IbU`PmOBh=98T1KAY-5^`{4Z7F;E%}9 z{%7igV@|gpRDC^T_IvqfXJ*yst(8mjuYR;K^X(mpMg8uA3uNa1^I99s5x|o0EOR>3 zP8Pj;-_QRzqy8|pack+C!re8TLO8xAcBo z{;}s{^|II3za;)zIrnV4#rY2_{jTlvPJNub^2O2iTYnBW$KMnw7RmZ7_U`ufA4>#o zRIASat{ccz^!|0RT*4nax%t1gWG`@4RoJuUA2@YwX=o5>5IYdG0+!f5HXYa?+8`s4 zn*D!^_nG@^e;(%OTz#vqu12Cd=}bt94v*w9p3CYo%VHv5eA_9!!7go~xVsLgYLEZc z_wzr^5t?}IN8%5Ie^)kaWxv;5X<&b^{kwJm%Ntw!oh6wPFFsYjUn@UBr&MCY`J(jR z{rf^cC4AzI{JrMm?yc2QYHa+A&l~(*q975xT=r??{TX#Z0&o6KN=kUVP{UyT5}pMj zH}sfaRr=Tb|IB@Px!rSf4MvlK-7Gg`53Flkd;fP`hs|T=_sd(sNiAVMhX>;gb(>YN zHj06rpu{F7gDYF>H~qA{ynniB{Rh*w*6y#7pECd3oMP~~C3T=BlVAB>+Y@6JB+`=3?Jx z#(&Sw|4-)dJY#nF$L8!`W_d~H%oOZ+WR~$J`~OQj9h>m)M)l)$txc0zHMjrEUKSFv zX5Y5AD+7Wpe=JClu9?Eyz4$)YPjNBlmHPeb_6eS&7b8`3AFGoJ;TF*BvI+b{?)$mVAu*c2G>9<#Re)80Ga5LytYP3OeQV#X%X3~r zyl1}Y|C-%Dc60lf8{SX5{^RZrgTxtz+h2+v>q-1$AG=e_=Vk8uKYJ4{%Q70&Zg=Z< zdU(J2`;s}|m)`m9sd%E-**#5I?vCh#SC#SMF$H!GA9vdGhtB``DD~i>AHvCO_OB1D ze`$X9!_0=)`n}0tgXOw+a#{2D|Ni?i^PO&CxZUrV6|<7eG`ZI?ma7H$RM+TOvi*1> zRbZ45AD(iyC zoSJR>^QUk6pI8?mK4Zpu?c+=3+W0oNo)o^G5V?BW){mlP(Q<|ScZ4^e{hfPu`}J#8 z+QpCdz7PNNV!qRh=4bM$kze>{_=nkgF@6-^^YH6JS)Tb@>t@(LuJ%6X(6#z&yTCpB zjh^iQ;_&qpWF_}qo_pr!#h z&Nw?9E^|5Ly|thI_q<)bfvezw?><_F(cBG^)oG_^*`F~#{UuPOr_;CcZ}#O2`gR+p z{a1*5f9%ft&Bh<&v$j9AwaCrNX!oy8{8-W@bRf#;-}Ss0N#~C8$bSaaw=T+yEoG?L z;~#TN^+B;fki*~R^gj#8^gSk`{cr*-@xf}&Dq8L9^Jeje-zxn54jt9RjYR(tPPLvYhdyufDU|Lo3 zzw7Vr$udP;UjDVVJ9*kS=E+JdtLN9L9rECzz;&t&qcW*!9tn4v*Ia9(uH!Fl~ zncqyIRejbU8WQ@qeeC#t>fqC9(GGtDqx1Rt^S8&cPT8z4yObqn#do_d&$U@Q8EyBr zu-%@(onTSd0L6EP51wIs4zWi&L)eRkPW6tbVEC-?^?& z^2)!v?7sC*;f3+C^EMkkKRe6aKie#qOKg6X-;Klj?-#LMJ3B|P>zTaR?e{Ue^?n3* zc_`MWTe97+e9gM>&+Gp``bz}Yo|gOW{G(5TK>*|0srrBH8-?cI0`6k|ePPV4)o7@7gJ_av_ z-bqRhj>iuDS=n~*u`yrWOxMDMKk-q_nvAI@R>pDo#IP)3@VS$}-W)tq0UB>~Sjl7% zlM}#HV{Z^9p>u8h$Ljmvo8MpmRiA$5e_izB{l%{zE0#Q~`^{>deQixb;-PLa-9@Vt z&fEY0W3~Ux&R45ezjFFj?#j3Q-^YVI;v);Z&??7B=Y5#*y(~b&GU%7mr(G~w)+G#Vdv+`Sb zGGh2pZ5R+`so;45YA8GhouyW;mPn|GB}}^yizey?)ixk|5xy0dc{5V)P!4G zG8bli@>W`W@9(Y(r3YEb-wgimYvp#n!xPQ?e!hG$=Zp2_kJaQBo7yD&3o)`kHTh7| zZst8g2dXc~%@-ERZhQROC-P_h@_kw@hg!aSFl=m>nY`?O-sXR`MO_SD4DY8WKQX9( zv|&oMVrwi@=f~S8n~q$L0~eeZbeMt|X1RJ5f(jh)Sd1W3Bx}NooBva9gruEc$L*PY zRnL2FPRX~W*G;P~8a_L-uj<^J{hOu2o%7?(Ek4_Szf=5rSJTbwqVJymsCxfiR7$RP zZ@9#|ozG?oT({Qz_wMW6=sdoE*X?TxW5cgn3NG*3n|^jiU6^3O_bZ1V2!Ad=<#{)u z+2T%HMc-B5D3Ph1?P2TXRCZ~^Ss(m1_qj;pk`4(kOV@^+TK+UWafWC9Hv6vqb9C7z z%Q2_$n51s$=B%r$racn96UpJh_+ribg*RapoP;RLCN77~izlz0cl*7+edb$x(IYyQ z=YFN{uise5Eco@BVZ^3?k=lEU_Rm!OXI{4Y{^~f<>nkE(|G&^~7jpkTM`iZ)b-cEd zvm2Bg@(#%Vdnn)bYya=v`?<@GS>F@W*~xJHX7#%bv7DFXdcE9&m}D-y3x3$HU3A>x z>^WACf7gEf{rZHdV0O}sGY8~n}XnvQ2}@&Rl_=YbT=y z?78K(T)7yoNv{M-NEIZob}ZVa3G?_Tcrx^I6y1aC;sJy$=C>B7(Z9>%a{*M%~c zSz!!CH~$;_-!yaMxBClNA`TyM>18xu^Y?a?#hL&6oF7a5%q@$)pRZ#*FQ@+6ufzwb zpR>bl&+PZ%eDS_N{abwP)h>fCx9@$yc z{6DHBA2QFqFW1GlN%))FtdG@c|5vQN_b>{< z^lzJzyBkCrHXe;%44V>>5N7cbZMbvGesiuFdqYM3@;(2yE?g19S-|^#OZ4|`xi=)T z{4AeNNw~fB8-H@U;NcG+@0M^qO8l4dcd^Hmt+#)i{vr4N?*sPa>t*eY^69%Y`C5Y+ z{^T{}@G)45yrdYly?jU_d!5)>@5xx4F+dh z#tAVEY4HuU&opn#yPb|Q+gDogc3telmyXfRbvLdpOS^rt>CN}{!s%xZ8<$=Cl*v9> zy{~EtL(RE6>hp@^+xv|USlEd_sK34M@5|5p+=_459_(Q*VqA7xmh}#A15<<11!MJl zwFf*Ko-kC*ztf}XE!O(6Y+a>EL|N*eBiH^NoLgy7fAg9^!@}o9ObK6}Fg>YK*9%`? zq_{z!C2!}`X^yKC|JALXUnCXiZ|TMG_4G8|$AR0LK|R8Q^6tU#E@2SZE3zFi4QW#u zHl0ykFK=;czA%IFnfaA>&6BGtY97o?Z>~KV=+1ijmVKcmw{!c(YPWMywomJLyNe!e zm~!}wB>Vg-5$0Ql{;$5<|8VGn?H6*-{*L8?MY>}gpHlgz3IXIU%%d4F8^q+t7L#)gL_&|4aPjf z6fK53{_}71GCXcqe0Gn`?c}Utv)A&h3~Jf3o7jB+v!Aolu-Wv@f9LjjorfDVk01Z_ z?TN^N3%1S6=l$F8#o4;X{#h1 zzyJNUE#RCU!;Jk!3=W%Y#h%SO&8Z>X`Yp9^l{k~W(t%s{KC*26tV=glJ=$P?r@*(w7Ur*~X>|>uAzq>HC;?Lyrz1k5X3+;ctelMVO zn~mkjliLi7c4-u4|F`p&Uy<GJD_l4i+|gz{#mX>q z|HM}j$22#me$)`qV0yxIf$y|M-P`$h+1A(Q+DJ~^VH9n6bV=Gy;lH2xczu7!b$*QA zJD>gUWaa~wOu=vX8v184eGZ@Y_q-m@E%1O+oxq1Pa;^uae?B(vc;b6?tIYHIRBfBzi?jz$ z65jCn;f^-{`mI@a`u$!<)z`mx&$Zk3Rlj{v;RpL4Pqrm&xBFKibN=s4Yw-idW!KkS zX?-Zn@%i|1GwJfDQ^VWTz8u~YU-?Sgx$+lZNsign+uvVqy)E!t{K#%*3rT_0WxFba z?^?8;{`bE6#lrymud42Br*#|VFee-qTfN+uw}18i&u}TvH#tG=7toRuK^7^IhC?${7r%`V>0dJYnC+L4 z38i-SX>)^lJ};Sn>)P6dtBlO=`MKYjqTJ8XufaI=usEB&;n#UTcAva`|L3`Ye^dW| z-QV>0#d15*H@xb{S1$j|;FM{&;fw6;!ftuHYln`V`SWGDJ#X^iKQm9vGR;2p_|oIY zv#hr>9Qv_$sq7i~`_CCZ$Oc4p9Ikq1pBngw&ssj#-DAW3S968l+?D^eIN|@TDGj?6 zES(%UN>rE(s?PuUo3e8G9Mk%m^B)rbT{&GQ&V)6RBrMWD{Z5RjOqz2Y2a9 znJr%H7`qzYTF=k%`EuO;S764ci~D!z-01)N?OcNS`xo5bu1?cEe{1*oL+QD-YeX4l z)X(^GK>m;0xj!29U*D{lvLuE>Ymez2t!dU5Hyf_|x|n0Z5tXF}HLXjwA1-3}P}}FA zRnE^ZQ@BKX;%#4!DgSKWFPnZb##`{inR~zgRJ*v}`|cyJ%HVB%^Brg^vb{0YN`8M$7EOitUKH@wL0->?3^_Ur0+ zUgrtSAC73Mv;W`s`yKbUlezwE-9iF$8tsqG`f1$Ht+zwLX48B5XXkJIulxO0{8hj4 z?1W8xAJU`NF>raG6`6kIk1yu~8HQu}Rj=($E1K)?D`z`p~I2gMaHZCp^%r+mmv!9R!j zx_>`3&$%H`bM0Q@gKK-<9_w#D?=V@-bw!{`0K>$Bjbs)N>3RI2y&+wJ4JZw6z-y@&- z+OnPBJb?&l6oUW7C1VeD{BxaCbhTzVENDQ)+92 zz>5NwAKxcztzTCC>*ezH!;*C zJGC34+F>l!7hT0!f8TvyXCCqIgU{YryY%12eA)kg+-R5Iw)y*VKVH}QJ3kysh__AU zQapI*k6>8PxBZ$7wzD7I7r`?j5ojb1m6Ar2pV2W*T z`2V|4=sZf^Pmh)Bj9KUU_|%eMiaksZ1AQ?|W~CjX_=zW7))YVDGkL`=*$t zORrNDZ>W9o`FU$cT=KFx%noAp&U_5&mv@@x-^)6#oPGH57S(PIu4#7}YPW2zyqC0- zbu*up!I7_Dk4|P1*N>B_dB?Wn_q*NA=kt#|;o`ZvA5>e{ui3hJnHU%Q&*Uz{zemf~ z9qMF1^7B`~jCyCwira7NcfP5A7M!x_|8KcC;oaNj@CKPj{Qe(&yR>lPTc!`6C+M@Z zI6PN&&~v!y(|+o~?A+yB|8LSaF#8(BaEz_IR}0pz@DV(r#ZVV!a74!V>&G8!{w`)% zQp_Y(w(YV~)O=wFU3K1LqF);SekgOgo9)Y~5myw#vG+5dA5Vwwbe%{cISb~wwLhk8 zu1@&=Zb$q))0#&C9H;(RLxAiykni@}YI$eFYdeNef`~Pb^ld!39vEgqh z+XO0+<(UjVq@JGkw)oRoqhGaUo5EEezYAS*oDWpOvDfnWx-j%#4__5oXZ>-`kMx`WULMt4Zm-p|@bRGq zk)PwTL|6BIyl?z_LO{{czu(z!XFophCsH{&<^AUsbBh^@+kYCzo%`N1|HtxqRa!Q3 z#a}KSj4QhqdC(~TQPG+Czu2<7*u5B@GcVb3=9c}}Ck!77m(McVcsVaQ=I7l=!!I0B zC%70DFTCZbaEn{UvE|pkegDI5YuA;41~GP3WSfA-r$A$jvW*U5j0t6{dmD?LV&@yC z&RBf@+w-ymM|={0l|-Z^{?qH5{I=@ZS$@-${r;PG$Z|jKY&5Yxx9MsBW}V-Q;|25i z|13ZL*t0VG?VB3EQ%;-81~zcy+0zgJDGE^hqpeT^x=sc8HEi~N=h!P8|VyAu9gssEmv&)=VZU-W$Bf|xK4 zj>eD84e4*zYBBBm`@=CUX-}s}L+8i2U#G#^FR#EYz?}?l-k*QQWWbaC<5y7{S0qpWq=m0pY7s4FtdZh6+R%gbCp^?kOb@e$oU@AoC>+kL;YtL*sPlAyWs zQ~!xgP5t+!i7COZLXEY-V)L6-3FZ!KrA%dJ*sC-Ad$44+bNBwAGiU5?4p=83@tvdN zV*hXdnD0&h_D?RIS_Eq(ax{MIbXduBAp3U=LtSx(nfQV<^{)#VF63`I_C>qhEp6T@ z^L(!UDThm{pSd0L(_{GkFg;4_|L19|9qbFITgL@XxE%0id%T9twKvuGe&4foWcI)R z?`?i_{LZJ(5>~Ib)4kC@@585r{h#ONv;ThBZ7-B_^qtO!$bS!xNd8x>c)R_eo-(SJJ~sc$bZOg%nT!vn z?{m*DUUbgy9n*_Wd#3vp-(Fr&F4xugZU3G1n7gHV(z5xpKYomo{Vle0Yw7;qE0W_E zIIB-Pyft{)?wX&UHm%(9=l+9De9Mr-(Kd0?+ z>Xg9sf0EN<8K!#ux!W(yV4wS3|IhcI_xl%?&vg<8tr=6}V4Bl?>CNkVMcy{|m&~_z zot3*{M;~bQl6wuCuM?~kd7*S+6H~!~bbIM*Izf62pU=+uG5vJha!Ijg{ryY#IC3gP z-^)9wET_tl+7QF=?doRl1rKT%U$@6F{*ruk=nT(k%?0x3?*#9x{_xrFs+oOFKXYB~ z_jLk6h1(e}@tv+@sO?|V>AJN-$?<4e=%2IakNi346~@t1&JvaSN3Q?+-gl*?u0brX z9=xb<=W;k+ujCs5b(h0$!Hh^ojoD78ST{s7Nxx$&P-lMjOW9hoty^fqqr?xYI~i=H zA6qhMFsYS75>z7Tfnp2)JSuDH1faSo0w>@?CChGq;it!(AWjws4 z);gYVvl?Go-+SGjyVEc0h5K6;ZuxHa^bGg0{`b%QYYzVoP85sDDl1CzbnZC#1&Yd0eJg5KMS(i|@_S*E`>1ECz_NnC__!Df)Y;E)B_v7k0lbRBK|9RQ> z_rI;}M?HoqQ?={9EEXvGDY;zumKgWt<;D{BW>Y^WY&(8$cb0|i#}~;9)6Pv=5t9=u zJeB+Un#}2S85?dNW8^<|TIYSE(}DB7B8^5*LhNU895@gyE1brE`TN^iTd$^YrXRn3 ze*4+)?633_(Pm9pRFk=PIW(Iz?gdT4JLnw%HFVccH%{AsH}CQ6yxoivo9pBD9Oa)c z%*1`}%l0+p=LYW}f}pY~=7) zv74Vi_UnvEm->q)OFDEput|uPt1zuOS*_N8e#yr`rVlH>U;F<0_0w`O(85WyKu^?W zIAc`3TO#}Kwr~88Q^Og$7<_Kdzrg;u{b7=3dQHA9^YVMs9|zChe8lj)(fqogIdk0| zDi8jvo3S+c-;tl+k9@ayaGCG)E&ICu)30j(`15y!ZWp{bM>qA)x4VBU4Bk9*lk8xc zE;MJ>yZ*WuX8ZN(*N)v`77tq>5-=~AZI9A{o!t7D*D)@bEbGV;75iI1`J0cZDucYY z<=;7VzaCh+o}Q-5?K_2=p(r_fDFfPC(hFv+30n>KEj{+7cz@)9Kb5!H+}@u1rq1_T za)W-m;kQftKDU_y6%rmq&hOi35V(0|?6KuD`xo0p{_LFf+inE#S40%btrSb?L5zV>2MxH5!0o-26y@1;%71qiu)LQ z#MOHGzdrquX>p#R*p9~_e7;rAd*=6!>kV9MURCPzVo8VWp>~d`QI}^L5>(++wb~@748n$gleP_u=%f$IrJO{rUaz z-j`~xbX@~YRTZX2+kd}tvf~slgXGPJ3KOD#pEoQ!cIs+ypQ>E95yR(t(8$=T5Ba+^ z@0mU-W}2oOE%s;%H^ZdlDQb%8#reQP1y7# zx85%MbIaiZX$gJCbJyPJRL?Me%lY|l#r@+CFY|w#VxC?5JFWIwpXBti8+UHmpRs@Y zzrMovZpi&_ZRRZh&&&^feX7vr^ZSkOZ@u|fd%j0n!rn*TZEo@}gU@A#^>G)zKd*hX z;mqOlvwud%ROSEvId8LtmiXRhi+dJwe5hT@!m#CyhY~|_`^Cq}n#YaAc4*iQJZUDdU6*0eww)N zOSGXHEAz5>(I2#mAA2_cxFX!Y)V@ak`Rk8?5+6?M@aT(Am!ALg%CtoqF++*^6yI8vH*}z^Sp>AWi3^LEa40r}u>1 zcfLRVXP$1quwYKhmu?N}m0_?~d^wna|7TeA_g)wLzre+%LIV zz0g$H80ZLE<&|gdka(tcNB&W%ENA;;M}&gUX|P^7yy4@_?v&+Vr$RqVkrb_k+|D&4vmMF^}`DgDW?Y|y)@-=daU#fAd?&mq3;P z0iVbfay0>K(&Nr-UN@cb`2P7{+l3w+em=wKKxdPNTM&~?(5Ks-4t|^oJn{UKL5tbT zB3^w=wFWKVo%=J^L>tz2SMGASE!vR2|BLE2yY|lOJ)QpL&lxs+JAb=SDdDCbgM=Z^ zv~Q-TH5)V!?^yX=tj*WPu5iuF;B&XC-+tV2ZO+%5tp=J#=dau=`0)7Yz4pq4leP(Q zth+Ti47fip-;uQa=ELhbzPpMlQoc=D|KQrOn}u&{+BF%h%Wms2u7B|0@Q1`>Q=Us0 zJv~x=U+u`Pz3JaFbMMWlJ%9Q9F|ludg%5Av`v27$W@pFu-^M+d zc503i1K%EgFNXIg_1Y`BAJx45y^yCu^+3V|K_=xUhU`BEfA1(5RL%aD&Q@BlYHveV6o;ho3AJRK$mCNwe|9DFsVLx&>EIzvA~A^Iwi+aOt@je#zMud;scg8@QOUGc4m^o+B=)+9N(&;>)t$g{M!+-2R_$x0_FBu{qo9 zni+=DcW2IslrYJD^`qryQOzsqHJZ$#n=|DMDzXn$f1LNA!+-ygLO+Mx@9P3uA04Rq zb&0d#+oA{AK6}!<4qUu?BBp#p81Lq^y1&PA=GUtEJ&cU5o^Nda%b@z!?n0qvy&3J1 z=TAsZ7dM?f!}h6Ic zH)`K}ejd5B9)Fo~c9CNNC%4_-_$tlm)f>LuyBl(<kLk~Et>&|tHsAJBGf`bM z!^m{YdYfdggHL`e4zoS6>C=28)r0Gw?iTmvng26re_d`()P@<8GHQRO1#>(*KKaM0 z{l8LUcfa~&@qf$i16AIq81_CFVJbi8VCCOXHjR10IY9;WhQbr71s`v}+p9iJr#5oK z>U+Zbk4xJBs8&jCbvVtj;oAGn|08#|U%b3g|M>EI#~=T`{l8=STOF2H|5sm(EWVtB z=z$749S}>3es8<>=jAIBQap7xCy8i8LU}~j&d&c8_bpa?cT%6j()IdBuFv>i63i5LL-4nv z_q?s8(yGV5XdioVP?+`bEYYLFA6X8cQrw&*D6eDcG4Uazt6FO%Yh%H^>pABitxyQK zn{ZMvVLQ{Adwv3MHdap4Wc(5xo4#8=fM=V_|DM~R(H=+aDnsY)E?fY z3`<+;YW|m;=Ir|MT&L@^<@5Ld6-Cxoyx-p&dPZKg{re5ca(R)zR|Udfch{|bzw<`k zX+Q1$Qx2`gtaonhKdx^kcOm=6di&=SB92%xvP4w=s=V{dWyMMXf0@swtt-ni&iq@S zv*qtEvGC0?jPY@&z0@E zwUlMazpn=C1RH*Sp0v}nYDz=c%=*5M#`AL0L6eBa`@7RrVS{}xpq}H7uif!IDW_-f z^pwo9el36O(3|b@a@PZvuV0=1K$HEzTF%RQ)9=2Q)V=wxx5wVdMj|b0@^hb>^-?$AqksALykM6(w=YRIU)@SVt_WpZO{o>(+gI6XW zO5Dkic~)u<|6K7$Cwmj#*00xloUAsTfmQh_(}fEk*01f3{4D8;+3>_Kkv8yzh8yFu)4u@ zX21TrkKyyGtfnmgncw|>rqsbZ8`)yce$a^6+XZ``r3#kJ{O|GIJ|<=hcft;iRePbWIz~m% z3Yc?@3HR-NRNsD1f4e^?>sU*b`O)YfLd-?k%ho&%-v4;wi9ZQ{t{nbjdHSAl&9zUF zuj3MZ>N!s&n3oANzW(zfOgx^e2D4 z#GBh^{&)SHZ~0kgnUK!i!+#S0bUuvUvVMKUI)|hurF-86x*Sjs{cQWDHg1#hyZiJ1 z_}E;`pFa0V_~zZBTCJ%+Cl@E26q)m3hF?w1x1T@k*x$(Kygj-6(S)A#Gi6P@5fAAf$A6;TDlMTpR8(toeFbFY@-+ zfE&6~c+bptc*b6AK7YS^OQQ6*|G|x>YL+j*S!+&wo4`_Zrhd(`HMH%n^kJ!8X zSS}yql$XyIiNdm|14j=xXa!M1%F7h{89Zm!@bGoNpD(}p#^qc4w>BSKwzWQahC%(c ze}N1(pY>0?+WvFG*?ounwl%-pxU9ea_?OI5;2gCL%htb&HF;n%8x15 zf3Ewl{vN(qA%fw|{2%*TKgRtCtN;9JrgXmb5_t(byHgBy6+wMM4?e2cJ!Oh;JnQ%E z^+wZQPw)Q4q!!P*q)Ia0q=*@H3?d7ung#NZXc<%N_ z+bz~lUhbHkaQ)iagYP#Bv(K;An`geEwz{V~S?uVSmzNJe{`dQ>_?w>J@3_luKRS9a z&%*4P*@xoT3BnJGY<6fbIG!h{6I1J`$5PI;r0O^4Ys1s`ryErL>z~)!-s*MCcjB@W zD);5`_Iy0{;Yt0unmIL)bxqq>as2q!+`DkoIoAbO|MQi;o1Kvc8{TPgxXdA8tJz=w zY}09>$ST8Kj+_~j9;!ThKZRLBTm6Qi@(g>s-+v-^KVuDGTX#=ZvUeboXkN169{`-+s`F_JSt8P|)e%>x8SNUXO!t>eoxltiJYSNECm#xxd;Wo?X zdYd+@=|Fze@x1~wUmZQRWdGNz>)Uqp&$7RI&htg-cBQIgJaGnpE}XRcr*QA_?Q~1A ztzXNs=RIUzx0RWnWADGEb6e{_d&f)txgB4aw87eUW#u}d`vu~^|Nq>VVqg4w{@ICJ z>&iSgT&q74Y-pbF?XzKe!s%rlkJUCC+`YR^zy98y6&krWHYk3nxsf>0@pJ5szh`cH z&UsUQh;!jxZ?&WIXUNNcon+x`t+^rL|9{UizNWMDg&8*5?vc0T)nI&Z;6DEh8@sM^KX|}#Wr5hYuHwsRSH{~ z;=r+myYZ3?!>0esH}1bTgPZ5-`j^lDm?R#r5i%})dSr9j+!?E)U$?J(HsgP6@bZ>* zdE4IniQL9!fAw0=a*4+=IoXE|R&eX>XwWoCt^aj-e%p??0$IXJ%#5+r^4W ziw%F~9=j0v+Wx?==qKNPZvQoR-JVaU4EVgxsz|@Tsrm8w6Q|pA3l6q^d~(WO=goSK za)Alj3Gah-I-c`|sJpT@C6!H_@b-Le!w=1Kwo7Cf%B2%>DBlI;Fc z+Y@h7SdRR${`q=Kex9$v|8KlzJ@W#VwO?$V#RXj%A;5IEje*6=I{(~1`*RYhH*eYV zm})ZC-QSn6JkLB_YdnEnlhL|Y7^tObv_1i^tD$V9;8{D2U@wbk*{IdNCj(gVf&vAcc{nm)J zIp^2Ow(p+m$7I@n?fL zPh&oC>jzizzx|s{i?01yZ}P1E!NHGbYG?fa`Fwu-b<;C@*A?g=zg}Ix{=$bBuXpNp z*S^~S^K8D;o%8%NW#2^3|25^k(vS1{kwR~L{Gv?M?(J7d+j;qfHj`brLh8ob{{Gl&Dd8RnUlCva(8Yx+bLhk&)XlSv@{50Ff-jf_NOvclR-fd zdYFP!0+V9EDu#yE_}|Zc{%^Uq-|*dazkSJnG}yQ5POQANetXK__Zv)KF0qMFuw>lQ zyzri>>OQVB|9?#1Z`1O|gzfu7{`whe%31PtKOSEAKha%IQm2byCyRJoMWV+4kNx#B zIZv+yH`|``Tf==Wu6|F#PHy8nxfRu|Eyr7SKjl~;vf#pxAE)M2*c~#ty}w`Rz`k!H z{_7e<-xwXMI+GiC^2goPkN*7htLgWA=kx#Pw%1AP-oD@e{~)__|8e>F{rl_I>=%Cj z_nG;AOPhah((Spw?cevOCBeRAf?@vYfB6TvT@wx`Z`78s<7#|++kZDx(v<^Gc@*3a zKA1MAd)8aF2j32Fk$&*S{EDfI;0o<2%8&&yQ-9tsx$K*G=d!>3Ufsw1+l4h54!Z`t zg-vUeD1z3DojJE(y65tA^<$BTGAvH-`}X7ULT(8Sp82=`1pVLk?R;H*U2)}wywAU% zKYz?w{ad~wA>-4u?MME;GWc-iJcs>(Kc}ZOr04SfnH8PKX>4^_;<-1k`91xI`IZc# z+rQ15u`l`Go@M|2=G>o9#(d*l_mVw7V%f~*N3E6G6|+lq-qHUP)=pf^U@&icXt2bz zTYvKFA2bRa@~lbuUjC{)N&L|NAM@>bKL7ivI-mcW&i_RkOyA~tO5RAiDe#0PC+dAP z-&u3j#=8tJ*yDfy`|eafzv@5xt6!mh4ze;uEeAG$_Bn5kUU>iCU%3y5?cahHdai%B z;hFK3V}HuiR=m9mK0ihQ)QfoG#IlKtL7hR3jcc*_>=}0Yxlc7;&)@uJpL zyXMwUc*nNke#Fi5=V~s^{9;nFE$jFF{!MFs{pIU=u23+Ysa$(UT5hrJJ?FoE>2nI* zW(e;Vtt&jO|44>EKE^)$+P}9p41OGI_@zGhD4ux7wSdu!ss6pj@u0q~KeFGbxP6<} z@soMR8UYDACg;?Dhvh3%swOZQ80}aU4jaai?FG%vU$gr?|5Mx6)YHHGPc@vD^S}Au zKx|Fvj>|LZKi=3CP}FPq_w$=0_TPSQPWaTY_V4|S?-%x`)Y(|}{e65mHn`2Ps9T0d zUS4Lyk;8vZ{z{kIS@!zPxBaGNuOF!IVQqZGCKVpj!+snp;tP%!w7)c-&sJZz z$FyID;Stxj&A09TOYLJl@METX)^j+qD=k@;nxBmav_0HW(y{EI?*1ezEbysl1 zSrMssH5zsQ@4K)hywYH3zh%j*p}yv?Fniv;J|mZO662TBatdv53Y zR_rnijng-*t&887lmBY7SXyxB_x0ax|9EiBt$HGO@SOqcgFmVl)x{5d|GwUMS^FYp z_2bcZPF!m%{9W+j8)SVxXSnB-#_t#?%^MQZ$GyY$l#(g0> z{fvD^`r7+H?tEU@t?GW+Wq(17aqQ0tNgsoWZbD`>-@dIcfWt~rc=5PZtmOnp=7<`;m19aP0TwPz8v58=}EfW30@5y zb_K)wU?#5HtPMh&pO+mdohg@G_&5Bfu+_1w8Fv1jP=2*<&WQWhrc;#meyjmTBgy;;)zcIi(B^D{lWk4eY`)F^WV*{zhFHK zH8G}0Rt3ZQ>3{vF8D*co!}TKZvn7M6we!8>53esU2`jj_WX9e4x9?)ZgmymLJMAz3 z;l;K*{QG0Y(oR&&lMM2=EHsFGrK#Tcb0hbIRjb!=x$ggSb?w2r$2XEWImOy$av5hI zUs*SUU&C+?!;O;iWf5n#%Cz-LCyV|5^0M%{+xB|(JocJ{MF9tn*56;kazj>(*Q@s_ zQ%GRNyqa0-zU9WQb1>U+b4L#QDgh>8cF>VyKQ{%T?#fhH%`ky^!iIwE@0#ofrkWf5 zued#5_2cq)QgS_-8^7&II;*U>B#GDZXMb6-E_*}uZO!wM*J=_U+=$tuuixE%^U#me z$C7<#ZdG{mQQz8*r&r;Sl=ZYCd;9mBpUp30y>V-QfAZV;pStFrKTt7cd)D^6-tBDX z=19KJ$T0mazh~pwzIZYFJMWKl_MN|}$8N7*#<+mt$FC>1^%~@o|Gl(fSkJPd`@p|> zSD)$j#NH_m-?B|x?dxl~A3KYVf)7Vo+V1GM_N) zFn!)8!w_Bk<>vpB_p`hl*kWebXP;kFdHgezwDi-w$<2+2za+G*xoGz7N(|@Ui}rsn z+CNP#>^XL8e>hX!NABIZ@19KN45mQOFsloZODue`Z-=Ex zvuo~^?aPnNo3qKdpf}d}L^tc1)7Q_=Bt&?UGj`rU@fFMK#3 zUEBHf-5-v&_t)MZ`EGTsEc1q!&HB&)f4u_^j%%{bwCC^77rVbXp)MnS>t}|n&;0#= zr#@l$67f51reBqyEeE4wz?8W*JFc&-E6phNe%C9~u~+>-U!a%4!FS3z`_F!jb2fj!7~E>(J(iIBChxyr@UkPqTFcMg)8BLP zpx$fy?b)ruCVx8{Y^VL5U&j2SnBk7O_ilzcN)HZ6i5SO&He5Hlv8ZuNC9FIc_) z?&FWeKAk@`7&EUkd_A{`d%>p6xvM+#R^QLO;1{C7q9(y4-23x$&KR^JFS zp5)Xx$@pU9?-$vB|1$pjzq=@PgScL_*qiXM`_gYV>gVv6eLo|4@ZYa(@$A(%{;Xg* zU=mrK_EwfnuF3rYzdfIw^TucVm)#i`{M&NbkGuc)+x_($4C>FnNV`@0-r(pgL%&Ub zFLO5Z{WSKwX0(7iVY*YGb8`WswNbzDLVt!I^?-b=zyzpZ)!nYPkL3YxzF~ z73(99{h1$=-qjw?l<=qQTYchohEIQmYK|;rsxEkH`Rx7dlc4<`GL4<5{y4f}X6G$x z?IGx@bIc3kzb&3${$o)<$i~_yQ}6C>{(sTG-s*;b&F|=gd3X1y z-e7Ilz(BDJ8sBL)|v5r@$N@!8~X46%iwT)`C{Aq zEd_~tTHpVxe#iaZF#F`BgoDj@8E#)&!~2x=$H%z||1=mM$Sj`yfAXB!XYPAHJAD8C zGwZM=0y8W)d`h03pFWL=K?t6G)C53VR<|1R`Yp*86E0(X)7d{|!lyfV3^QJA0WC6m zSEXXK^47Go)w`rBW}SN55?1xGQ@w3@_Pjc+8(WVZ(A)K5(S!Q$yYFv3k&*Dr;A`2> zId9J=toivkdFNq<|5JkfIQ#EcJk{3ZGD~w3VZHe;<$wC-e~D8J&hNU%b}n&_`1vX4 z=N*2q`G4&1w7aW3?f#_wyuCG$vEu8Z6))c0*=by|wd(7u1na-n8{hwLVCLiay!Y4Z zc>Zq>J}lpV@(@?NNe#b*Jy(O__bFfbCm(-z_2`0ryS`|a*q@c`$A11xfh1TlCiA-` z!4(hdP8*)yTf2S!+xgY&V=VvsJ%1Gn+Y9Bu(c{b#VRUBSEzp83jXztCzmY4N!FFxy zo4YAJcdss&VR)42@gr@rP{EN$yJnrbI=uqxk@wwT!$3Eh+`f7Rm>#AG_?(8gfJ|RE9JZ{5#yB7-*ayj=V@XE3_ z{M(fMU)ubrK)ZJK|1ICk8NMvs@}X9D!kmUKO-JoA_h)tU-#+_sOul}OUi00W>OH&@ z?rW6mcUVe#KX+MYQ+#QQK>4k<9rd;6-dG-tPbj<|SDpLeWUs{P_eaW~Ja3Ku@Avaa z_TfMKzF&KK@RPXu+Mn&08to6rds})nO#PnI-6eW8?&eCnwB1}W_HUS0eEfb|q~YW? z>y}u>=kMkHwf>y^zHffpg=PVX_Z$bl{H-q2`W(NnX6O7>-+wMYHhufi=l5T4D_Q1; zm<@gBpfH=+;LXd;V!1qOPZT~?Q!e-k>;vJjC%WiC~v&; ztNPrvig$Z1zgxaN%zK&+r+xm^rZKS z?#VAdDn5!kwzc|g`mK`<>UNU(+;dE`!#ZBSe$8FBWxw$HgXK^6G$r@hnuVOLykFh? z_g?gUVV(Vk$(i>Pt{mRI@kS<%%e1^40!(+C4s1$2{c2g%u`jQi*ynU^d-neR{xA0p?>p>6%)I>NFj>oBGKb^Ey}j43 zE%^QX`0qE>pyf~hH5hK(O1rk^?LU+9OLwLmZEqL6R~TjE*;jjYe$DsY&Oe{p|4F>d zbMDWTNeTyZG%)_fEd6k?d_dras@Vdc)c0;m*hT z|IB{eek;>*{lfoay$k2OKQgOEL*@r_E1UiI*rKmf4*y9!<1SxYvSQY^Yunj=pRX5~ zY0q8w=h&X9fB%)Vq^`X`qdw8@jD70=#XTWO=hyuFE+bd0zK3bTUgm}vrq}Ja+5F>* zSd1r$GCk&FJpU)U_F(6^KL@+(&wl{zXo2k1ZRBiVIHLA@)f*;-1v%!RZKr;WD{e}e zWM519Z@lk5tApju&p-CuSbJ>C`ul?Zw|4*DcfVCYLizWe@U>B);ePh1Vr-r=>c8LS zr~f)X-`+lC@AuHalNHY!Cvpng=bn|4TWp#ZvF+LUng2C(HB>Tn?^pT${gqhsb%tg&#x^4-;b`Z)4gGL@9>POr!$v3SN6X7`Zzx7dj2f= zGdHr%-<0w%dh`49e}Uh3FN(jBzW1Rm;r-t4_Y!{kX)tO?*Blqv(r^E#Txp8&zw&SI z`CQrS-+oH?|Mg06^HcMboTPt$8ba5w?cdPOTX@~){N?kv0>bjPYeywEJ92)wKk-ey z)RlyPVFowL3TwW#2s?3hv3<1U?%P>4mAlc;;Q^?VeL17F_x}04muJ)qTUx!07yGaG z_QTKewX(G<`5_|)phNAv1vJhwHh6A1B~oR6Q)<8Ak}cozcQa_UAB$m}((oj|D|^4_ zZFRn4mF*2O4P24u*}jxnXRgb#+kbP8S+bjkW#O$Y3H1p#@78BpvZ&9iDbje}^XvYf zXXXc=@4YE1z{UPA;jN?%-=@F64gN3Re)P?^?sN9`CYAlEJLOY8-_1Ky`Rmr!g?4Md zTB|Nd^5XDvNc!{IyrnEtoZ;sGWilJS$v3h6^Z5NQmd`;x`^GiBzq2y4e_a3ao-6jw z=T|3M>Wki49(=#~`_li1&KWx}uDBsp_VvQyAdkDvd#}%NH9W37?^1xs=5?L^>Hp9F zmphdI^Itu8*>X*$8vcUi=Vdl8zZYFreP(OSROkQm?{h2e-|=JdLBCl-@6#CmuQ`;k zLsWx-=Sh*mrCatrbE~esSu1;HzD&cbUq8M#aZJ%-=#;#*B;nR&OUrYHQZuY}GO%7}lzQyQ zd19|}`nBa%$vrFWljEK+)f~xVpOeS)yK*^;!T-!_eX&gSUoM{bQTOMJapH=twbo6s zxzE{UwxxJ}NStAyEz%J8I)9Vl2m1}ifA1%zA8S9xTt8vLMJD)HZg=kEhP{Qf7s>Hpi`6OQiB-d{24PT%9lb^q?q6ZY3hv60Zc`Rc0k zqt1HP^xXU{li!HBEQ?=LZ(?Se+OYMDrMFo7rx^!+3jHxvwFj-6j)oqKkEWog$`rVE18PmQm*t?xK`=8i@kB9xwtlJ*<brtRo7qd_Jb!ESJ`CIV#c}6?^ zjHgdn0`}ZCEIM^N_vbx>x@UW*eipQtzbGqy#vJY`eQT$^K6Ko_Cuy;PE$m>2_;|a~n7RxBvQ&|3c^n4dv3-YRi|;Q`Q^Vay90;FNmJ;|I^dc zrx%p{FPhT2JxrfA|Xb*UdLV!R2_m5r%okym0v|f}{_Vk$>&6s%MSjp)k zh8Je(zxjLBPY3#M`{r|cRlDUx?g` zy}UN*SD3@M`l#RP7j7Q;^VYiHlYI97md)qw=Wb3A4Zr><>espCK3>)D(SC>5_gm|^ z-H_!xnv(pZCcL5I+PB^EBG>O+o@Mztk?F^uI|W7a-f|_J{VQP2x#{?(H@`cV&lg+! z-*nde%oU)W6h%Tq*|9&f9{_8Z+X^+%8)mEnpXSU7>fMu$SF$R zH&tD(f8pij?9t5^zTG~_ZTxs0<1cNqqo29DesU*Y{N=v5RGm>QFP!1+{D|zE??q;$ zUS~L}!R*ssl%M!#%3_lVmmPlRO6T1BQ}d?lxuVGV<9FFbi{y0F7bICSh2Ac8;A4FJ zB&Rf1MjbRkY0vxieW=yX^HUm5F7ugNeBhtUDXvD&b_VszXJxz^$5Zdy3k5NJ>+R2i zO{VmCgH||z_UbZwRz35M?>gOg%x90#gc&^M>aZ{EH|JN|^ z=3~hIA9A=N{7qlvpRFr{ov!x35wp41Ui){d`urZ>`F-jC#4kU#`#t4yLb5s(QZ&os_nR<9bpvQ-q3CGl)&0CqjQ=;vx&5Zl!D)d|&zwN)fG~jW{=~bG{ z%LKmU^p{KU%-Jik+@SN#q%%D^GWCz<$NzrbVqewxGyAQ)ONzP@)4ZR*x7Hi}e^#fp zgu$eJ@*-GcwnrNj2o>4uSq`YIOy`wSZ73>Yz9gmDbDBwNhCQz?Uz(5MnfXOEuZqt| zx6PZO&3h(@pV>`PK@PN!hc){1`Wv$>zpndTbbY`6?{jNYPoKH}%RBr3nFA8$_uucI zR}!@1re(33;K8umvzC9CdF+0^{rHZ*Nj15XzHT}C?WlZO_J4!_yW-eozQ;Xyd)V!) zd*h3(=5yuVPtYj4Wyv0#{LZ=6T6Ecw-Ktq-=}w92o?*XyBp29!FP?Yr_*C_0{tS`- z&$a&y?n#}_w{MMr#CeX4v-@r1&HwJcH}Bn*ZfLS+RJ_0oI?3)sP|C#XJuiP)GyUmo z&|pgSV)$zw;WumZ*2`D=)6clM{O0f8ezCH3!J%2}4cE+hUo777_=xqNnRhxFk~dcd zotM(9JKxs(@am+bM4uUzYH2xtO%3X1DEnMtJUXjhYg=7a?tI&)+ShD^@{Ip^Edl!eTIiO zql8pm7Hq-Jg4Ljt2siw%|H0p=b@$g%eYU<58J?pv;{V&6W@~S}wXR_a%Y?gr)-(DJ za(?#R$!OrI!!x;T-5qU#z1#NhwyLj_U_2IUn^UkqHvVe=;VAQ`ogY8T@tpZxao@0B z!v6PPZPC+q=1ShhMGPO_Z{97kuHy4-=fL~_RDYl3egEpr4zYWm&lGReo}J!**Drjo zwe__8O}80-?tAk;{(r`r`iS;K`}rsY>$+vaxc$$Op; z+c~!J*grPEec`D3)27e7YvzZ{+xdGz;*K-OSjkki!{Fu5LUhnVu8GXtz z@W$Hu$vNemXX>Axn!3|GWT${cDNB*12I$_E8K+l;u68T&yZi5Z;?GY{Q-6H$FN?f0 z;nh+G9!@h;A?RtS7w&TKSh643|E*5dl5tJ#VTHth^BfQVk(Mx2Uvu-oR$UF&Vkgdz zTfTojt;u~xeeKR)ZO@G3<)@#@WG`-4JjC#^)A;rC*xOm@?}YQ;+CH9N^+a%C`##g` zWdE|H*xcBZe|y`H*ZweF&QkMy&i0lcukF4W&TceKpI5rH*&?;@+do@>DdBD3GXhu= z9`HP@UC$xVt~;Ck>jRJf`{Mm{?qpbUUt5>{x6NYG&#RKtet%$6XE|p2@6bD^6*qTs z*nWQAS{5pzC~f{%>inJ!d-$&vX%_sfd|kF|@;!I{$4rez&+PT$ikSAah%|71nE15| zHsxW%)H&lv*TY|# zY~K6l?R<$06_r4TP-@ohNhuFeEL)HgUx8M6;`=7r5yRB1m z>e>17EIF|O)-nY~w-<2ykYTh}J9F2#vPM4sS@Z6ja?!=Wh^={V|fvSLsG$NnTCUf zfuM7*A^tIF;@G0ge&GDaE$3_XCU{O^$eUU{bMBP#-w!{Q?Fj$(?AwJc|1a!3SfzTv zc-fY;`D{INwkG|)b&^*hwPEZ367ShtmCtE2mUvs%9kyA~Ah@htIZxq{a^ekSuZ(V`B-`9;h z($3X>yBRRMKmFPqX@}jf6gNLoJ|pGbkpAnQx?cK8UxQ`u4@=xX&s{UQl=re-{j=9I z_lK{G`8`EC`SYwKOBw5Tdp9zubrO+u5>d`%8mE=2zR<-Lm^Oul1uI>kPZX&X30HLItM3 z%1kIU$X?H~;6;G{X14B030{s-n~$qk%c;G4HvQLWgChI7!!~Q1Us>Ijb!a#9J3OmC zZBCnM{p<9fjvw!|JdOWvWqTUDjtccw1`bBW3o|)-b}${tUd&SS*E>E**kX=9y~2+whm+OYar?WHY6K@Yd~{*2F7|9kL{{2VjWEkA6N z|NY*%`CqtS@7L3He;(g3R{wssf2ZWm+pmR~pVd}6er{jQqVnwQT_!XAO`kTOxqtrf zR_DwWMcE6F9{zKAM_C=?Q@Q&0)91Z8zP2vq=k4$FN`B8xWSd`I8ImyrGQgj(MPSAM z_4hM+R~5pV6da9)t_fE}818-YxBDF#cFvlK&_nj^rurcTBiSX{EOkLicadT02b^&Fc%^mDcF9KHj?L*!dmHWDLAm z>l4qsQ@{N`F8Xu(&;8%!>jKQD-#Hnpeg9*h!1O5$*DmGe?wuj-FXA)TP+!}_%W>JB zbjLlp7qyuUs_y4&ZT~mPe}UnPkax#gUkbm=&2o25o3o_EqLuAfyz$Z_+Ds+46Le3< zr~furSj?oTz;X<9Us5v5o;FcvA!{&=qh}Y>gZOE88u<78zT0?d{WjCL@9+H5SNyU< z_T#jz_SH8(9-LovWKu%;GMR=4d@+afWM*zH-1Ppf&L2CCErz@7zFl9eBC)w|uPEzI zwjTzS@qV_`ENY7Qm+5tKvE2MS=gRbJev3l!)d)kKCtNnNL>g=|AZvNFs zpDk6w_US(PXNPyJoHu`YNWlLCzdzNkTw8f(&HVU1uVWQcp8Nf-GlAZ-CCC)SaEzmZ z7rrb@M^K`ewPE`Id;Ikh9`8HV=LlHTye(bNADVCTuqDC%$MyT1-`18f-Mu|sm;0Yy z-r?q-(xvO9KJz;=*I&7IJ2&4TceRI4&D^WeKlyg^uG@6s+JWAKhaS8X_m1f;duO&! z_RMjK#NLlGms=9mSr4rJY8==1bN~BA-5i|LHt)P?8xX#8db7}nndW;nr^S`WZiwSt zF;O}p_wv8;>i#1=Ywgxfo&A1hMG(iD+H1>ecdwP7{?GXRWQqNMWmJ#7FHjU`Og(B` z{~^r+w8_5ZKnCd2oh^dbDldIpQCBPuKX z_595ho*%Mb_WU|=NBY{0*m~EtPUE;BK8+7=*V-J7tnGVvnRl9LorL{v>98A7^+&J$ zx_SS9!`t`k=hnHscqF=P!iD?1=63|-5@)2(EfotbeOlVuY@xyU|K6*A#WR%>-uGUb zz#@6>n0qCoe3^K_`Av0T(Dg4>v+X4QTg)8sWzSnuY{qMiYa@9H|rGM4! z1a*4DGtkR>f&8OS2>jwI28}X@5w6zInYo+pP`P^3VKNK7Kq_F#PM$SfMkg zjs4y)uQd7TuwR2|{>HNSlbTFlveoaavhkn$W~(*(b+I1T6oy;E{q{cG^Y%$g)V5Ck z)pPRthg#-8Jdc-G?bva-A3On=utZ=2lR?mlRq?QqH`yMC<5~=Io98Hfh`ufRp&@m> zeZ}Qf7fQB1<(N?V?~?AvH+3@<&P*%3w=E~KA|;&B`&!On_2~`YzIgv$lbi78tNQEM zf!>$>lYTuYUg$FltE`Lk<9 zN!}vu+`CV|?LG1#R(y(Zc!b&i6zkRZ|IgX;{7SGh|NHv0*{`aE9=Q?7>kLXk$$j^+tln%|b~w(i+=KR^4#o8xs4p3Qa=H%Rr9s7d&> zCE(mTrelqfm;YIu)^*TS;5#kLIw!>Ar>J&#oBOe~l8^W2zndd5De;ebWSRZjc?QSk zPhqdN|1Ui!ea)HVCAwV)=KIf+X}h&GJA6a_uV?13+wS!q|Nc?^`OWX%?;l=&)LH)f z-9gQ*$udQP8SPsR|0v6TP-&drCKew3b6xlxiE4wTkJ`BPmmE(x`s4M33Cb)j4&q7= z{{Oz%x_*HsY}Jea(^{nqTe%wQFXm3;-Tz`n@~c&BB25qKKc9~0`_^au*!InL;Z*fM zck|C|I6j4GRUngGl*sjWfm{K69oALVF_Y^*JY;vi82IBFU)rp1+oPSoeKtS+Lz4ek z_kB&VXXk6y{r++M@Z&EpFE`)aS6jUyPV&S1&E0nxXIRThCF^Ur8#Y`Np1yJYwjJ?S ztPfvh1}Am%JU(BtJPDLM9Ik`53T4~RRfA1gCAm6%Dk4|Z1f2*>Oi+9bxgPDfY8|E-RTJ^4MU*m2*r*8GT|7vSq>)p+2e=lkD z^lnn(zcb>g4D!FzPD{@C^J1~c)!Q+ZwIQF%Wa}!b>OMZ4UQv@CEc8dpJ`p@=*!Z!l zL8Rg1uhg$`uwvs|kCQ{=vXeenHZv6+3Y&E@oaegO}D zFwW|ge*N*Ie%ai)3*Vn^f32Ne58asZn3qwL;qlw9E~pz|Cu@E z`~Uyn&c$!!@RH7M6%WNtUBPUXT|2tgUSr@C ztYUFr7j$IhBdvyqeJM}8|L44Ycy8{^yEAVZTgN}X_~&ME-RHS`uUDUY7nfC&{q~BF zO_j2sROOad!h8n_%( zFYJ&MQrIm2>BZ9JJv*lV&6E&eo;>l8yhX z`_G$F)Edi?qP$@%Pw?+Rwz<3_Z3+Pm45AH80fw9q%^&<4xEz*ptP~13DVt}d_~FCf zcHj3QlEs&2O9-y7wXOb^lXC6;*I&9A*~3 zmR$ZN+nzNb)No~ONMYE4&M)>A4tWs_>#Zld+>G@QV1c+#!@q&cq4HQogF_+HsX6P{ zt?T+7_2@yj{=SH!9k-LGS}y0h68vrD>+H44pVzzIYM0kyuzS?N1r5zmP-s5n`^$IW z=FOWcnlAjhc$BkQvHHjQ!}f|Uk<(=4<aWe4s&POX3U@yGr-jLG}BNRtAdf)AJ+R5HLi8JJ`RA22OgoUl0*>J*L-JPjTfoEEq;{c^S6 zdwu?n_S?t*d&itK;&4b<&9Z_a$8^&hZb)w4(9R&*U|TSw$-$UKNSiU`-&q%tg#sF& z^j&zw0#u$bFmn7*c3?da?-Rh%_>(1s^T$D^_dn0OpPVRg!-`RhA-dn-cQYiD_Xs>- zN?_q~hPbhDt?&b;gx7*;^-#VbQw&3oLm~&%=2E5@h8){NZ}=g61E+@V3~mda$n4s) z=gv%POUs!lWv_lsDEt%u?t;%#%hKA8`d2^R>YjhSd{dGvi^2qu!);_XLQAlWE(XyC zuZKZuaVPKEn*Z3p=lGGs3^VtGi!E4DVhS#aO8gqQQOcPIObgEM*qjXxyBBj9&NGzM zF>R=gXUWUUtKoFwWl`7=$rQq1CLLwQ21yni!V8!L(hl>mtP-sF_9oIa-lB;|Kq#(2f8iIWsCDDuz=4HF5TSkKuc4IZm3Wht* zhalnakno#j*J_3qqyLK+FW!5x?#qjd_kM0w+h6r{Rmbc2ec$86cE^2Pm>pHI_tPc4 zJ+D8nE7q;kkKZRU%dxt)*7n8rdmqc*$J?xA=wQ(W2bIGDWv0-&+!ZS4ukT+_W}Wu` z!-u?Vb#?XTml4a>A6?i}zg9c-Wl*$N`?X_+8;Y>kUO29xewv9h9aQ+)QV1nz=uzyxLlar{e6NrQzX^7WPDc zj#~fietiAfdbO?g_22JaEZzVAu{_)3`k$ZGo9os*4wc{aPHDQ7|N1>8|0=IPk6j*K zcl`Kq>yq&BaHkt3uWdhz$7nGqIdVgS@kNJ2v1miYv;5@gvwptj3OWA&^J)FB=N+T1 zAD=5dYIoyEOW&XA>wJ7Bm_$fjTK@6iqw8~5e%yR~`M0O{i!Sfj+PrS}_DCK5!cV7s ze_g4%`qKA$GyCl`w$Ug5lv*FzAm(JHeMDiWgzEbs6b??2emDgYP%Fq0NP|N@KYn!dQ zq72?GcF^!=W?Hw-?O4V7xj*|eqm0B(?FgQKDelqlv&qg@_hLT(-M{qp`}uWNGk%?Q zm*@Sp)4KTU!t8pL92;2tUY6b;|M%B*C$o&@`_9)F78+XEUAg%FV9T@VecQ{<-+woq zt3lOC9+LVlFfwjG&v50`pX{R+(=KMkNzS^OYFuC~|5{sk!u%Um*6SZTTRA|IDlZ7jvR4_vM-T2X9K%!&wuwXYT(Iz$m~O1> zY?wDpJ#&Aa^{E%Z#(C8?wIG?bLJ`)V#kVg#&y=J4SzH_?i5z$(+Hh;;{=L`plXKtC zz47#01;( zZ{6p<<$g$P%0H!RZr-d5dMy?TLE>-1REMwW3|XoF7FPca{{OD(#rj*C$pI#BM0c*6 zF;(-%&nT-U`q#Xc$F`sI*O|1pcD>BSQgO52mUpDjOgt%YeB#p0Z7K2h<*#{o{J%9n z*r;B5rP;3#hFcxNTF^=+k~3sA!+0;Z zR({j}6Der(Hox=D`(VZ!=i4Je@g&f2K#fymJ;R#0Kee+KY8RYczU|w+`d5Wf&t2Qs zy;ypB+lwtO$9~6IF4BIRuiWGQ^?|~X^<~FoFD)?$ zA!=s57#F8o(#-wOoWEZYj#1H_IR8S@+3D8=Kdmo(8E}8wEcfNA#&5bW7kpVh?^$;7 zl>76i@cdu;^IA!(QT^L<-p6!py`zt6rnrAzXff$$`-!cFerSRJjjLh$nRx&2=aw$@ zaR@(9{C3S+=iePKJI)^erf*+d`SQn%z8imTS?ztXS>{4&=bf*?=XZZxyuAOIo%}5R z)H~Tn1O5MJ9}f=?-(4RUAD^9(UtL(ZvAph;ivMqaRkMBbxDHr|yFsI3w%UZZ`HX9( z{=6OkC%US2O@_8{Kz#VKSGTXlZCt<9dDolY52UvLc1pi>`O&oH;e9V=iJuRe&wo_; z+h4{1S$k{d--!RA{5ia3+r=Qp8*VZ;Ss{f@f>7g8Z~>6JO#ar=bvv9tm(}F4<*dK3 zHujf5gM&58oA1Z&yl=hG_qEn=tB}B^@Txgy_M0Tie_P4$qk~xs+JXz^JhP6W;`E>A zL6@i2zY^WQ?n&~$6!UF*opQ*AEnyX-}UY z_IAS0?NU1{cdcYN^Y~aGw8mS;=~KtOpyZkSuIu(+&38EOzmfX>pyp!!)CXIQr-sPh za@Sd`xpcqz+{MX{GVeMP9OFz!r zuX@FOK9_@hVcK-44UCOX(ix&o{$bxe`@%)hjqB!I-LB>puC!+V&c74>?fmwpaFc#q zncY@>>y@vUubcdLr&Z~nko_xPr`Bix+M<6t@$GqkkLgz}x9k7zS{~Iq{nU@OaX%;5 zTd%j9x!>c<%^*gfOEEtg7}zFyx;TcsFn;$&3Y=T5)CJZuteN^#TW?|Y&sqMtZ})D$ zP`ImT+vi|o@#>na`@gP>?uoj&@%z8Gg;D0AR)OkiD5@~l4IYo_4rol*L; z_*1t;$)D;moqy|8{HtF#cEw2go$=3z`~CWo0&hZMn;l zbS?XjYySS6822+g+Irrn?AuXRU&5yDy{>PY@=xhvx;HCwDb)@vO0=$*Xo zPjULKmH(VyCsmo`YYX1$f4b=7g#EW9!#&!|=f2q8J?Gs10GaD@{Vy-?`THm0Zk(NX z_G^XD+tc0V*J?4;9-ABM%)lhj;P9NKZVkhgbAL+nz5e93t^T-ktr24?Tku<*tBcPR zt*d_-yUMw2**3$wv&5gT{8qendfx=wv+I`z|Es>d{mY)SUw?8I&bNN2I&Y=bkKF$| zC%$`Zp~X;pWM-@r$Z!T0HkNy<=Kkd0WBuaBnS#t`N!wL^Z`3Z6U0zz%ANhD=*~)iI zC8ziGgEO(F{Ued+{O6@L9_|@;ZgGB1-7j8yYkh^zQ+4aC<#lx>b8aoI+OmJ=#~APS zvwuPh|GqcB?{Vqgw?~hX-v7CB^6=r4^<`<#AH8{_bM>kX`^szPyZX2exG|sJ2F*9W zIsW|MX;^n5FF)V?`uutG`uc7keEc}s+NGYUG2+?!9v8LgX%?Fnmt`Fj{q#Oo{g>U% zRvXjJyhkISpS`vAT=dHmYs0@K@7a>4D{J=o`sIHq|GGHd&SqJ`u*b8x9vqSkELMsi zrWw`0z5dPq#{*{Hx4C;${_Xk{-nLx3D0b&@qc?kJ>sY)D4L_)xEX5>n!sS5PKY#n0 zU7KraYv(>`tp4XY!)$v8*MVnFr`n)SE@ZN|V-|?F+V|+b->;I0*j~jpncM1C_zEG#%k%#}HvVh8Qg^BO$)D2QNxSyGcDXNo@XqJ+ zTOY~%{u2=!_h=`3>co`+&;EaWZ|C>P{n`AM%+1{^7;?1%>2Tcw|tOr)retdK^@5RT*$IH6x zz!@<`;lrn=r+LEo_=@iSR{wlnh|k<@1;Y+bRwuB_8JNCuoLR@GK*kS} z;vtTZEYT&jfGI#k{}`yQY2noP9B=)2x|31;#21T~GF@<=b5j*+q(cMO0S0ziP+)!K zm~!sV)Qk7;-FtU;%C)z#CPpXofA>3NW^`~lI3IM5;_FB+$?h%w%>r z-1R`;@>A-c{Z*e<%Zf7G|L7&RIn0}ITIDOX)t7wE*Vf!Y!yWKr|{?e_2g7QV>e|NGq10vE914yH`)S8X1y zkYdzgxEk;n+9`g}&TyXLM<=TnC|y)2J3M=@t0eg~fbj%}a4^(gVH^RB8LB}qT0s8l zXP8-Udu?^)BBl*eRWeW;uPHmQCfI(f0QvkuFT>3J+dD+AII}KLi1C4{*dz4AKDT+A z{4A?2<_ruB44$rjF6*2Unlh6OEEyO&&UOa)x$|;KaWOD3@OpZ<1Tio$F@P`!8v_Hw zmx?RD7#J8QXF59vcse^P1Qg|`W#*(ZFlbDyop9QlDNy8?{niafI99oKi!n!P^KSM% zeZ_%=*|2$ySg)~_vc+Qq;~>Y=3w*g3y7v37cb$E0Yw1NZjxME+vcJrG%@i;1>{}>W z`Jkw-=KGxD^M4thi>=Q*+NZE!#j<%_t~-97VR~NI#(wujv-IRW2^kMlj2OG#|1q|E z_aNb?+JUscd-J7jlgqu3naO z;we0%z{wXmCD1`ojcH0~5YLhqc1h2|e6PvqW@cA8PV&|B;d{DchgQ$eodE_WdevZhY3BbJtbHWz+5W_sp4eR&v3AsSi3* zKRYMh8Io%a6Ax7jZgy zb0l=@G8J(a`6_&O*fBX|lGStVZ*lwQ&MD1$ZoB+d$W_bG`uWG#l)v5k?djkBQv?40 zkE?#~weWwbC=+N=P40WnaIL9(V{IWbA_p{-16CicpQgX}%cXU{*mtH+DZEtR2nNUWX%8n=ehIFa3(h1cMVRO46+{tO;|yb zC!pi{7xy-ZG+cDsld{L?S^cw_>C?U}$b!g8aIzGgnZJ=O@n7llZ9GRxL+;HLVc0hZ zJV)oi!O_Us(jd~n_wz>5KiN-;CcI!x&Iuf6?th&SBhuIxz_f&6$@@j@U~vJ^K3+ym zhU7nMkN!FSgE^xDB<#S}Xl7Jz@8qt*7{u@=eWE^W^(~Wv0&7B#-KH7;B^cKyf>&Rv za`Y&C)|ad-S-q5@NAI4LFD$U#L29SiH_!O5!MyGvc$&ml$sllseSrrf11ESs7vxW2 z(B%B$FB^~kap%n7RR-CVA=ub?>`$XR+SWD?Mu~_0y3gznF{}pPseV8}aK?%=@;jEG zZtQCiX%PH%Bk7+q%bH!_34b2p#?Etp8vQYh%lLd;>~p^Hf>+?fC@!e69QpIQaSBsF zf4dDR6u_=yV$@{F{dFekUoKP7UGVnJTRjak{y%8&Vw8{(p9)?g0!k{^K^Lq%doKD} zUacVuJmn>!$a3V*ciuH34YiLKN5KqyEX1hE;QVJz(m!Vwzq8;_QSND&QD4m9&6vTb z?h0FBBN5Kw!I<%}xa;S3jv0r*A-%YzVMcwngEwOauf8ihjf#WReKPL)Y0f$25ZJuM zAO~Jxn9gKia_0){9AJlVWd+s+Pd<14oX)TWoRAJkC@MU&w|TIXfrsCID{SrEg{d4K zj3;W$4FB^OXn_TL44IPtz5U4$#Bi&5aTP3iUkK&!U@Vxgef$smsn{hk5bwQEVcGYg zRlnp?iB+9m5QEh};mjsj?z`3BAi{7sQhs&?QjN2vD$hn?j%de|pYoo4a2_J=p z#|sOVB@88Z)GxNc4D7LC`o)^?#PAviOs^Fm<6ou=h4Wp6VXN*8K5_W`h-c86>hqZs)s1Ah%u?%f3Aq;gYDd1RfN>BnNbfucqy^Eo9%#7^~ zb&LfKC%~x>R1^pbT+n9_eyIIg7NW(0!-C}tcLTG_I;f7u&W46M#u*&(k?%D?IY5BP z>44&bcm^2-(7tr=b^sq1mM`1~Tz;IYa)&t&-5HnedAUW$2m11}FjxDM6_kS|)*Y_-+ z2mZ}oj2;0mVD~^CIO6EQb-?21wO_tfb80;H9^2u@aO_^5>Vjy8=AXv#PuUud+=$R* zNN(Qk1`n)dpqv!^quqW-`oGiD_2ui9zjEZ@XxygopqSxB$&x7z(Rn*t6|GLi)&Kq4 ze9nD06I*NQ6|SWWJyKVsJV3q!T}bs@L4kEa@xG%Q(v+Ur>-@M9!O_FPw5BqA^;N-_ z`!8FcHT>^4|GUe~`63OSpO$`|2lMtfCkL(raS0`llly*dK6az`{Sr%%zwdHXJo|sl ze4pW-3rnZR-MXu9b}mhyHDOL|z+TWI1CZ{KiBiJqj;-o(Tn^O*A^IR^fR0hw#l@(}5c_qf3Al`Pc&>Or%HH_1SHt(t z$+FQbOVAIXS71%>Nw~fMq`UE*>jC2`5r+78f8W(U{%BdO$?*8|?pN@<`9_#gli_!Z z`&5u(Mnwjuc^9jny|2A>vP_LBh{5Xf?u;;qi~ew$qC4ota)e-{R&u z(EU2;wftw@pb>Up1t=4RBwSMf8PNF7`G9d{%{>;?h9aG(M+h6w&t&;bFYUhV{S8xR zdNF3O>K=s`%<7>7gn+Ki zSyhm20Lo+z&lMOpe?K$#)25lfEZ$Gw8vgf&k^*Z&&d2L7K+XgO_AwSv?a8#84V-?r z$T$A`_wPbxet!Ojd+9Fcuk3v<%6KcWQ=M;q)y;RH>p;qD)XxS%J?#)JIKzPJKym#? z@vR3ZM8|d?Jszr6dR4#X=jl?rbJ}kk%cdmP+V8JBo4sOEE@NZp{oi#R^EMYaa<4t* zynS7?eABrf2Y#P!7FA@~CBk_A&))a(t0UF;FXx-x>sQ{t8IldXmDmPap!F9I z;`Mj0>3dkMHqUwUO^f^Ywx8ByTK{KyJ*V%=?{C$*oGxfBp8uFJe{%n#4Zn81p7rYE z4)eV$S6Z-gHu^anSpU~}xpdwRMVmu+G>;#8^Ks+aX_x)BS%Yknz3;hM1iHNLLKw@g zIK~re-)i*kunSD@C-I9Y2nhNC%tc>wHS(N{> zUa8mS*l^8XT4GQ7zkBL(v$LPS{+PNOl;rOIylavTiV#qheAsEhYY~QPzib!lIVZl_ zRjRlo|KXv8V!OXj9<7jH_x1C4yT8?~3xY)&{Sto}6rMlx@nGSOYv0@F2XjoZHi$WL zwa$WL0=I*_K~>Fqh96arG}PrlapUH|M&pHwPvNypUpDaC2+jj9Nb4`1iH9 zeipqKey)3}Q9u9c_b!J|ch@yBx~i1azMB8Pa<%go5&p|dFBV+?a(agK*PigS+CATk z-zI)K^7#3q;-~v$D=w}tVl6tca?f0j32*P8vx|S@eP;jNjxx9UAO@?)))`{3*x=6(X)*QPfcMGVS4l-dTx3U%Nj+m1IxqKWNcmS__#RxPcz&5#R6<|xIccq zcYbSj_)hurzvtcDZl(8jDaV$sIgg?p7c5_Hs#pGU>GW-v_9h+IWLo?8N>8xBmnfJ` zYEn$Hiy2C+9>2f4NA*w67kR7l2zzCNdaI9iPc3H$^XyTYkR2b!7o1zxd*ArkrhmKF z?tAk$;m6s1;vXOQSihBG;Jg_II^=8nrR_<_?Llh}|C?WvhGn}9hlDet4HuLC%{yrR zx>@4P{IZ=zk5=SwKdZ^6!5lunI!|KKWR}xKOg6%2&u;JGe15C9>gO}w!V}K?(o+}O z>KXhAV}EY#!I>etvr~3|(bH3%ybbs2B0yPLtR_nbl#>ORoEBIMN*J>)==u44MxNvu zgD+__Ek2(8_WE&6^?PIfQy*U*pT7OoW&VnVECKU28=Q;To4#%5j%lZDosZ{lTs%*G zKA-NY&3rO@o(lZ-ox4!s0)HKs#GiwYudPygu)kZR@nB)tN&x|;!|o1T2R;~vfbX>j zW%yluje+3|w~qdqoqFnD_l0xQA5Xt3e0|N=zm@W?2c}ow?|=UKcU^5X$IPm_GmIAJ z-r4-PW%<12(`UP{n)i<`*q6ScnT>bp1>?*=KJoJ&J{IQt{Qc?9D*1l@n&z*cKihRN zJpHjwx&L{9D5EALU&Kx)2M!)-MoospZ2_|2)@MtDzzaJTH($mK@z46rH;f-|s)&!T z{_`;)WTx%zbz0$Z;wCK1Z~mNi)VKDjX5yE9tJiUEyZ)?b&&}0mt5g}xlWPw9}I9 zbssbREwldzPt#eJ74Z9f{nzk?e>xvuWYKw(deNOzV#~*UT#5S(;%aVL*c)a{-|KIA zcEdgyH$Tg3plagR*RNB4TfF~W_G63xwC`-wLj>h*?w!?Q3SyF(0BRRW7%>GgwDHW9 zf~C3_aV%~=j2g-Rrbeyh+Zwer=()MY)g7;H?Jf*nllAG_>RZ<;+Un09Tm5B&)jb2J zTF13@Q@0zb-(z&B*W4jg-~Neb?ysn=_BLT}{ucc;*gtP)`>|zte-8cZc|Ox#!_Uk$ z;rXns3-{a4vopSNKIY%_gMR;>%xAk@eE#miFkeoMA9^+XH4<<4uqxX9b^N>R>q-rq zh~M+n=keryoe)|2b)Su4?(cK1&wel4vFl#fq3PB3t(WatpBeApRQa2om>)ZAmCE4i;Kjgjl8aH%;1Vd=XSQ73F92ygH1fHCuDR&@`TX8pHVXVKzyC-7pqU2aHUER<4L|c^#IrTj z`LdrHB;PvRBfQzX?Y(5_s^#{Zuax;7xU9&?PcY zX4FS+v){>}!Pxn7^R@hh?Wg`+Hvg3UMb)S3l%Tg$@C?(sSL@##{Q6$9X6cIax(y!} zi#+&k`hQd6=~w5s&S7{~{D%9s^W^CFeU=Q%f8J$W^YZYYkCGi*>m{~CbL&^>UT-oj z?_Ruf`_DQY-t=Il}Z2Xs z=VSG<*Vn%!{#rTrY`ewz4=eqy?ek83oV@bI(e_(^4mZc&6e$+T`YiVD_Vyo31a4HT z&i}3($W`?Ib+KH+A3M4EzqVvAa8*^N3k>B42#lDZIfhZK1fk4yS65|JL{O zKg|)Ec=KS8HdV#E2O^xpmZ zLO&&Z;*I>h=Hu?I)lzC~{EN>U{9U3T5xiXXY2^JGbwL7e{!U6tc)U=!VLpck;|+D2Rj@XS zfgNa*oxzo@^_zZLUfw_5wElx>TWj~%$WNL7ZB8-x+>$!blF6@puky3LhSU|cWjR|7 zUL2Cx{C>Kh4fFBk`_2>zDOfV{zISJz`Tfh|rT=;!UXp3+*`J*o<85D+ZF8~jGvmK! z=l>^jc%Csk{9|+WFSER)b7l&5JTl98ll}jtosLcTccc38y4I%2teV^ZWiJZ}S+j53 z+m!*qmOmCGNY_l^?OuGJ>+xjnglRu3Wddz9p4TwV4r^|FS*_aOaH{k3PDX?JN5QpP z7n(uwlyD#9J9E2L;6^B@ccBOJ-Ghr6WoPei_uiLWG-dML{`0f!BR{X%c=$}>A%nVG z2j3)q`EjNC_2UmO=gTnJ>wR6h|IDp@=|3{}9sBV2_tH6yR|;!BJbq}rehJHrri0bV zmFtV&%xPesSHCTfWkzlg)0$~TGm4UqtvR`S>z5-Rbgk!`7M)5w*J}8uB-rKIb0)QT z^PA$b-OK;U`XAlRQTK*vrTRQ;fgsB>_qVRDXzeQI)8Uf|u*!HR$|zy?)$;Y@SN;LcC|b z>HnJDKX!Bbm>b?tyZ+zF_xEShD?iB2{3N z5ahzQ_P%e>GL8%KK63YOw^jKmY;myf%h!(wwJ;f&(2mVpkjlCsGN)$S{`~2i{wLN& zh|id@UiSyqNFw zqWPJ8YUCIG8UA6mUW^~b_dNW%P?l%@*18$?kE^}UIdrZ5+AeU{Y>ZMowYxYs2|I}`FWmZwcGpJ^Dk_JkI&EXVyKh4Z)+m$ZhT+9P*cS5=J~E^fh;w743D>F9sLvS>hsabfy0CG!g)~B032tW9S)bd9P-}U zPyc(~uHL{^@W6K;EyHN;2FdEQ)3fZ)n4kUz(xuyD`SRlyZ zZ*%&e2QN;C-->0N+F!e5AM@v|JYFkS$$zP5=2e_OkZtLZabeNdztc_E?_kql^3i_E zao~fce?#BTpT_g=Fsuq>u_?|E6a4V@#rB9=|B9H>Q=}|HSQIhz_h_! zstPA*x%p$b1}z*-xf9J3uGrs3Gh8g*ita9D*4~_clTtOA}%lg zTHBpG?HluCC6?9m>(q{XwUzYmyM6Jx_@BGCA8}Up7`>b+VV|27!nVwBrqHTB>kkbH z{o6ivd_Q&Y>9lBvzk$*DeEs>`V_Bzc)|Xw%60_pFU6<$DteuRudt2CUPvB0lsC?F6 zzwT|_j6D`(edS?pMBM zUHIqq{~!G&f@@F9efM&xEeLE#K9qkt?e+1wlFy5nXY7yv{QaMQeh=5t{vnDKlQZ$Bqn)Amhnfma`c7entPB?rf2hyJW= zJNVd`uWqJmVZxvIC}vH@)DtV?IDBGQmN59-$zN|S4z9x+IeS1y!^PwTFxA)_gh}XJ zTmP~8{`cnh*MHTgpZQ-G{dj-z>&J>E&+2}&T4!HdlaP3*TTFM+>V)(5|NmI+KeO}I zs@1QYewDlOZU4AqdfO+@vUvyoG(TEfA|C(qa=^c@{&hw-*2mUWZm9pXuAFstfwSO& zU0c)omF>K|UgWH|uhBaY7h2l?;M26Dg40(n-)D5if0uUJ%xJNKoWXNGD0razI%`wzcczd!ly;)Snw z7C*lA?$Oci=J>6X{}%cDFR=dk)-d|?H#;85)<=is{}sHLUU82-HR0Bl%!L`BypP+OrZx%xLX7NBO+J*gn|Y7Wf$9r# z^M!@7+aCY+iTs(re4kd!p_cC+3>({JCNKM+xA|XfQ5S<3!~5yUPYmiGZJ1K6*c!{! z`SJG2rX!c*z!%S7&|wN41{(eT-seO2e)?B6UE?wlWQZt>av`<>#~yP9rZ7k&5iN7eiHqEd3Td&4Ex?R+*% z;JUTuzjt5nM(6SUyKY}o7#n`oQgC_K-t@CG>cRvIzF#@~K=^a{DbKqJ%@%jsD*CSa zMu|-AY!6#6r?N{U&idfDxz9x!mvl&YS-Ljl)bgk4i8DO&x7l~?pQFn*S&lh{$0T)2 zH)ma4HSLk;ok$K3#usbeFT4q>;3Py@HgP#@UOaj2yxZ^n?K9uniyqObJohVofBnWf zX2Gx53?nxEi`3p*w11}JKl8HH_gBY>USARU`u~M?yO8_$IV!WSuj93yoZX=0kas}- z-$VJfU;BUW-p^fj%=(^~&Q6BoH>=-mh~>O2*X!jL#3XasUGT$p?V{rjXV0;E{JZw+ z@7E_x1+$Z8oH-!>LxXY7>I1SI?|)y9Z@utaTz}!omTekLcIFD~Tss*x7}q>q%rNEW zzW84Y4tv}* zbK|%B3s@o!A93krG+*=gc9g}L|NERDOa06(i@u+)V?8gY{@Sm^2dSU4!)?#(_u+i; zzCZn2eC^dPgD%=wXH1L5UF~gO#e$t8RrD)K+|ROZ?hhF+o+-cgr`DgU4-QI zA3Ih*_#_?vOWA|oh8~+^Qm{d6hvSMDwlGbYz4JWdiKC_l^{0QGfA@X4^7e23A61eMndjb@>*Cua z{LO9F$Lh5IE7o58J((qtX~z2ex2xOY zj{SMrU$(Qb>dv~QQ?CyBS zYyDWZuF@o;EcMTkYyS?;tu&~=c}<{U;qxMZypg|9DC+@Q~rxAW;V$JL4d z>ekLLk_z;<^kVo5I^#ZYTQjIfcu?Lw7~Ule0((WaBc>s3D#NBT%IoDVZp{~FFg`QC z@~(MuRYlE%nd!~7Cj;GCPv5dHwB&Yf-&pN-F3R?49dCEhqYYCIf01OLUnRnP%h3PT zcl#d>U9&cI{uF*IB69wZpVBx@PGdM-(TzhxI3k^H#%(ga@g#AA%646 zF6sLmPp&&zWMLmKCkm|gXZz$zrH;YIdH+YdHKA58@@PO z*Vvy64UcsV-EiLKXULbwlWJn`2FP6dlX?2z|0N7pRxLcW{_pp{zqSRO(_@&izlgzM zldagZd8auwq+7qG7OoO!(pNfg%ic$pt)F%2rm9C9%s$u=3gnvKY{LjC^n{a0TrUFNvt$$zKsrLK* zR{w}FLwDpx7B#=x-8ww?jO%|bmrL`H*_{3V4bzTiv$CD0|1Ubd|HwN38dhhX)03DP z9=i*!`10l2*VB3o``D+(?=DQO_%peDuXcpULi?Yu-wP<+W@9<>-^sTZP)eoRfpv(Rc?fB{-5|N;+W><)Q=hh8ca`^ zF7TbUsCzsAF5CLrTpP)WJB*?Yk1k2uDg5^{AFuBZxz3N#d*`$Noy>f|k}3ENUqk;) zrqAKi{+`$4xdk3jsuTEdM$YxX^v}oUeSDnUIr*&*XwLLm`NcKxffx;@rCbcz`|QLU zw${&B_I>8o^nX*#=P+-`t6ky5sqk*HzO|jrzo)hzukESsp25rTSdEXHdAZ!N)3oov{i)NBB&KhzU(a%<>h)T~Crc)C++E)KQ~1cqhJRrWMGPIPJgC zWiMlhDY@9*{QvIzf2EP)t3Zd_Itza2xo2Ekv#kI9=D(4z#UHb;e77lxVb|;G%x$ph z{#KJiGt-1kZ*y}iXU(-df2&{bEZ{{9ym%$+m>;cK<45&i|chEq=hb?E0E3tq+AcJ|91BCSCq?YIvL4 zm&1GFD_?0lSN`HF$uXOH`}@nSw*`KSAKA@pAt{i$Y*%IQU5nP!|K3->co<;+Rn?vC zv~I&3=7hsytC#!o_OIUm`EA12*~%wQa5cVjWO&BE`1tWpYWLb79{$mJILJ@t>8828 z4gX}{zj?p-CMT%<0$N8P$RZ`uaA=0=;q14VkZEi5n=Oy!RU0b_w zm67>9KleLRl>0gQH5jKJ7H6|J{5tQ)?vuCg|2!A)Z|eWA`YOc_myYjylC;Y!PrD2zXC1{>rg~_1m{GY!mE0@nP zt*<%%A@Sdp(`DjJSR+ZoBK_0v#F)yYIY%U!+Y76n`AeMH;QUCSLiYZHC zIJEYd-qD(7eQ~qly042l793GodQj84Wc%SFh7YxU4qD~>{4#}0v?t#7<(Tr%_WiQy z7h}8yKb*Pu`%krt`@Qcz@~RBp);HgQrXtI0_0NLalnN{@4$%S`0SrZZ^R~w{ynMs8 z!C}+6O!m($56z!2Y?zVjb;#tj-Fd@{-2VOQ|7*Xlj^}lr!2IEeraJroeZSvve><7$ z&(*mlPj{9LJHxWy zC(HL+v)oI3{P&&t_V(qbwG)5Jhs+fGbC|FD_e1lX8v-@g?j=6Bw&(4!{^s)zlhs^T z1gZoutl0nH&*wvrx7@4nj<>aHom=nmr6Ip?%9nNh?{6RY!};RA?0g?ihWxU`FE`3> zZq@r{{B`Q`mLK-J9;qKRn$Ldpk7Gy}M~N&`U9SD{KZ(B#>i;iF{c8E_{qKqP+du>2 z(SJ;LfyTZ-E1nD;7dSGWIIHxOp+L?d>C?3)*Q^zbUTbJFmgzOD)=T(TJ>%sp0i)Ey zJJahxSN;9zulsfR;Ju`q@AGZG_B`0UZEN1$T@N;2ihocI)P4mcu~Oet{Xsv|IABbH}xR!a-F6OtI|^|9|%h9q5iJI;r|l(9M5m`kyJuE3eP8?;3-xSky>2-?Y4Ye;mKX2`bOI|jI*+Hz{nU6vJ@=nwI zds)YovkyPsqS~#&HSI1#?Uv1z_mXz9ZsxNxIP&%D(aB8W`f)Nf@7Q+yez&{%eEyLq zTs&9zgKF#gHCs0?6XRn4ncQXg_h{L=L!InLe*OxWQSWS7arSpA|1B3M zynEXm-XQac-~WSemljTZ%k<&%1bvnkhv&);dJZ>z+D|>0ox6PN|4sS^W?zFCjZ zYQe@nd<0KuG1P?_9FZ~p`tiq_zl#}`6f;ScZM&=#HDB04SDp8m=$FR7AIhBWX8Uq# z#1(~b?ETE=$J3!ZT_;jV&VqSv?T;y&s}sJz+Yvv{wB}I&$EiOSQGpw-)jyf&-llX; zHDZ&BmeBP1(%=6Uzm|Xd<_q(krmg>H%~f__EjL&q!!ZA^eWuaEgPTq_9g;i!ZT-!> zrpD8pPFLTpUbN`r{{I@!By1{NZ1@|>KnER^$TJyyNIgC6ZSkkGM!#yyHifG`eiypr zI3K8lW3T1$b%l%ov>eD#oDj<3_xsLsrkC~4yyI6X|DD6Jf4{Te&VGF0Po#2m z%KOhN<`y#)xBoPbJNLb3{*UGJsJ@}N=vqoOnOf3anEv3oH*XI`@7 z%q{z`PZ&NFE}vzz@p4{r%+I@#hF>_MPH-_QUUrWAXWK&&v)R@k#tu5|NhpPp@zC+p1@0`At*y z`)}SM%l){s(Zu@Prl?a zyaKlXcQU+rfBqSh0Z;aiV;LtoKlJR|W@_|#iH5}CwG;39*GpQTeaBF7a0uA!IIU^-TQyeoUy+-V4Z-(caDyW{lEQVzBm2bKe=>j5v-BO(fF~`VI|Xn?B6jA zb;TKG;tSH$zb<6BkiY5J7wvYpw0Wn@^SSz`94@JT=61|akKy;j^eD0apQo*MurHi$ z9Tzy^a=@GI@ftSQ-c;ZFeb3gB+5i5(xB1QSJD)yFSiRm(_eTG`51$hDf1aDq{`+CK zy-?24cRC*;|2;S&`CqZ(0spt3o2SJar@gvda3CQwW7?Yf@IA*%pEE6B3GoSZ;B3gW&wtMRVfOhirrA#M zx7XJAAAehW%BWuY*!(ZkrEMQ(GCr8T&pp3*(K)|&OfNd^neJD7dwD^*Tvy|_{dd-5 z?w0CF%jVDi_%TZMx7g0DrTc%cNRD6NtUm4V*5GBkYkq#(v~tUz`wuqpMX!9mzj^JJ zz%_8!UUteeQGpKi_}e?_XFx z*GU+(W=xHPX-@a0H?Qv%dE4AyGT+*DR_=-&eW2A#?lo+_POwtsh0=vhOa%wh?WM2j z1nDt+K0D{f^wV+6CB>fg_b=V!$f*#0FYlnToGL?VLkz>WtDC(SJg8xO-5$gEOY+sB zGd!m?7s#K#6TGwf!)L#%X7)Ax%yqfn*9im_ZfCf}ce;|Hwtr2h>(&Y-$D?JTf6ksi z^5>ve7)MVzOH}F~x&G^W-<6iS2C=+)@S?(<%i(yvl5YUiT@JqmGa?x^W;>l?-4M+r z{f@0bo%z`>WoyZ{ZlMW}5gA91&llk^pO^mU zO#dg7UrT=Zv+&7@|2cG*X~wUO?V#%b{6%M<7d5{p@@M=0&vWfceE#fSzqici*w^N3 zJ{PSXp3VOj`l;37x{^W6vG{L~;sh_~wHqBdwk?k9z>P=iFT$&HPNuJ4HnnO_dB$Y1 z?EV6l0}tNz)Y+S;|KBLaf4G(L@RnNZc)rbQd})2}b$jkkzpNMTZ&|qIyWP_>+{gOg zKliUW{5v>NEGDb0D9Mj=M%9r=7m|)EXE(S0+#J35#-^KJ@5Fsy_j(<-Y*To3b$)!l z=>KZ@c`XMx6elGATXWNR&G~2V&;I%CBlC6M&&%?Uy*L>rp4$|} zVD-8>!wgnHxv@4XYBM;`likf4z!AW7M`~yK9)mk~cFgmf{&QztLfP7D(|f0vIe*xv zmV4k&ur0H-&7a?otLIE=O8EWfW#8ZbwzePj7^Y0suKTiBpy;RMa^YKI+?SUdOW2!D z{hYAv_`Tg(7PcQ>Bri-mH)%yoPOR`$?(1tZr`Kg{xP6R~|I}%n_l-^m&i9Hm8a)ZI zpT%+DK(wrI8vo_*Z)iKC?o}Xj%`29au{J<5^JtNoTs;B6+r55+h z_p?3x?aYFno71lv`^`N2wb{twuVObpf9%&8lP>iaO_p@%a$u7XEmvV$bFx~k|NN4V zflMD(e!uqp_3NkQVxWbSXn~%n&2Yx3dbdRO-)-OcAE$;hbTRncoPUA+ar?t0&Gedl zTju5Wraumzzxjyad87GtL38H1J5(P0S2ts6^1mZLzaRN-@!&Gw>09=7{ik2m{_*GU z2;DAtagJ{4pKo{nRv5f_<|f&}G+k)Utatr&G0gVs)vq19!z>=QKqO#ZFxwub13S6( zFRx=}-B`Wr}e)2aTQB?+cZ_B@P>V7@2bUi&ym)my=H$zc!_ELr(-G5TC(2RFr zhQb9i)`YEw`<5R2QoKL%z@N(7Y;JGQeN*RqExAFz-SFEbexKV+feHx^BIoyQGzi?h zGWOW=nf;4xB7ga^HrpTgP+7l7LqGbrJLihfpC7L6Z-o;srg> zI+QuzcAjUwbU2Tpi0M*ZgS&ih@iUnQ#eIxD;%YtpU!VTSv^dXDY{z2|KHnfZ$M}uE_00V4u+q~~KBQug z`MPdXZZX&0_v-pOQ@OLGtE9 zg$dEW&l{EuZGfmTt7JD>>n_*INa`mya2zWEr zful#2DL0s*qO-d9rjDuF^lMI>4V*KDCTw~Fy3ONr%i#iP34O+M*WTz<&oF+=`T1|f z{o@ZW^M9OTo?ZJpt@c`<kspqw`fV&i#_Z2ufBQC#evHqy-xfrY!kzQ4y6la ztOw4Eu_`=ex^c2$>c4*iQJZUDdU6*0eww)NOSGXHEAz5>(I2#mAA2_cxFX!Y)V@ak z`Rk8?5+6?M@aT(Am!ALg%CtoqF++*^6yI8vH*}z^Sp>AWi3^LEa40r}u>1cfLRVXP$1quwYKhmu?N}m0_?~d^wna|7TeA_g)wLzre+%LIVz0g$H80ZLE<&|gdka(tcNB&W%ENA;; zM}&gUX|P^7yy4@_?v&+Vr$RqVkrb_k+|D&4vmMF^} z`DgDW?Y|y)@-=daU#fAd?&mq3;P0iVbfpc9hQFa;8#E8^SovM7&DX}RaLvr%bGNGB ze%x_w&exl*2AW3auiPv6@c8My_R55lwh3{pyEQosxIZu7k+l8h!|OS|yNW7OzD-&G z;M%d9g>P%xH5shSZtF3wfAHY&hs0x3o=X@#JyLyN?Z~aY>EAMQ@6D(^fBF0|v2TBc z4{zW4|J531XWJh6RE4kILJ4mJc_i%L#yyyJYK{^E-yVK1hW97++AFyq)x7<^kf%cR zK*9t;CgmoE>^}y7?R&%Ia7wy%>_*~`R>S9~mWb86zf#<9y^q1m zF){M@nf&uMNz?4NA2+>{e^10p={rM2$La+vU#``AUHhjkI=g?b+oW{4?(9F$_2Ptf z{rR#f_29qb@qe{$cpl3r&%Y<|r|Dn%xt@P@W!(vhws}$Vr=OqezxJO~xJ`35|7E|P zIcsX;^CN#5{A4R}Fv))PqvdB&%`53On#`h` zGvy2_vJX^$ocEx^fB%s}KZo4!>jGLI9jN(riL>F`q6gVNd(ylPT)cWBrhG#f@8-0+ zzsGXs*Q)tFjEt_HZ*2a{p!(MCLZN288SRnhPe@J|H=RAh_NiES?U^a;rzFMaSAP7w zR(Zd02d%rk@El5OUkCX+e#{ta9rLLZjMWOE(d#{2R4&j*Je*=%e%$<!AwojyC{w z%-R3n@kQ0q-}j{3KlGUX{MKqdn`!fHKQ$B8MKg>{x2(5G_B#0F$Ko*C6PrHGH&Q*g z{^@RUZ=U%-gZ9_u)^@NCeTrf4a}lQU za}HMi4Q11qC!7;hP;V$ap<3|q_Pf36({yShH>|!Vy#KhQ{f}y;)K-Vn92>5^-~2yv zcl*W58}*Mbzjyrc@7w=7roYu;dG&ww#mM5zIfx#ppwj`dr0DmyYkyw8A|d57-}L{> zH~Q_CR%+L?v*%^T?|!>|S@aA$yB>M_^uz;KHh+tour<#|$MCVp3Fj?mnOYtNZe;%> zXZ>>R!#hmZmgVkP!cuT-|83s`QudoacQNb>7dXJ^s=Rl7Eqf8qj@b{RPP6X#FfEiv zbnWc?Uvb}JwRb1=IV@eTf8_d%|0TgpaW@2iD|*k{S}Lu2{EPOn7YBt|56==kD*Tb< z@F~U3NrLh^rXCX?GPG)=}Y(Xr{f z^#gdex%}^W{cq-k#K=0ipZ^ZO^6B*!Jh8TN`!2P3s|nl*Z|5hy`?BNZve{08J#x?d zWTsX9Nqd{I_V4q8+_HJfvfDx3NW~w^SLo!qyjsf8!?EU72(+E%kghBsp4M(~oadmI z?Lrn4gKZ*$^1pO%@0=dZ&|CQQ+P|Cr@dpfI>kZ<%68HVs>VEyBgwFoD(1cfIL2{1! zWad}t{7tEyF=wxQ*O4j8V(n^m_dEp`IB!nv;a$qGw56`*f5~ait{=~Jx;|SzfB#=m zWNpR!{k@@QE;SEoPF zWIwQ$^RnLbyYD4+Z@%m8u{W}jNQ;{M+@~h_-x9U}`%2H0L*Z*;PKGqCT~nzNA))>^ zZbMF_#{bTv`|tkwpZ%}(S^I*$|6WwTc=+JpmC1(^cQRz2mD-8Qd zt4(KMRes8J;lhXYYr7*qi~oI4-!jYEzs_}obiciw+o6b!yL}id-nB;j-*fZ1g}%bA zQ|DGNsJM1~7LZ9^e{e?Ptv@jV?`9f3wX-|7Y{kr^fWqIOg%5B4w?`>J*}S3dWbB5D zGR~0e*R(lUKX3ggJo)>X`>$3{+kL>2op-0e>^JYbp9+Y4lM7;Eh$xHaFqxff5W?1< z6mV_d`H<`&`-u`v>;JbX;7&&s5?b`T5a`)Tw#+Bzwq@wxaCSCj28+kA% zP%LQwF^R-~2G91nUyC^YF*NIq)e3Fd8+Y@4?(hF#dhEr_x$El_%3`YT<(|ni%D#S$ zLABxAy<<~9E_z_TcClQ4_LcAQMFkwTuR3!N?t47=JG%Hcnjr|%ipT>BLHIxf-2-Y{nNd*@>xX8zlItVVMGaX+>* zhJU4GZ~fNYYFhB9I_ItUv9H(q>r{A3fAZH$yt#emf7j3XmY;Q&3F+KD{3r2G=fmhN z>(@uDb4Yqpy7yh6%K`P!&$e%B<2EV3yFdSrkIlvW>2sfiZ{97c)tdTqa&f{*kvSh` z_|?>W`}xC;{f&Ii+mp*5P3TEKQ`Tiz`=PnTDA5^q7QoBzi)9!(e0R*>`ZX)Z@MN7_ z`D~#Fwb@|>LP~cRZV`FIwc#$qny;7jB5!{UxS>0R_so2UXY9r1^Y^>ABuan#AKYlF zX8H1)wdTaP2`oit>enoLBU!v#l=1%mh`q~?*5-rDw$>-lFsQ%wFOb3Jv;K)!+kZ|tyYGHS|}D}KINZZE6cvr{PvPF<+v%2KTfdfN&wI$cZYwiC$KHQS=eE{=_KuhO zb348;X@j-z%F1;@_Y1^-|Npr!#lHCW{Ie6c)|Gi~xK@88*w8%T+h@b{gwxA99;QO%Y*74Cb0cx0T606f z|Now4d`)NP3o~rA-6Lu^)H|Q zF-bgLBV=6q^vLG4xieNpziwaoY{viC;N>mr^0vMC6S{p{%0-}jb3w)=T?``xhX@@M2#9|XUz3Xiotv;Y1S z9+4^YZWh0K{2}3vfxou9rh@o_hkC5HF7_MVJhi#7w{~Uf^Z##m=5q?pVK%sW?SOjp zZ{2Ot3oI10*jdlq_?5bLzE5MZ&&vx z8Sr_XRgr#wQ}g5VCr-EL794E-_~ewm&YSfdeY?sI|luIY%#+{MXe7943n}KKMCE5L@wkO`EupIeg{qyyf{5)TS|KE7cdgcWz zYroh!iwn9kLV)RR8v~1#b^f`3_U9y0Z{D)!F$LWfwm*59C*us0oq2p~{%+oOf5O-N z^lP7)uHU+4pZ%}gxASjoZcpAm!{dLy_y4|dbN=k)3GKJ(G@?%7|9yQj1K2W?W_puwmTZazOB%jF;TNcznUF;RZ$Z3$=Vw~Ojj zn$6QTxIJa!Zyj&>W&0Bx_pIfgru?D3-A#45g~7i+ zAL5SIBtMhB-l~+xyyli?f9qSO2jA@Lztz7wE+_SlX+zOFy$64q4xJNq2z>bb*{=Tj zJ?p$h*6upASEjD+yVj+}0xzUktaRBEIL^%f-_pzZEQsM4OBpYGS~Evb<1AxDR*yj2 z!|MjNkH4?Kd|t}JtAVv((%kc2?LU9lUGl7-#(dz`53b~Y`!|~wUHh}%M2-I+`|D+Lo?Z!Vwms*!hWlJx{hoxK+{SluE2>*t zj<@W7%CSIX!G#|`PR*&XJ7jWuf4|Uyecwd<*ENW~F*;UtCO7cpkGrcM{rTxv)9?At z=l{=buanljeZT+zL3Zc<0zwb{=f_=#Z!~E0# z@(*ykCLB)Qs4Zc~)%frtopMO7p{+P4+w|qrH#;0l9kNkaQ@ZrjN4*LUt zPETn_&*l9yD>{$U*y^&xb8lYrd-@OaEg3|&f15XBU-G{_%l`Y#xj&(d`Nq5MC3}9v zvYE|~S}V0HW|!)`qyHzYow%66VBYr7V2NqB{^Zv`XcRc)S(Ea;{8f39_@Vzl=G*gp z{`XULKL0nJ|BE!3zRmNLypeQM;0a4k)ca_@v*xOecNt!=$N&EK-KlS zWMzt44r~DJbKV@i@czHQavu)czXdJyT>oyvGvh1A{*I`aZT#LWJa#ksG%lRpHMf4kJGKq?BW|8QS959R7n720S-72JG4|ot{=Kzf@Z(s+ zFZIDk@x(i>1&m%y_3t%~2lZ|Jk^M%+?c21DpUgAX2uRp5Ij8%XveB> z*f5T4FKBN5n%(dDpW3#jp8n;3s^PSp|IPmfVrxowT%J+?@y4!zqF%$lpWhs@|Mq)x z!l#C{fA42}zpy{0&c?Fu@8iR--RXNl?FrmElXYv^)-Km z+4Jr#mwElKF5phW&e;v0m2?_n8vOUY|GTi|E<+HDlt4(MfQIXWyJ!BlN#`Z_{Cjys z|M&7~JGMn=GUPS}&gEc)1jP$IP-4j5b350!VwYiPoW5agUHrzJ{8yXB(tT)f2&k?+jQU{87EAE`H$q_w~lh+7~gaACJCs;#ynb?~3=;$IeL^78+DOTH(%l zKz;S(ic_^RcBdE~PhkCj`~I=$yZ=t*ssEWAxtW90?AZfx*B~aH?+1+kzPV-3Q#$GQ zlbZdzF0#oynmj4^e|MID+rfPwDr`LSC$4q%-yF*}=g5t<_g}u*e4dYE;^vR*e%Fit zsoxSUFI@AdW_i<@=7-aZ7~ka7pJVpe&b02i&(U9Xmns>q^?hdG5@~FgE_jT=4 z&c=6c4QqZ)tm_s``L}cBXa3xG@y}v*D^B%hln~0vg0+Jd>=rC2+3+#-R1t&J)P^73 z+}Z!8?)-SfQs?)-zaDd#5B#g2@&D>H?hD!JXY4c5*WUke=kvmDRrlkj;n$|r?!VW* z@bC>=<>zH4r!1A{)oG~nd0YC-FZ{5wo$>Oy@6|KjGHJ|Vn((`HLz2(j=tp~$E=*XR zxSMfRv|0PYzj+O9pBZK(O#UVr+$Co7JtpI0&)mQLMwi##?|lDt%iXvi%Wmg!zi($U zNI&`LL4NG!ZE~7ZM5ZtnG2PH@nB=r~>$$sJ9?vyOTIaGG{QPE}JoPD42;YtQ0g;LZ zc>)s0&)lzH92m&7grVZbQ`n0884MgLpcRX!7$f5An{LWIv$rt!?YTey@BC|19L=}2 zCm#HBlXb&$bCEj5uD5A3H!&<;W}a^=oGx?f0jKkkuiV&2K{<@ml&PtxU1@M`F=D;U-XGjZK!Z4lc0yzD^fOu6L3zu`B9 ztxn#1eBkECYtDJjcZ37~v*c;0J#ewK+qSPX@Pq7u+4H#{L2Z~{_M=AqoMFW7bLW0- zXV~W*#<@T_y*lFe@;m?PmP9kw@-_U8`LLZ&HR1ZB6%IaTtPfr-fBddH{LM+Tv=*z? zGL2RiPkahk+_KN^5B_)WTD^|Tb^o8MYY)~vzLCtyDb_ZV%Q*Y^%DNf+8isQiZj_WSi#W4Yrma^xS?u?h zmxb5ew%4oYvDX|d3OI1I{{9k{8?s`&UcFD5LINx1)y!J=EjM zgN_{gxhaUj!3nky^Z<*K!fJ*I%o8>gWPjIWKQPtY=zqoS`Klk6zmt;d(cJiLPtsXs z#U)9+mOuN;igno=s&8wakGxis_~1s&9)11p_M3-(oIaN9J9DeTn~(a|c09cbhor2h z71`Ur-~4QT8S9N(`}>pM&i~Xk_xyp1DciHQ=k;!9J2yx2eMW}qZ}~kN&-TTO+2478 zq_gk*O+9vd{W8V{3_pH7xvkeAm;CRg4a0ht4c!O+&Aa+cwaarl;P+G<~4%l+6{ zbQF9zfp;6I8U;>hF<8H0Igt5;VTbASHW`NK;x9MSA>OOMs&VBb} zGAHjf<(yZ$2^|kJ*zy|MTe&-yc6R*89Am{{P&L>K6;!IaY3NFQ`t9&AjJ% z=6|Pp@`U4ee@^Y)_WQuM|J8T)&Xk&eS93+nQkef4K0jk?i)_LR?P4~ zZK81z`vEyVNp}}c4ITD|$^#}JEf@c95%yc45g`#3nXQ$Yh{@? zylmEo2Keh8aBy6cZKgecf4w!n!7f%D^lC*ByLYU(3J#rm)cm z7e0sBhuu%tJvg)ZT#4$%*2bx+5BYCZh;T)IPS>alj@g{%t1-(wKW>9};w7;c_wRR2 zKKYbk0ZRds0`H$&^;V1*iZ~qh1Z|yIeL>+x;{CGI+j12Xw#{XEv3U1a>xCI}3Lc&Q ztIfK9{+hpz+1~>@oEo-Xc(sf7VmV(wB zLaMm~JKPq8FrJvl@gmW%bwS$i{k7lfQ~hj&?aHMS&dyM?WOyF^|M~>(2ByTP+watP zS6F?&Q{0^TcCQZiomu_6KAx$+w1i`CJa_xSpE3+}!L!r64u1BYc4e=#9{U2l3=Y0i z&e?zVYn-$B`^Df^8}G4%+&6ju{eqVr5!PCM_MZNpiwE^y+i%Zq6*l?X*+|!oKi_jf?mBb;g}MPFXa(M-&IZe4jKE)z2yyWlkMMZID9BQD*d_W0fV1q zYfK;aPffMAO#gTIPvr0PdCz5veP$?aXJ8Ts?Qfg8j724FX0>6k)QWR&|NE;m6qVWD ze7)^kzmS7{>bHNqWz|dO&a{u)C(Lzumi7Df?G0P&3s$ec`}kwAPv=h!#?0#sU(apg zUa%>1?&{9G)%PVoOwC0Z7Mv-VR=2%Y{n_7NsfODhzLx(}P_aJp*q`|^>0RyN zObLI=zSSpgXZZA2sOHF0rs{&Hme1bLJ_*|IA=B7->W`xvW_I49_Flq6Z1x#FhD#H7 zs$MXbKgYZv{@ddD#c71*Zht?n0I%N>J8R*T@JJ3e{7XO z$7|S^TskDb&(+wwxR$2zYGq?moK)x-%^mcr}h26>UZ4l z4YN;9N;uejm*MucHM~z*e|(&q@K1yBfz0CB|0mCxedfORv%~lAKeG;7A~3^(!>8og z`RUV`7=+;2M@;~7Cor{zWe^x6B!A=48E5Aob&d4!kV9tlXo6w z_&+7skF)=N#ZzrfF0(Wz5!RdkQvRoJ{+Bq#;QX$8Z08c^h@YQwe%|2+oBzlDPP@Cx z)9z2&&)ZuA87sanTJhq|ot?%dTdTglO0fQGz487324+5v&wGEpj_3dO;KTC$Cl7JO zo7C`2*mE@)exLG{fAaBnSC1~}x9f{$iTzp0e(dMJ6i9*JI>Ajr%Kn!tvSzH@pk{u=7756pU<;bU-DFE-JNu_D`BVfgAV1s z6`z}pd+Z}FtFM-~zpl!4;Lgrs=M(bt%i}h@w|lW5A(wM+0nh=r!N1soujo;l4(>eut%`_j8wZ zHpQ2=2$bJy+fiS8?v3Ta_=Ljian-pWPWDQyet)F=$@A9e|9(G@WFP*s@B6i<2S16c zul?D6snPy`ytk!S!_@CN-Cd$r<8H3BOWVyAWB-O}#mDcbMH)_Svu=r1eEweEU+d4w z@B8MrU1%1Nc+YX*%iroUtc!w4&o;U@*B-aNA8D>y#HhFLhw{cdzpBq&t9ZBP^1J2R z!@Q^IaQdgXCyVR%c`>VVzT0+}ZOy~O9Esmj_wj}w_|k9l=|lj_=DEh|M)!{%tMQ(> z{~`P4#s8(|_6TlNdDKUn^BPg8QAty##~%KO#LfA2-#7uMNtn4Eb( z;rj9Ux04Pox^eE@kLPFpANgTiv8?K~MKycFU9N}%yOyuV&zB4HEKYo-CBSsI>A)7=z1DP#S4EqOx7}(%;9)(Z}0VM3w}R8{`*Ze zX!+BB4Tc-H(ypy}`_H8O(w!+s+uH^26-L>3_SIgUU-Nyp^UtUDe-iKVocnWSdDDOQ zb{U~J_w7EqY%uP((z?MeUt2>>UHvhOH7UM~xOpo~( z&;N<8J=l5f&%y5c^B+JvS|B@h8#x;oj;Q@!^@d4dL5?|S+o>Ppikng<+1FD38}GZ% z>R@^E^N&3@)*jok{=T69t=+%(-ES3;Q2xCqd~H-{xSxHh7@Mbz`tP^->A%j;x3>@3 z`#m)9WX1EwiJZdrxo4&17MrF;YO*(kMIatN*&AeWB*p zd;6IfCdU|BYMFfB^J|O1_oM6UbZ^+*J3OQ6>CENMmA!AiK8}yNoLcG z-u(XjU*PxMi{fvj?|o=Xc)$1iy@a2B8jKp!HOB?E^xOX_SDIq{ul(D4K3Deox1SRJ zf4vgi{M0-pC+XjxhR`)^`!}@n7GC!`fBF2afUvyn+EIzkj+`IvPkd7^btU0nn8D4m z!kTX_!cLrBY#%MT`*v1Md6~`2??snYpV=BS)%pMY``n8Acl=m<&~KK|`!t6CYYrvs5Y=Gdc~Ycs z>6U%Z+^TDD*2Z`v3O#grobj_g751)A#ss-M{L z@!MF;Gv4syjd64Rhv@rqZ`Lk9I;U;xLFs@pp7UKl z4eFnrytFS=ymfBI3A_Ja>R4`^cRls1{bO>c_Gam1Jw}V=1tP3mZ{9zgnSSj1o!~S6 z3aVePX={Dm`l;o>4F!XkW9Qdc=boKkS=u#~>4Ijw(`QIQ!Ki4^#o$b-|`I!DcJSeQH=JRUx zqxU)ASA@p=-ha+7Vb9k+GcHeQ{uVrbp3zP}K*?y4{-L+{VrS?Z5uxzYw}XL%FoI+VbV|l=VioT#b3|3!-QI|Mc|q=>=u~i>9=0 z57TE|V7f;{7c^1~+5;Y=5a7@M{iByb=aDHLtrsPgJ$>dzGbUa*R&u(C;e}cHZ~k8O z(}DimzWJP9)owYFdxFGv(}vE=_q3Vjot&TZcT=0cwY>Pz`gJb3k5~13wBOHU z32&&l_HDPk$n`syXIXwuWcu;vPC?PUw_FKl{|Z=hZaTi{&F{|T^TpQwH=Q*X14eXyE*#?Vw{N)MSX8&AGAb;D#H}%I9&mCj@ z7dF%W@)S{~$DECMiT~y{?ZmwHI+L}*^5BfJh;4sOzCD&^er5VBei_RJ`N-ElPFgLS zoP2D}+{G*pCdc+GIqZL#Q#)gB?_*JB37a$WY42+vCHy$aF8*EajB$#%H`QvxlMT_Kg)E6XKGKJnQb>L%s{3NF|Rz@8(L21wX_I;?;&+}6n zPA>DATYTW3%PFo#&UOa%%4cP~8pl)b+Y1FTeCzGcf=#CMc!O3rfcEM#dsaR3j_*3% zcg$yx(1aQL@A7dR)^g@&<6i9h@z{}sV^a?IXtw_h?pJE?uRWZ{_*ywCtB-0RKx>~T|;3;)+J@aAL4{vUFFJNe+izAfteJXvL!ifp znF+_#p3PgCzf+>^tj&!3=PLAE9KY?qyENc&%IQ^_%*zD6W>eexn$W41>d6bKdB>sbz{ ztW4*XQf(+IV!kA$*>jpnYKA?pE?=6D;hFhGHLr@#NVmn&82(+_RQ{mwD`d zzWw-)zezQ@lfG^_`t7KETK0c~|GVPYWxmHfczf9Gtb5~&t>$y(-cQgdyJg89oczwY z)mn7fk=?3UW$8|d>Yic0d?Xjxe=nYQ@Ay>pXZ{S4|IfAm4DLyt&bM!kfW&!@jI;Y~ zzBljPm2O0Xloxc8-G`u*iPw8x{;+2H)7hZGlpwH^bTTAwt_(UarB`>pt@q*8NlA%5Gb+{6a{ihc z)Xh-#xx#pKR=w7?x~kmywokRM*$BzWZ!rE7zW2Fp2O}7Vykin`6H8z}z(*kEUMxb?~@CM#8_a_{S=a zk7o97-ThB^K8JtOzqx-lFWK2^!nEdZ_SyOj4{t^Zsk|)Mf}I7cK_?Mz_+S5nzftS% zucP{GeI+tHM`y(Uw>iz$-gs+W!xEMWcm1qq^d02!sV1I1<)&9d#=1)66ewO1o^Sk1{VZDU?@4wojr|ry@yo-w%KD^(&TV!3u z=h@DI_y4K>KFRz3)tMb)_dcH~-l#o0z5lLX_*`r2Y5ALOGyL55=70SEj5Wvm;~0aF zsZLkB;|mlr;ms?VIeADfHQ&9;GN17};Yaj$fC4ydJbvUy)C>p~8>ji5^4EE6L-(zqs4l6dr+LUu0f|zU zB1;X>y(=?LuL@o5R^oT}-}l6ypPr`v_~2g_d1u0_r3^frW~M^mlhha$FWlwev1C86 z|684^CF7df!wQN2<~bhzBQ0U5zUJnEt-2bl#ZH_bw|xJ6T9f;X`r4hp+MXH5%TGU* z$zI&9c!=R+r}69OvA46*-wEfxwS7Fl>WSdO_I;+=$^KYul-@VoTcXZ zob4??UfX>$oZV=eKCg6Xvqfs*w|}<&Qo`H5X9Tb$Jm7g)yPiX!U3WJ7*9RW|_r?3^ z+{v)yzP2v?Z=1!WpI0TP{rJhJwJcObQQG{k)cHLd_V8aT z(k%E{`MPY`AmH%*}V79+xhfVEPK!7u9xhywH`6| z*c<+B?|mtpzJJ%j53z-ThO7^yZol`x_CJ09cU!0C)U)&DS#n|ntYr#}ZZF{YA;V~| zcIK{eWsQ9Nv*z75<)Vwz<2(;8kbmZHT~j1?;@kF5rm;v2YQxt5 zCEl~QDxcG4Eb+FiJ8ZL}L2y~!_7?S9<~@_I{dgPaczs{vPy0<~-{vI#IitPysRZ-W zCHv>g$>l$7zIp!6Hr+4Z-zc`<=vlmQ-?{>Mzpop2q@An%b~9jhfBLmK(hj>{DQiZ(yJu5f- zT=LU#YwmoD9(zrZV-n?eO1Oi&#FjE-Z?*mLt?teD_}s1&iRyc7T=xBX)ZP5Iez_0l zx3gu__Ll~S%&)eyyJh!nUh79a)){t%oga(FlIcX(EP+MG7i`q$|{9Y5Y_c^d!U%JwvP z9Tn=W3>=J#7iMzw>|i>Oy_luuuXlWsvcn3m^tJQsGm^`AKEJQ7 z=q>dvpBUwDTjZ(n{bT0ZsbQXmEB?!Ne7rPky`k5)=kEhKlpg!v{A=Ln*RZ*8(#AR| z5uW2BwPE$M+DluCf*x+|{TZLF{`cS?`8j5$TYlIk|NFgj^S^Mv-mj+fgut}28zDL5JpT@$W|Fx>m( zZ}&Sg?4YyYZkB()*6nWk?>k*MU}MhL6XD%S%bzmvtoe0ZPgb}!(Kv4Y+xhdWo;(V; zvVce6h3?;^wRV~;n%5V+E3MIIeY|zgvGY5Y$ryOC)+e5Mr+)i?T=eJmpZmYd*9DkQ zzjHEH`~Js1f$38iu3gH_-8)0vU&Lpwp}w|5hAHFKROzRNc?l+Wv2n{{q7o zA@7d0z7&3!o8|7BHfKqRMJwB}c;lrS=1EqFVpMfV!8Qu z&Xwuc{z%?`cDzJeCL`hVp0e-fZfu?Vp}h6&=kz_dUi&}asM&4QAoO8={kP2*-n}|g zS1H0VBmb;O6I)u&V)fPo_p}YOSNreg)!A+L-2AJNK3l4U?bCho&kpZcIdA^*kbwUO zet)W6xwi7on)&g2UdJk?Joo!uX9B%vOOPpu;TT5+FML^+j-W&_Ys2*a_xS52Jl=Pz z&k?Ywd0V=kKQ!OwVM~JjkL&k2zpX7}x_f)NF84pZyu-~urAyaIedc#$uD^2ac5c2w z?rIO8nz>h_fAa0-UAO7NwFA8e4?TD(?j6%x_Regd?3v>diM=0XF1IAAvmRLc)i|#2 z=l=JLx;Z$fZQgm)HXwZG^k$(CGtKvEPKzs#-4MsQVxn|H?&W{w)%{0$*4nL|I{W?1 ziXe_Pwbz!{?p`ZD{h#ss$rAhj%BUWDU!W+?n0nN>{zIAtXp?=*feg^4J6i;=S3t^I z1r{rY#=by?15L3^bHqPzCnsHr&&-n22JU?W=?D=)#j`Xz~vGuNP zoyKuNd>S9#uC+NDS=;yUGVe6gItlyT(qT8E>W^Ogb@TrJhPUt6&#iNN@kn&pgbVk1 z&F=`vCC*5nTPhY>`n0sQ*+PTy|GiiLif1Y%yzjjH$eXsL)``>?)<*Ic`O8=_c3F_Q${0A8foZHlZ*{gdj!f;Pk zl|kOM!Su%cy5G?YUpWS|ysLe<^MU?W;g5P7*8GlLbM=r-WcTvq8QOK7t%}oHmS#y5 zYCZ5{(*BVCeDivFwp$yn<)8VleEfKta2wDGaxS`|W+W=k1f0sBNA6tLNnP54FsHcpfjW+OgwuKX~3O zVTr&5CWD|8tKwlJZ?ZiO$F&&bHqTM|5Pe(rLqqC%`-;n}E|hG2$}yqz-zD9TZ|Y_! zoS9a5Z(B}eMM^lM_qCkE>eCy(eewRiCO6^FSM}Gi$=QFl>_6}KMLYWS{-Wc37g*ZP z?vWBX>BQsN)=$TIu4^9+v7pTb^k|6h7e`kFJzOLV&q%=e!s z({^iXcKC+;U(d{6x83VK{{5r+^PAtj-#@(msI&a{yMvlrlVyqoGupQt{!y0wpwc+K zO)Nb6=eqDY64eGvAGLAoFFBrY^vCN56O>t69K@9#{QrHib^QWO*s2);rnO2JwsJMp zU(B7xyZ^`+4Ud@o|IPN&Tb|AS|I)s-=+^z0*E`mR9-Y$2{#Iol7w?*X z2Qv+)H_TytwCY{izQ)~rPTlHv|JByK*1Mb4{$A4P>D{Ene`mx~8RUPbotB*O=fz@? ztG8n+YePPj$<|d=)qQ+8y`m;PSm=+GeIj_$u<>J8gGj^2U#VZ?V8zC_#sfP78QM-w zh=2F3c>aq&EqB}PrpSH&`r!M+Vl(?(o6G6<`~n{QV4T$}{rcla{j#}p7rsB;{#rY` z9=b8*F)yPg!{fKzuWDgcr3u)`Srym&I2vCb{xfsR_y7ODor~Yz_qgluk{72wC?C-b zI_jCam5G%rO?&#e;3b{iDjtfPx`Np%yLNP~y~e;PSjFPLF6hY0M_LUJ`%<2G|Ic~* z@Z8*+cW2%-wvK;%@z2fTy3cd>Uavm)E-tGk`|TAUn=r!}S^3#E(f7|^=AXZ9U+dmq z^XvcBytkPw5HXoSw88Y{V`(Pvb*CGI7_}H?9z1SzDbDDx#I=aD^^cQnw)Sn)Wr{xk zN0j&NWUq#f3sp)EtOtTkE-*2IE~6D#;nKk6pn744q>#d9`A;vFF7Mef{cqO%Tjo<4 z1Q&jFXy9sS*I2*^F+X6Y!)MWkE7d0z*LnBz-@ICp`TNu2Yri(vu3g;f;LCKXA^X=6 zaTbLQ^BF`N{?^QBWncka%$hR^q|4W>)z>jWt#NJ2t+jWx{h!X;m6!HIT>hHW_oLG9 z?l6cpobzYc#t(K=tI7e?I;QzIy0iV;!dl&KJ@;x=2i61GDHovE z;c9p^a5*^cxIf#@((-2Ijy-$sY+d><+4#S@|GX(ht+5;_${V)w1pf|Xo69TGrV!A; zAlkqbV8{t}o4^OZ1}=xC94mzaPRiz4DSr6yx83)Bh-C5Q*%E^5Yi+B)<)mEuf8piJ zmwrpWJ&ZTxdM>bl$)H{8xC7+AU@3J6)&(CKl;oLog#+4Z>gw)&GJBVKecwA@0|rKS zmK6*ZTx>z0P;+2l+R72YxWZM+UO>aaVP^4b$>m?N?O6jt4OiBN6owt>{9<3>kQc$Q z-g>gj%~%fs7Kr;a{2RC&Dvwn(I21CSnzMf0x~|_*j~;aE?~5qfaXWdc<#Mho!QWQC z&R(nhdA;kcc6luZyGIRN(9jG8h2}%PzkCO7-n_Y@>B6szM>(4ntADINY_I4NIZZ}h zK7Hfl+a6h|Nm*)hqti31Z^_Rr%e-{MU(tb8p;agw>Tqdg2i64z4$d>n&#e7dcHqwA z)cSWHf9$`bIOnwgpG?IMwv0yg=a~ChRxnibaLs~hYUK=I)Zmf$EYNV^VBX+@;wGEbbHnNNV zR$XclF+UnctA8w1+OXYmZxBvZmLH&pB{Pw?7tE$uzRKJ66 zHI5Trz;qy!0TPTaCNPLL@HL;Cw%z?e+P{Oc|6b4Ct*Jh>VS%5T0z=~?mK6*l?mf(q zU~8~v3Sszjl*LuRLv6yGpV8eROge(U1YYzph&H@)I@boe8`^<^$%f^GCCv0m45AHs zhtDkoOD!m8vSGgPTk^oa*=hyvZR> z1}0g-2TThVCu|OdI)&o{PlLw=rvHgch*H@p@0S`eHR|FXnw_gmC^i z$n^f_dH0hO1#Va|YB5Cj8~kpDsOu4Uz?8tkV+kz)DyY}q4Gt=7Aa%M`|t6vie|HQw$;Pce7w6>%E z)sMHj=U*@1lqAcdFahLn8<~yJ5-g*OLA1f^VUSwf$-B1ZKlblAe&jI2%>CeE3s#hv zf=i+jzXooUa^?Zkg7Z5zXM@A;#T&N0~wH z4Hw`LUce-fc9@4{m0-oUH<70C7EKH+*HjD2%EW{VB%&uI&*O67>$(9AJQKGDE{9}B z=XcvUY$`vcY+op@AD5Gz{DzH5puoR@tKqkRq5vcWCV+~}KRz2dAgOPM`+?JY>p2%Q zDF|(WhF~8@Ni^ewdD-simeJsZ-B``Cg5i$yAxQW;B>ZOCwVI*D=>Ouyi}zlv`|{%A zy`Njv_E&vf)$uxh-}gAN-Em(RW=B=*{d7rh&+E_YigoMs-!g!S*QK~@F6c-U0uETWyG@eM;G?guhmX{85Hf+ z{$};uXwDC-_+u|?S;tkr{PShq`Q3i{e{xh6wlWn|R%#y6yWMgoepmR+W0!~59Y22Dx+FY2-04QiYunG_FyBLXQ9cd|LnOdB z==$81A2%Og{_W}gqRTtBHm}>gJyJ)%@Y5;ZUstNGzVyA`%zpcfZS=`MrTg-Xxo*iq zgNlJ^G0Uu#3_fT7`1||2o9D25r~bRjEvjQGh8|KC;OF#krC_4>!oR!)zv`K{3Z?fo_K_lr#~?|wbXP2c;0>m^6;?b?=K zx4vKctg}qnO#agHk1#XTH>6$@=W}$Dl+EdziCyUV5ZO=3w=e8X z+MTz`PIiCD@-HXnAF1J=51z_AdXj_Ug1>au@5K)%opB`FHF1opgq6 zvwn7Sqf|i&TemapN&UAoX`Oc3?2RuZ8?I=7TUxc`@GZ`ln`X|4O@I63RrK6z>vu%f ze#*a|y{AO_vg-e>Ul)2mS-y4Uos_L1F~RoyTlcwdxgQdn@=xiSn>Xu%UWNXUvZTkC5{)@;pPw3dY zaf_LVzwBJ?b;a79mjtu2=l*}RVE?o7x;i_pmEZLLL<-ux&F_5kKA7>w`SwUqJP9-$ zP~#L?&#-3hPwlLQ+68BqZ~Jzy{#9YrbJzBDFP5I(_F{|6vEOl)i?rY7EBCm6eV}k; zec3VDOUn!OK@N9avUVDmL-a={XvS3FZcGwwh?-e1#>MHDG;{wm=kHg9V^nk}&cBd! zcKS8JPwNX`2Hf8^%YC`3@tf|;1z(oWdzM{1<^KFBJpY&eyjId`RR8vz_c2{t@93kN zDej*aT1@)ceqyVkA6npl<7$|GCf@)1xur{e9KsJ2zg@G|`FF?5jDw1qzWgzx z@5Y~7R(oG;mbsAHdFN~J`Q0BEFYiBQCqIin^-lKDK>z>Q$HT+Jch|?o$7g5cR~Hs; zEU$Z|;{V%U)okB9t^*e0ZqTThtv2CpKI59HKX1qXiLPp0lc8-K5Fh^R)$MC>8`m#& z-u3491F7x5ozibzel%@)c;Aaz;^%|r^B-0I_E+(L*4~==H{yRNe-3Zib}@+YhMUYy zR!Cu!Ak=siTma-QlfSie-45r^Wi@$hIqNU1jr}Fi;9$-2=KHZb?^`eQeXTXzDkQKe zylT#w{U(X>-&QjG=wQ}@w%|fJ&#YspIQ{2&(B-N1uSEB+dy@Pw#eAFJ=av7q+FiL- zeRW}JcK>2yf0jK(Juhed`gy|n^#g@v+SBKUy`AuLyVTCgT`L*RJU$i(t?`y|`qXhR zD0wEo>$?3{^BvCnZ=}9IsJWOw^}$x-sUfnr+;tXfF5PcF_nzgoOX+{t)XKH(t4-eZ z#?Gm1S>NsRtzVU6H?4jz|Fw8)So_xO(vS1@t6p)R&*dOrm^K}117qWpbcU#tf7o}= zzHm`=n8u*X;u0sWdF+7srA{v zw&~NpbC!SZ+r8T_6z(e8_Bq&Cyt*dq{;%tzd!lY`{QmE4 zVU&4jdB^sr;-^xguD_i7_|~tiqv6lr-wB)FzqRt{m+Aj%=FOkq@3rCapF{UGmYwAf zV!Tn)aZ>>jr4Q^H6Id6NJgblQnkhJYXO#Xd{?si|@~3)C=ifRN|LWI`T``h=XZ$nb z{^h1+T+f~>JAW4A&BwvNKgnNOS((jWTkdisUCaLCn!i6M#{CSBwx0JX`*xJom$0dO zuj|{U{8PG^?#+tacsj6`>%gs<^%{pgdMB^@Q=EQldV`|>^b}OCuiY&>vyX2R$BeY{l9bKyT=w<47EpQ#yWuvXJBDtxwmTWPyRjD zFK(PE$b6QxUFG*i?K0WrrB(frk2jXBe796`dS5>{6KmQ(5{b@#URvYfo^j_E=hxKz z;RXFuiCJ$yk@?ukL!RN^XYBSeDj;*&kvr4brX{lNo~`e3QJbD-v1xHx)-lmf?_Ft!{;{5K_E6 z|L;o}2&fhO_+@+g7HVI38jSvL$V>w}XaP$jJAd2G+4H_l zUw>n7y;1$dSG#5Bxz=t@_zunLc^oeD881wIa`9rIdB6<~76pbzF^(6R|3lWM{9C!? zSA;w3f_{t5-q1>@!C?#2f~%`oR`^3&lCK3eeE+j_(Y5be{_d6d*}wJAw)&ocyOmlD zrIn9)A&z^{0Dq2B%C1Ii_!KweLQ@zT;Qrp4PP!ezxD-V&lxZ;OUEn zvJk5bCLegjb--u845U-S$h48i-t=>P)%*Ep>;)F|@&q&9@KCtP2DaWIfs0X#Avj~B z7?VJQ10&O^AE{QRhp+#-qdT)cZ;{>GK*kS};vtTZEYT&jfGI#k{}`yQY2noP9B=)2 zx|31;#21T~GF@<=b5j*+q(cMO0S0ziP+)!Km~!sV)Qk7;-FtU;%C)z#CPpXofA>3N zW^`~lI3IM5;_FB+$?h%w%>r-1R`;@>A-c{Z*e<%Zf7G|L7&RIn0}ITIDOX)t7wE*Vf!Y!y zWKr|{?e_2g7QV>e|NGq10vE914yH`)S8X1ykYdzgxEk;n+9`g}&TyXLM<=TnC|y)2 zJ3M=@t0eg~fbj%}a4^(gVH^RB8LB}qT0s8lXP8-Udu?^)BBl*eRWeW;uPHmQCfI(f z0QvkuFT>3J+dD+AII}KLi1C4{*dz4AKDT+A{4A?2<_ruB44$rjF6*2Unlh6OOc@y1 zr#S|>JGC%O{@=zh^?wV)wExWv)8V+0Vdnn^hFSj^85m}x6CiPP`8od?7$6v|1EvI| z3>DA#-^hT#O$^ijw}7p0VVK;|#=y`p@c`rhhE@iKhDrY!8yZ>|7#sdiIsj%dHT*x& z-N5+&K*N8g10X4oKo*-WFo4uFGPL|}W@xr!Z1~>< zGNgf_;eSH_W7+M!qD}pF~Ecv8yH#}m>59vO$Qx8*Lwnqa4he!6#fPkGl8v;-gQC~Jg!zzwGj{rNnfCf}Kj=pSAvS3#1t2nt%p1km4=|Hc;XM zdAyIwgJEaGf2N%c0g!ao21;iQ3<02Y*2chapebN9m4WhK3j?SKLMxg^Q(2zc|It*| z(7=GbEXzzbG+SeW?85kHRXF59v zcse^P1Qg|`W#*(ZFlbDyop9QlDNy8?{niafI99oKi!n!P^KSM%eZ_%=*|2$ySg)~_ zvc+Qq;~>Y=3w*g3y7v37cb$E0Yw1NZjxME+vcJrG%@i;1>{}>W`Jkw-=KGxD^M4th zi>=Q*+NZE!#j<%_t~-97VR~NI#(wujv-IRW2^kMlj2OG#|1q|E_aNb?+JUscd-J7j zlgqu3naO;we0%z{wXmCD1`o zjcH0~5YLhqc1h2|e6PvqW@cA8PV&|B;d{DchgQ$eodE_WdevZhY3BbJtbHWz+5W_sp4eR&v3AsSi3*KRYMU=F0 zoAj=o-RPW?o+1RzW&}9{rlprZ2h;TKR@vQ+I#+K?Y#4!-{rnM`|EGm{^$QW z1SDo3h`#^p+QF#F-+%wzI%}(-fLhsgA4wZR=&Tt_g|CEG2wWL$9I;g z!DOMz)Lag5H*i{VoQCo_1R#vZA|IF%=InZgre0V{VSkbn-yx$kXNPnDbLK3Lg{o)a z@M$}6``$OR|7mv*EdIdRzRYrWVN2 zFhKzYgOyC5G(pO6iSgEE;oJeHrI7WC*=P3*lw)2e=zv z+B;jL*uco-%c##V%f$-j9Z0}8z7!8&PWW~H0^czWgRFD^uh-ta-dk9T6m15POoyNS zdH(9W^7Hx$$x83sb!@y3s56{9^uZnBIu;HA1%uU0aSUf(oxCNE8WI-X2e=zH8~mAw z8W3kzHApdRuG;i%s~)4}|JO;z9WeO>KUO`5bN@GNid1&+ZP?6G%k)5pr(Olso13*B zupU@5Z%r*C{ek@3xS3@Sg9Z0td3dye{dr&w*9u01)#};t&s7zk|KBsCLv}4p~IF_EBh9+#tl*Qn4CNSbe70Z)9>)p>v zz~mb%MJIf=U$6fE`R{L>4L|Mbcf-93a$=*U;0LAzKfYULC{doUk97~jjQ5|nSHsK! z2k8u9MpK4oPZp%7&Mx|w{#4~{Gc0r-IB}f#xnJPaK+*Ul^01p7LJqiXOi;g|c3PW|4K_DpHt`tV}%&9+*a6;o}@d=;n z|Ake3tFmK!pb57e!YEdFzD03h6wT5j;}>0 zeBK{t`52sUK^}S*=y2}8&AeYfzP%AGRLVco&}jiFhU?(ji~z0G&YDc z6c?P>hL+j)Fnr*FA+-Iq<~Ws6U#G)1KbUk7Aetag?Ai71sf!=U~zdshGPYz0eid6DY5pmKjUB8pL*Ma zD2WWNGueMjwl}-}d;8CiTt8S2RMejJgSi1>r<&6N?uJeawr;4^FykMKeqc)2vo8&$ z%wS{^R$Rb#z(wZp6CI~>|DVihoeGb`Gy59m{J&}c*z?vxe+HjRnGxJDH$oDG#N-BX zhU6wwT~y&2DxhTe(qv65L>bH(J)RD{4TcB(PH!ptxBTgnHIre|31Tcy{+vIg>Gxi) zhAE-y{JB$T8KRQAg0bLUh?Nk`D6kV7UxGY@Rrw0A@^$VB|Ns4cEt$rH;=r5@4gL%{ z1}k2|0tS-L52$ceFdB3&Px6KE;jU|D-NSGrA>cAv?)3yU(}etw&O$SWjk|(z!@&j1 zlp(PJlbx*bfc1dNye?BTV|c|rFeNlQ`nsbkvdd{`n7Vbo{fYKM3O>~)Z~Gs_yp8Bhu{ zNHlach%>Z0L)fq=VMz-305ckIf)a<>`K#;Tc7YiVf;WPcP`qarm{3@_@lI`K=E@^XOf1**9|$wN z-flbz)vG?e4dM*J#UWx|sNTJ%|A6(tueUvDg-WpU0=5HJWTv(vGR%zH#>C=(S9xaq zO+UnE?sq_)!R*{6AGqhhjD#dm6y8|8(Ev5JHWV_&G33lyIuq;%xXTV40ktGIx+f>H zRPC+({Vfq1U``Ko^DDh$RzCdq_xI~o&hBq-ZWN$6i_Z)%AS4`RU!dYx3yioG#zd|nBlXsL5d-`s$iP!Y^I`1@I<1w z#^Kow|0>@G?$yS>%TLewf9K<)M@c)kY}pc$#Ml@q_JOk@(k`|dEsNGGK45KdC$hG? z0;=t9xHN{H`+xi1w{5;LbECl>nZ}bM6{n-`8C^NFY^~Y>W_}xkEB~JD{mgFvwcj zu7<=YZ}4O)`e)90FBg<|6IQW&s=haU`t;>lf5oh49oS&`fAQV38BCj19|$vSE}d8A zj0kH`2!?^m&`>dPkY0q$fgH{XMuX_*ndWG*5XxxE5SCgv@j$DfgxPcZ{l|YCT5~BD zmM&(iUpV!1|KD%7Pe1zh?rwAvBO}v!kY9_%{-L$8)4~pLH_Wt+l17Vy^PCloALg{$ zqvf%gq5;eaY5muZr8zpB`>!)+ku5mH7?}=pq@1gN_TzcXP5awNSvYJ!mHhe0AHv`e zf~H3fff<^Q$c-s~@be{Z4L-W@w4 ze(CG#PK|I#n8s4WlrYWjavZ{Bkn;{$f;wRAJ*Uyaa2lvpyY%uFanyJ&;A1ppILG+d z2+8f@aSFx%j_+l%{Qp?Y?7s>qELG;VZ3UT*@JXW~D6-TdE+cX~$mflopyuTyzr#^z z&YHn;g+W4iO(s&5XK>%C`~5b%EbA&u#@6+gJKdOy)gA~l6qh~N=8Z@d42(>lL4{z= zyxp_$Q$O>!uCFZaW#L$(`9PQ<`%?y5 zVYyimRIVcrr+|YOcRgy#kcLu^9$*zbA@l#t&GQz&pDRWGjecu6e+ENiG4~Ia13PoK zfDJ?VeU~|H7)!lE6w(?#}8zcL*t16dW23`~)?quqh8VJ6@kodP#g$&x8&L-bkp8`rxAD%OHcXzic760*m>{amp@Av86GmGP;!a0r7>!<2Hy|m-^ z^x2#o0yhE}=QG?0@SBWQ)0_k~+>Fj2T?O(t!kq`&xGESoES#f;R$om9HJ{bypAPpoKmD_)W?MI>z>We?4u81j zZYQGP2L)=*tOjw0*>3NTf&30`r-B&|4slj67GPB_#gM%0|J~|$nwJ08%6tu+zWMEk zhek(NzFx2Yal_lx4_*duYAowEKb}^<+V=YWRf-GT97HEyj<+>Z-#68G{@c=RXZxdG zpZ=DZ&2gvZxa{oxp4y-SMU6v8Pj6l2^{~F$)oc#gHTP_OKmT)c-s7Vz969qq-K}|h zthDuOl6Pxk{YzNqa?MvV9RefH6<)v|Y{f(bdkE7pK?hpGP zR(+Wy*{PoVyssW_3{qaSrT%LFzl_f1x+mtmi}^pb@*&gl z#n0|M|Ir&)m;Ep7_lDOe=lq#tf4hBd{f&QXe?R>^_4VD)cki3N(fz9K&~U(o>rVau zzrs7$73+GP`@b_KM%|ziR18+8C%J;d8lFlL4ug7%1wq1S#p6lg4@?Q4&K>DOPgC40 z7!6cjE_wQcf9Ic-ukEsY8`mgK_?-HCN28S~)1$UX;Rn6%tK+}ixKr?7|4&k+gLeAv z5;^AymJbf!TV%TLs@(_oeYxjT8eksPu-&!L18JV7IZ`fdP@4s)}`+Iwz z?-u#XAuyw`@#DX3GYf5Qqov==N)K2MY?(8q6wS$kppu*Md;n_P80a!(F&yzc`H_Eu z;^Cu@)lYRSU0pWihZFnE&-1_MZ%zN7_&70}XG<0fPxb%6-|2o|r!MxBcpPo{>|(4% zBGck|@y|ZwfB9DQuV&uoI`jL5?r}oG3JwW6Opnj~ls~=5*Q?=x52#b?BeU2St=ilQ z>eSwL*9Ikdgwza9P`mDtL@s)#R@dOWDMOm>^Ziqs_g{Sbvm*6e{k{Af|19JC=6|WU zA;lbN{NVb#J)3hrEdm7&ipE0 zUcF9z{`xhX6aKdM8XvE`@p0{(w~5cCtN(}b)o$yrbmaE`lezQor&N8NLgO6=UcX(V zo-OdCYSUihg9YMI=Wp-GX4z5~cZEaZoy}M11d~}js5khZXAL|dLl`}=2e=zH3hxFN zOo%|gQ3I-ZuqjV?md)T3b?(30^C{csP1qB^x_(=~mEH5(FLrF*7gl|ZBjaoS*6rV} zOVz*nZWp!eM%nebs{4NadhPvZ^7=~O&ix;I^L0M1aMWh6zVg$&rbb)c_I7)WgLb?9 z?c!f&e&&CbFRRJ^mvjE-?84LQug)`N+El;ITuTRp)n#dtZ6I*XB`t_l{6uh2j;*=NikNmbQ~IOSk!b zT-KP~zWB*z+ctjLXElfK=^y9c-H>>E`?cwBch1{$zo_iQj>5RTg4rxRzkk-fV3yag z4ia8azyT>U8aV|%a5ivSuy})-_DH$lF=+Vc&Y@@MgLE{}% z7JjYC2gl>8{m|L38#SP4{A0WUee9?V6pemw*wCW!GbkFdDQ{f4n$aNZTz$PkgmCGF z_v>%o%ZXWczhrO4mk8NS8#ca=VN>^?@{@hz{(nw&#WgSOY7AEVKF#?n{GG=1qS~b& zyB+seZ7F(D{3oGuWz4JNKY4f0`x1SlFm&er>o@9G+kU@(>gW089~Z3^(pDe!sI}id;?dI;oEN&EuN2=m_uH9^`+n^*s#ibpvtRaQiKh6Y zf86tH7n$hqf3Zm@{lcsJCo}u!KfgD@e*fH`MUH}?P)ptwr+>}I0ZeO$3mOtEh z{B+l}^*i<)S^N9@r%LU`;ha*Y%$wXAW-+Xm*ahuq`)qaid;NMy{?SLMjcvI+EIsr8d;JS`??0daKf6C| zN2KtAFL9hnd-tCCXs%TYR`G@#iM-Y232!ZSJpl8Njw)=t)iG z{&N$;&Ni$NoM6gWw6Axa;DpcJu)vYleIU#rt(#?sR+Kb?TICNGMhGEgMHUW$8yTRo zG3rVUY9J;sv8t_O1C7Pp=5z1+IN`+KA9A18a9%k1(!MI^taXp|^Zmu2Pgu&EvfCG5 z+J0}x?mL^V##!aN2>d>+8EyIF@4X^E&BA9t(tR6q-kW9#O*v_^vuum-)`-mZfb00`KtGQ>w8_jYm$$v-xTk=wNqAC ze%0^j9S?UIX@Hu@;>{;A-+wv(Z3X9q&#Ar*=l=A5lzqRWemR?C^8cOt{O+vM6nMV% z&!W?(L}p&T-~DgtXD!F{nlF;O+#Ig3biAyJR8F`ti-EuP0dwl9+3$BO2905YORNKK zpx%^Q_pE+Mp$sa0Kw;$rT5%v;p)n1bPGRMfS=0gUhF&pKd5|KQAcw#VheqG^j0QR9 z{;z18`FOvC<=?q;{wE)Qt*hK_R$LTqxxI8#-W1E{f6x7Gt4^P6`MdJ?9Q()TzMnf@ z74_M_inno%-~`Lhe_Kyjo|j_im12E4xA64x&oxI`nh%?%+s>+9{`e4o>?hTyr}qC` zIbZAJ{rY=HRsa30|D5l==g+1Uf)gzN2L>w_e-c+ZzJK%n6Cd-RmOTHHx>4Kl*_ZNn z)0vgp_f9=L|FCu8pFLmtc7cbkDYw*>a}}z|4(aEwxa)$$qMJq zznSOwHYT1gf4JFy%HQWd)BEZ{)!E0rkNdCv?%k>8uy-c3 zox=krjta&C#tC=PT0A-1K;3{^rg#33x*HaPdJPAbU1yLe>%Yx+ea?-<v&5ey_G;_TQWP&2#wbKy|XUxy<`koAqBj_S?+2*&la}qvLbUVej}TvoGKLYZe`u zt5CeinBAs$OL5bQkLRC-&9VH+eLX(9EyeHmA>OY)&wewin7Uwcv%KY(!_U5yX9>9Y z)!x(p&3{+U^6%WQ$9|S(@wl9AS`#=SMfU!V`g!qv=RcqMcJ2NBGcV77JiN_3o9PMf zBDVu4fBf8SRQGSw-zWNil4cg3FRu^pWMu)TKZeFY)*7aS5XZ-`tPBx9Ai`0>Xu#T@ z(h1?iQfC5ag^Zi1$vl_i~x1{@3?7ZnU!Sc~^`#%%k7=_$9so8&VX7jyn znd{f8l6S>vv)kP+{u1Cf{DR}rwgJ%8Smu&e@xDUgpP{%=0q8 z{eFKuR`uD&?qfpi#csXTh2Pe%-RpQIne`9zQQW@{QMpm4X6x+}C3#JGXTiFW(<3te}4WpJlv$c8WI`k7m*=CUw}qgI zo{EfVXoFB~pn<#y!@uZ>nX6|n+kxQk_ilU6o~yC^#KyDlH=dLE-zpp4yY0^j&GU2K z`JMaTZf|tyuhH|}Q$NqPd}#S^(Fwu#u5&E^y}!48|C;}^^-3=Z`r>8POfUkn)O%reGQ2H|57?n zqx{6TOBHgC=f2NVpRcueo14uW{rhz@*GfP6yW95F)Pw2Sy-l}v9s0ZI^sA*SI4`Ue zEWBE}wccg%HI9y#RWm2gf4g>v<-bn**y65hb=PFpOoWEthOP#GhBZx(&?@8^rl20; zTbH-(P<7DoU!(MZ^?;U!9@^+nq_9LaZ$mFzv`yV2pPeOF`-HYP9Zf!-J^jqjvpc@M zbD2BmyC^wcuX?_I$`AiVf4%+f;%?cCzSZyiwnlTp=laX{Yf5M87yn>afBkui<^R+V zl`Ma?Uw^(aGk-%!+R4xI+m<=5R&$t_|N7_2f1qk--ud@+-%?(F3f14W>B!8>@lxU3 zk1Ah1X)rH36>a%z?YFSLI_>3lxAnVbG2GlIbuj9>S=GKh;n}s7|7HH?T(QZhOz&-2 z!+9aI|9-sX|AZ4#jNI2_Cr9775^?VTvQN7$!By`JZpQfxGrE(vd7|Xi8Rd-n4A1^@ zZa`XD0a{qd4HAAdBNuhT@>y)c;cNz*()WAUnp{fS_x8g>q3um!=jyL_4_4MA>f93X{{=#ZivL~HUw?1|zsJ3VGlkiI7vI}=e~05W4v%%0d!-m>e!d@>Kc{|M`q_@0^HPj! z=lt$nCwO63{JQPmFC0I;^zZgNL62Kr)ch@KRnu@_8Ak=<2F*8l zXtTL`YZ}BE#IN1H3oA__`VK7P$f@9MxTe>3_GkXt>6ZT^l@)GBe@?B|Zr?p|(ymXY zS7)-$F3&h(X;<{`e*H6_nGb^H>o**!{OClQa=$L0pZ+b_zh>Q$^K-01 z9~t-C$35cNR2^U-G6xvR0!@V|o40>E3rZi}uc3d?)L@PlW!H&o?Un`Ca+^ig(&;7Rj&I>y}Ud zH}muTneTo@87tks|5tiz+oAg2AMfAP7E2agd{`B?v`}@$^66{$-kav!e(LDcUlr50 z6|$_iv5U97A-^;0ctKC0+|MoF9ye@ObGWxASXsfEM>73fJ>PkmKRM_Bru<$}c+KL( z-~VBE9DExX1ff;8Z{ybgTQA70V@3@%1p{7C-{-JqB-#oSiNFKg4T6lkXd@Aq6%2}a z8_wQKxyF*QR=s$QF}wBSx@R@Vd86K5+$*`ye&6?h!5?kE)r(mEuivv&?xFmgnl*PG zPkL^@|H$;%vdB(j^_u7B<}S5u-u-Tuwtj9#&HdW%Yc20z+HA`G{l(e(tzYhM3b>yc zTb%hPE%T1&oS!9&>_WGc`s7=!J-vEC!DVR)+T*w=^D*~U0c@K_)WilpM7TW{I`ZRhYzo@oFKPz zK5u*jCnO~{?i60}KWf(Qx3>*YLvsc{sQi39=Pg?K83S4^R?m=w+B|sXyg+S2f8zPu zQulw`wnb0VWbeN^=f@wpum27uy}ZxmSN}tKt=`tX6PfpY4ULcfRbKS(arK+}`i<+p zf0wt6IQITV;QsB^*Vn}^t*zYo>;nJn%k|Dr?#Ok?+zqRKHX)t2_5I&_?{#0F{ptPK zYl12Bw*32XyJEgPnzgv@S?GGbxBRZ>>Yn|Xzw6(xOaCiB+J5l99us@ZIKrk%NB^qD zy#6yk*Uzoq`{ne%xl&>uYqn=GJ*j;1ck|y`b~(*hwvRUd_O6KhSYLnj{))fK>U*Yp zURYYb-aN;zibuRJazUxx;cFZxW-;vilUV%3___V_(-yypR<0i^Vj&qoWD8wN7sH_`z`Q!{#ApD_tp2K^EU2SI`6%;+>e6H|1aPF-6xd3 zp(eF<-mk)W%_m;U?{agPQ-9CC_=C0O|HA(=_E|L--$eyKGBtcSZSK~zL(Ao>G^*Cf z?)!A4bE|d6+^ojLY!)6V&+mt?aahQj`b5q6ds;uYRP*i3&+$^>O*!lL->u%8m@W0> z4`_{i&Xfc5Y^%+(R)s#lxxfDZs_U^T4heslzQ#L0-ap?O)_RAPqq9N7glY?RtD>gL z9T%A57-BLCzoX3-%vLZc;ce)Rdz@6a{#WSN>NlJBmi|AO+`sm2>V}xx%Fq9QN$0!r zO}YQt4pGyh4dA*+F*xS_=Re+Fzw7(oNB)r>I)^WSUEf1mR4vYgGQ6UwRF zyUVW1d|6{y@Z!S4OaJBnG}i|_n*aajeEpA~|D7|R{$t^Zm-{WxeV#ej+WY@ocK&HQ zf`u1Mygc8ONvvO1|MS;J|Nd&fK7agy%iH^z_B+e`{$7(VpZ?oc`h0X|4Cf}>Y^FWc z_y1WvId$6m&-c3TSWey~ZH1b+6Ap zuL-YDey!`3l3cxFr%S_upBz2b%m3G0D=3?Pt?CMgMfBk^y?!A7H_hsFQpY?BF@7r2Z^*jHK_Qr+-227E{3djG2 z{i!?iEo_eEx0%iRFIxV$j9;gJeezpS!ke?+LHqc>n&&sy)UExxT5v<8`s00@6+nxQ z3c9{QTivkaC&d)UVA5cMR(nSZd|*lt^SdaA8lDc$pthvRyX%>8XXd;R%w{qv{`dRq z+~Y6#>z8a^wos2}rtx0YqC@syzFdAXb*ME3$aMS&{*5%VIn%8hn zc)RxZ-O}r^sVAEG?IIriFWGZ#L&e{(=F`4~eJDx(E53c+^bt1=jb?WE&Z<|+0 zUf93s+LRl!?D^+g25g&Q%BXj1@9Hh}#Ye!6`EU28PQM=ElEBQm@7a+~quU!y8I3^G zwwrB>fBc?){r>fvabnwrKvM*uk;DSM#;|jLb{?Dix=Q5aeEcUMl^P>xng9R@A_`tb0U6lxCr;mxSe@Gt1lf3(`xSO-+w=C)^_ z`?4X-Tlv`^{_6d2_J6&)UT3=7I?jN!*KG9#CqJJ$dR*Q%>QQvw&ZS4n?^ULEn(tO~ zcy=Sbuj1K<^y-^uv>eaPxBTDEC#$viQu3AGvVYfB$=(0i|1WT7eE#VIdn0l8-sZT) zYzHoxhEM;kD`y?|=;?`<=jZ%?D!jG6D#f=U?h1p3d959jxpWol!o<98u3&)?<27iVM5!4iNKn66X!``0Ljhf>Qa5Et70{{o$4Ccl( zr_aIP?^*Adz}J2J^>?fMFMH?r$~-&xQ2DFa%*Au>pPu)&wB-HY^LEke{&?2#|2q6} z@5=C)Lf4o3_w0#zbf!?h_cce9E7l1GHc$Nztj7;e&6SCuQ}(dtEQY|VoDY}A@l40t-$)asO{%v z{$4h}b3tlTTJ^c@Y3aS75om`-cDag#6*rBZ*JoyCp8a^!-un5EH}g#yi~i(pzdH>S zh--oms54ySOh;Q%GD8itf8*trHB(_l7Gw-;4QQ2Y=^;rs2p5)#mw7ITWPae3pZ0Rq zti?MoLUKsX%CtA%tD2Sjr+qtfa9!_SzjO85>OWPAPxqex>(6A>x{uTAGCSYz`Fu{O zUn+&K_Suc?MNd9gKiORWx;kQW{kiFd-_FnZcgKI*^B-#rCw%w5FY{k@`hJ7mIT?3O z{ycwkv73`!|IEuE&+KoW9GJY={*Lv5x+`lcKt;{sruU+$;^*4o99nX^{ZQ5-*AtJ;UZ4CKU3iV>#`gU9?2a;~ zVr7Fn_y0X_JL(2$xPcQ5Xn_On1(EvT1(B#hc4pdv6Q&G)vGuirH_Lt$bVfTq`;pF9 zm|e3iy|1Y5{Lh#C^(yUaWRHK}^W8|@+U@!G1@6V~Tc^iH>FMh0Pp`PKV5;zZ%Lg~@ zZyV>WectvX?#-En`A;7_{}B^^Z0Ec^@!Ph4E52X*{pkdu`hT70r|#Ikxox&=>bd%L z%j;9uuDrOC(O|{-`!AWxsQVPf4?Y{Uwu?p_1v8Qb(x|9Gjtly?EJr0_UrT1 zJFCzB?*Co)Ox+=&jzzBGLF1;IXI7q<`O|ay!PJB+A1&jLeZOB{zq91`+wIeTtj({@ z?)?4^va<6zXsPn^{H5x!FoFcZj3`hl`u0L+4ulWuZq3;bTKt1WdE>-v2ARrC@x#8*-9!=uyq`TqL9rCV)}U%%$}<%{^db=UP)Cq6rJ{o2WH zBli7MKhL*5@p0zn`Jdn3iJbhQxaQmWpP&Af-z^Q_`Q_gCecO-h|9K#P+K%r}>-Qd; zEu;Hp$Er07#eX)tIn*a^{Bl0w^}AQI?d5O&SFcZw-}%LV-`m?>b4;E7o!tNb<|RD^ z15c)+PwJqp3%K_jmrQ_Qk)7Kdb;v7hU_i=|5;~Z;@s;(-ct0S@^-W z+j-i~-`?H^6?K(DA2=H-t#YdoJ2*gl9Cw0-^YZ%d9YaZF3G+ZL*yWeEg`-pgGoryk zq`kf3kBj6aQ--$O^K<_H6Ahp8bF*#nEaT_)#eX*M_1Py>^Xk;;(@Q}eOI5i&udb@@ zduTjg^W)s|dy$U{tmf+%Z^-kUTH&}q{?XFa*?sl@YD$X!B>&m)yzrMpZC#b&{cCr3pZZm2kd^Rf zb^O1lm;RmnQK``jouo}rVvVx=9jUzFs=fKmQynR46>(BKA{%JQNo9j=`|>T_7)vOYb$9AN$g~Es5}3C+u`=>cmA!g{BK#Q{oMX{yolwQ z^KR|n5r~U>zqd`_yC>$?O3=is|Cg-3@@G4ypIgl`lX?DQNFBa`R{OIE2t*4#-#(lYUqu0p2^23efrI%l} z+Xp|2xt~zEbIbF)?B3o>|Hl6QHuZ;m{r~S%f5_W@tmyPVR^|0r>tNBE^r?DJgS3zD zD*>%H`cv5rno;aAuiE#0&vV+$}YJ=Zu+{QV*(cKQd8U+u4lMVYs|^R+&{WbU8x=Uv;nP=AGO=xSDHh@-rT+2^aK`W-D8q;_i&ip(-*LHJp`pzwX9~=}aZ(1R^ zp~UyE+~+s*Ezj?qcktxoRFC@OeM0FQzAlqKy>t!dh5ZkIUAlL2W&iuc`nRv+!hiig z{r}H=??24>HOZat|DW>u_eFf3-djnXBY)*8mpn^JuRdmZf6vkPb>DZNo@Q=l!MW ze=99&KNR={KC0ioW9t$Ay7TrrANTjqVptjoZB(!ERw(`gS}!>J$&WYn|Nnk}zEo&? z(GTP2`+39!6b!-`=QBuXuRn=W(li`M0X3NY_j&G9 zG5dn|wyOUQ+W%=5lCOUj(z*Yc_P#|&e(wEley8B@thYb+e*GNBtWf-q`<~YX%c7Ul z|L%X*6&1WlUe@Tj{jA-IHu-;_KE0H#SoCkRo5QsuFRqw$=8XE8`V|9gZ5v^!EA`!3u#@Ge{q)Py53zd;=9-b+w=N(}$?<=ouV6Gz+mrdl*F z&0crTTlL(W=VuR;8W=*!q@%ys<&aYQR|L6bcoUiebf6vEW z)qihv<0BvW*L|9-TKDLqy4M_2Mz6!0s>b9?*yod@P~oZ0E{_xkZU$v5m! z1B~P?;|XtD9!`zj|G+n2E57#M6Wi}sOrHO^_tEcM{S%vXzLG<+;124=+C|1XBzeAE?3BStA4xKJ9^s{cdKlb6y64z|Gwq5$vd~y7H&L} zZEt&5iUG7Pw&Ulf+K(Q#_tVbR`)w#$7S}n8;b+bKx*x_%|2x^7KQFiL_04Zx(O&=S zf2@nwE&TPTbI$)q%8=%dxKqN$kKcO}i~kufw=ez|T`g7mXM^ScwO=#T4bFoWlb&Cm z{~jgF8JL4QerE%3YoLVYnavI244-R$eM8;zS*#o&yv#h|w*UJ(k!d@BJUA$n&R3rs z)0x%UICai{zkXBwk}Ret1{R`S$H+f%>oxloklzngUr4m27a zT{=BB>e2qci?qG|TsqMSS|VV3HYc`I{FU{#e?e;%Cz>)&TesR&UabH6EV0wa`=-tQ zQd~RnbG+4hmY+50)%ICcUzFPmUapc&J+c4aKY5Lh|9=|)Uk6)5l2Fq4=l8>TwqM`( zSGGsz@7)^n>q5I-$Rp62j$cbZdrh$X4{9Nw`x*6k^ZyMW_tpMxlU-!rxKnV&f2*0Z zbJ0RhV1_))5TtWKl1;?_1fCZ|I_V13akG6Wxj9Y5&55o`=|am9rr0!weJ4!d*P3+@BjBz zweGm}y}(C2QI=mPU;8)j`yTb}0grT}+p1IK>wY{ms=K`{SM}e-{GZc=>d#(Vt9lMp z52PGb4NO+ZX3&wbj$8KT$sc*!uv^77xiOt>p!N;N+@Fh<9oQCrCur9nmn%DdEPfsv zbL;<;W3#<3x51pI#a~G5Id{dG@5e(_?=fvif&rrO^9ZTUQ_Hw+Xub{XsMTv~Onwcfa5F z+idIKz3*%Dch=XfudVaXeOV)S@Y;!&_eIY?p1yyLzm!4>^|`C z?{D)ja^hC(^^4zc&%eKq_p5;ci(RKHT6dz|9^*S}uPUl<>Gw)FZ`!}UG081{Rp>sv~P`}K~{C-8Ltl?4)ag=*Mn^?FpMoQ->-{QY#YPY%_uK(G7{PYj|ogb$`wum$^G;-@tu>7$7ZrN>*?i(*; z{!SFzeColS_gb+rN)8WXK)V&3k#KK5DXhAj1^LFo*eADoQ^{!N8lz zbm4ECvTs-O>xw;B{r_{feErOj`i~2pQ?I2zs=l$^{r4&HxzqpcJ&}0+Ti&^P*?ZDD z*SRhK7d>&%zasO}szUYDzn%MJ1T4SYoMZXor|oM9R|LNNxX%9HVM8>i?}7PuJd-MyUY= zX2^revFB^vq8_vHECMuTWLFc7(yM6vDY%03$m<*5ohLH?zjR`wy{P5WnZIICZg z`0~S~{r{$_{+oK-Z_1B}JO0nJt@f(E#-h=yeX#Mzz27-KIt(k)-P;D~wsVe=^#%?peFJ+742G0Sp$!u$A7l;!_OVWr}K#lO<+{uab( zeRNt=e*4{Quj*%irXQR7K=%HhTSYIW?Y?bnFyA*Abaz-3zbOM`l(16XpUuW~*&9B{l{(fz_`q}?)zQsKWuopIE z+9q!mvMc@ntsO$HyiITJ-`}{HC-dnGe!pvTexCa?@vv>ilMT~n&v)PO_rt?Wuek$- z7koYT?6mUn->28FGUc$_xcFMgkHyR9X?@@QZPse9KmX$YCv^JHwF-TdKCg1w5y_nU zajRu=Zf{##vh&ZUUwc2D-~VLNrMkcB_K}a?@BVyFD81lwc#UhE*2fE$|5Lx5dMvi@ z;vK%nKTk6LtSQT4c+$|ZegBVTMXK3MJkwtHr$74x8tF;>qhEV;{nQ`N>tfHsMsH9bJ6HWXiHq_scdXXe$i04|9e8H?dH3c2A7$7t;{IEs6tv=A;fEW^ zPY?Ys{Ic8YPqD2j16K!Pp!0wT=ac=%muI}3hPGCNW6pX|0@GfKzF;*8l)!#`(3y)i z{I%ZUe~tCJ?f0L*-?v*uwtU}po1$IY-Op7&^LcJ1)<1v6^hIqBtJNHg*>|72*D1Dc z-?HM|72N6P*4(tsX8N+&&G8z`i88Mq`N3%y zi{2&gihKUEhwtZ~(mFf0HH-q=U(c=k;jnj0Kt1c9*XsYbY}x=?8_z;wAiOWmORQowwICPIxOl?{WQ;i&fpN70bm6?et4Ocx^do`Tu;)uZKn5b^F)l z-+mXn^l$t0>0W>S$9(QqeOLQtnp8J*cx9&Wjm_!jBfft*z|248=k#f>?%R7UZeVES z6c)kYzG&m#96q44BqkRLU2{aF6HsIy1D)_8QRs`dGg-|w;f*On+=pf6Q{PAa z`E$3N|J=Qr%s)xa`-`8xc{kTyU(WX0&M-X}zOu|{)f036hwhrD|Uk@8xBq&O2}8KW7u2_9B1hiX(^FZpYUIOBTH{X7{=yePzz>e|@XHexLulYtDZr zB}l{3Si#_(%zv?qtK+_|GTpsGaD!UE8eXcf8#sF`>q z9etGpU*pE>3=&fx&OG6HzwSlA%%YdGR(s!B$!VaW%HFolFhDJy^H<vJbV>_SQR($yT zetvn=rvHwA{{7Cbf1N+I47|h1r|m%6^B?`IF02yVQ2+m5V1A-a<4(}#uAR13(x{bc zC1}6%JipsQo1jN$ ze#Y<0a?gA}*COt*X1Cq9M*bM1+Jbwm0}Q%(?A`b{^0SNzh`; zXBxR^=TFUvKET~jd^3rWe{LX#4 zr2m%Pn<}I9@;i^+@7{lO@x;vYpL-Ya&is5|a=vt)jr`ir=f7S1d}XEMh4|ld?;6jq z+p(r1apAQc9dEzi`+BZ?+Q0n!#o3+ex+muRi-~{sBmK_H`Ql1(9iQX+p1<78&OcQ! z{M|ZJaX+~grs7`Dxdon7eVUe@WdE}!<$vH~oBlP56ZYp{;gATuQ^CZN7OGJE;P~G2 zXKtRK^Y7Z<=*OGYK#MZ}eYbqSKmY!|Jt}Gr5A<2C{kzVBwsYGdK@Bt_*_phB6BMwJ zJO-**H-OgaXaCMX8}c?*-0%`wPHefX{(fhAK+5Cl<@4|D+-wqGv*OudXU0D** zHGlo3pEgXUOy`(A#hF+*);NRCT}lnnR=2->`oUC%+nd!Kz-zao^0W7pF|nKjZK}bx z4;*wRh^3b_S~__y_JQfa9W(S}EY5ITVfoH^W6?7ubwbK4so9B0*p2cu;Ug5X%U++}CUTc|h_Q$r{dD?G(e|rmBbYTP9 zLt`_4-(Hl`_rM)cGtJyRcQGh6!Sj^CdC-W_=a;up+i7Qd4;;D5P@z#&6E9`?_wc@r zC+7UOxtZ4Y>!Yw`%8DIRndePT{eQ+V?#$N|ziOWurUF$L>tB4Ev0vDYFE9P?%*FD5 ztzUP3+jD=z-{P8e>o40qX+87s{hahO)BpaC*6WhXZU@yXFDIBXvYl?eRA-gNR&)LI zzQtSqAHR3p%O=MltM7l(<2})quMV%1 z`mo*x-?3>~ays<}-u$r#%mqGIqD$z2%vF z*&pz%Tle;TU)QSM+g+XyntPeE|G;jyP?yPiyJL%JqB&fuGyA` zGWf&DB&=*uXvzTU4(Mgh^S@W@@0ld$a_;$M>vFL(-TZPoh5A_>SB`yjpZR#M<-?ov z3Rl-}D=)ipicxNxZBfo_%P(txT651^!(A!2bJrQobKhjwi(p{_6bk;Ol>q-hSK|opq<9?d(r^)8qEV$D%Et&3*d(^NjPwd?)_htou^1 zwz_Z^?E-e~dDCYN z9t}E>#tE9VToKJbJ9++Oervnm>2p4(&oN~-dj9|0?R@7&&G7Wk~dym-&+H)k^n9#y=Y zZ27$MKj@TW@t2>`Fa1}quHl^ z1oO*l6tdm_WBxyF=aZ`blJEiRRNDgU{AUjL83wNKYY6(<_r+MMQdjpM}pcvHql3@t1i zK5HF7%VX-crO)|m>^I}ukKgb2@8>xw^S{UVx&7_aDNIZ(ZJ?Rng*!^nQqpD32doE5 z=FJX8$-)ec3qc!Vy1dg-s|JI)Oxfx?{149C#CG7ab++FN&_qJ)m+8~IY&zcizQ4j^ zQMKmFd4=MAoA=6FuAIp{?=k!F*MEOmuhR-ntL{7h(^zlvT9%vlX0121yS=&1aa+Gs zI^X*ZpLuux{~|fZCNOX2=hC7-(_eoMXIrm)Viv>Sig}-(KL$;-@BXuW|KDEKf1jS) zu0K-$blYvOIp8%wb7kJmNw{KBe8%|PPvhgZ#n(31YoGhMsXp8G;=Y1M8|N%Ma@u;G z#>Yd+{nK|$xBO~Y|8|d%>;I?Pdhbg##TV6Q{!Y5^$>V)Y{JHsscRoBh`0MxIQ*+Iy z$o>3XzH!U9D(^sLwfgxhI0X`%m{`=@AQ@eE=H~mSE}s83XV2ApukN3EC~x-M{`d30 zM_D-LM1xM-&0X9IYHdSW@1X9+nVtr52IJx>W@uaO&*?s3#d-qIj2}`A@qeG0Pd9lC zs%Hzf)zzIZ)-QT@{@rfL`gd#AZ|ykI`S!__Pd{5Eg||8Id4BKt z-`jtsS0CHCKj*y6s=H z|L2#>z4w$nDd^n)WY=qNo1$~|HveZXzIR(_|0W~%KPL`uniuzM&h=|$Q$BCKHr?3m zKd93B9oARh_dd2H@ZQEFmj4e4*GJtlj;Q!k{59xD*)?%f?rHk_xAgV@HP2?ba&hmo zpGSXfQgiT|UU-csqU+}s77s&1MyAVJ206YBcha+Ko;^uFSHIf!{q(}V^JRvNOwXyc zc*A4G+8mEZ49yb^QWqGQgFZhkkuf-U@ysxQ6H*?aHNMEBQA&seToyY~#|d6^Gq z1kcO7nX%41V%2@&`JYq!s{8VfuKk);eQx@F6VWz?@#>kbKU0B#c$?+-hM0jSnF{) z{ctPGj~DN)Ocb#E&0YU1W#)Qud(a-|8TFuz!XIZoo^Q%*_4@2AhQj}A3@7}4KPUXp zzBhOFhbk+~Z?~Dh=H-Ovm0PZ@coAD0`!Q0pDe%!6$qTDE1K2?4<`}p#b$|Rm@ytv4 zGVPg@LF>DIg8DLBpa1>#?(Xd14o(4!_5-*6S6LiaKpPlkXnYCkVqiTRb`SV$Sd^;Y zAz>Gb+CH`e8|L`GzZ2OOBV&2??}@^*vlu|r@yGP#>;oT#O|X16v-zHNoSu}8LLijZFBln zYWu44i!%F8%YQ#MZrTUxJwT)8u%i9&om_DvdeX($sa_#eV zcT@Mt?|ZvV=>O;YKj#YNbIvzDzBtWo-Tz76r+(b~93SvFZq0`q6L0N%JWFc(qBETR zU(?Q2J=;=V^hEjjKFfbyr%!VktJ@dm-_Fg^{9E1c*4y=?_QvkCw^HJuy}_o8di(cX6OcIadCPzCx{W@Y zp6}kj8a%_)+$2kYcplH+Ay-w=);d2i52NyXU>pS95q^+4$r6 zp<-V21ME1?^nnhVES^?|Uh04fe9KG|XeS36PmMPPBdi}*2!H$e$fwFZfRmfu6ld|(!jQ!;MtK}?T{M`F$ z?^3IM-=92x{cB#&`@Q>%+;jV7UdP?rzj3}FU)6EtnkdUpJMZth<#*-G$^M_y_+8I7 z&oTTy`|V57zvAmwn~Hp@<2Jt{^F58XX;1wd^=zgsSsXfZDs<9yJ{DaG(db>x8tJ^~ z3ATk~`4RpZC!YCzjc6Xr6_yu3gC{5;e2Q{QCvKYLJWvaRS>ba0wSZITeBB$3q+|>XQYEh%YS}(i#i_n%q`(j z7Q>b&-i-~RR_VSCf8t*Lx%YLAA-G|3?dapL)sKwZt9~B&c*(wakFmPV<1-)Sj?~gJ&Hn;u0*`JAFzM>ZqxX0=ifg)H+%cH z`EM=v1sf|^yWFw*|Kc9!?tfdo=f!`Mm+5)$+5cI_WzPA}*=29_%xlip|5z%t|NZ;g z^iFG2hOF0K7kmG7_Wr0iyYb!p$W_KJzAg8z5h1t`>7wa9G_iz{(knk3CjIfysy7qRp_?%-|@w52TaYUNKUJNzTN9i_itVKmH&R) zTsgQmZh4wR8OQ!K-5-4 zxL=!u-v96W^?Bp->HnNF#RU``9yoF89DDzG>7VzpI!~JA|0L|3Wch1pp=!q0^WS9d z&$7RrzxV64IZi$e2dqGGHMgJ*Z5>x8sC1jzo)9axuseZWo`L*Yxy*W6W9Js`|9_5gLu-`y>&4i z8@6xQ{LF^`)1PF#~CQdZBU?fL&! z$o-nA{NvwK<5c$hpAP&JDsTD|_v_7s=fZ{mZ&vO9w=y`j&GA>fj49*34?ZvNTL(Ws z{eCBCgG^%auiq0F&p)63&+hc^uXev(c3!E!n5z2jPeW;5!0z-Z=d1r6l6UcKkh$Oa zxkfqeMrgg9_2X#qM?a(YJ^Ey{X!2%x%m3UDEwg+Ziat+G`1xV+*PuUtzW81FW-I?A zf9roW_n*HF>;IWoR_6I9s5B<-e_s3l-?94hZc%4{u)n{#IsNQxog?+{?Y}JKpZag+ z;`x@}K}S0D#VGSM{AvLW}2LEZ6)B;_uJN?vpZV-D(_ujV0sR zjk2^A;?vgcT^18zQ?=&E&%HNJtM^U+cIM{0D=ZR5?R$Lo38nOvZ%aQ{zKx$x4z#d_ zWk%hzE6=~5ntoARl}YOFX4|&%Loxnk8QaqR@}6j<_qMDxf2XxQqcXq#qwmssZ3)xk zX4zaRzMV1t*?)K5b9@q${yV!YZ2t8>?f)Zo?RjtgKd-a;rM%_8pP#ST|ILxzAF{u* zwqVsZem~pL-}5bEA30v(c_F{v^5)(<`8EDUuYYQpM{~0I|H<52^0Yha&yB~X=QMtm z*V)helOuVt{~ze&7`yj@hf@l!mZp0A&$tqxxmNr4?q$!uZ2zTy{BM!1VQu=}NaqB_ zzmN88QgcZES0QKp_w&!5IXAD>%>6ba|G(`0fL%UOz73l!7#W#@bthQ<-#Ifnf3Kekiv##pv})G7sEC~L&pTpw1KLq!oD)Jf$D3ZZIZrnpylF- zQ7MN6GnQj<%n!EzKe~TK=GuvqXIfsm%`dlR)5ZPbmeaNtumApq*EId>qr=(H59r%f zZSfPdT()(iH18rchi4hjJHqwffl>E_Z&; z`&tqAJ3Kb_*?B3!NasZ*ak?G9zl({5zy7*^T`F&zi+8edaDZ6uIC#s%h~5gHZPj|SzcIY|BFpUsft-vI`XT|*Drr| zX5)|dr_<+aeE#~#<_gOS8zs;Q&!Exeul#YTPg>6%JTJw(_+EYdpW1?{y1Tyo-(3Da zu)^WRV0V|)L-8$;uN)c^-3Miv1F24o^CzCoN} z?f&C2icA~|4Gc(xpgzM6PBhg58O)6SlIwq|&aZl*==q!P>62={bggxtxUAdUOWaOJ zew~xMK5|0T{HH0^=k`CJ(f?NV!sqC)noav_`qtzxcwSSzd#+B^nW8UyZB70?UHa?p zXU@|%-+p?(?l$L>XB)Q7Z25KdhsIa8*Q*x)lKnb;T1MZO(BogM-@gBUfc?pqxW|rC z-i_B8KFq1xUthE5`}eZ`$N`=Y=3_3UW*jd@g-LNM_n*(IDpPY`u#0IP zbNrV1_6s-v{1Nbf&({3AyG--F&uzK4=lP%KwSQ-tt!A5BU0tm`*YvCZ9WV7Wmn-U+ z75sM}jS@tSHh~#S8T1*_IFB2kN9ZS&1KbTZZ^g1*QQ}#^Az>QR+|4rO7ZaE3KEGeA zbw1MX^`3(VyU&@fW;F_<=u)JUQmvw#Q17Vg&N5nIJZ$7z?IbZWm;K8B? zw#UEL&i}Dv&4d1ZKYcsvZ{FIU@^*jq>)cECndA38|5M#puho8EjiHsdgv$)L|LE5|v44=MA36>Sx`&~is>j-zqJ z;*5Fq$L|$u=&Emhq8*YhFOy{KDS_=W1=)SauC1BqytVFeXv99JbI%)}f2iJlo##W@e*3-q zud{I6oo`n!QXx0FaPNIC_x_V2d*gr4I>LXae*ckq#qU2KopyMBPqi<@T)je9kjf4&K?N!a*yy5BTgtu>LV&3~$vesmJ}QTgQW{EA1MmLk6@)#ic0kS?d*zl(D>t)cGlf{T8&CZ#f1>c4%2|z zzq_mb{Qbsn@AB3fUP!gvx3FT}Re^|Fk8F!G+of3kxxJos-E{e{7nnZN%&$<)oYsebag{oVbIdw)MsIXU6lj1R9r|2EzE$4K)3 z`)li`{&3H)ntWt;-j29OpTmM5`>e6HsBJ<_;t?THE)BjfBS4-&9|)7bCtb+UA%c+HEv5VYrlC@ejHssf7%V^^FP1OVwk_{dz}2D zjZYQ)qkP%+&*%1@{_;maishx1G8NMAO<5-$Zr|eWSiEQJMv^|#qN z$N%Zy`z<$9aohWS=eO=SeXjn;l}t(b*kz{dO6Mi7-wT|+_W1s+`sG*8SZvG>NR!w$ z=g;G5&h}=@OilGRe_b2B-S64w1=r4BR_?b^TK;90)ZDV#<`8pNo!in|{mK`b)%G_xZiw)qZ>a?$N90+q?C5$-*5Q+_DW?vY1q~zdq0X z@~60ptNQ7^pO@!nS_?99g!neh`M)aANRWwFe1+4w`orrN&J;`dFO#`!=|(a12oYE@ zjX|GbmFh_waKVX0m}~@U0S!6(_q(QcdO>F{kF?*&D;K7byn*CQ>)}=zCSJhm$x%nT3+%; zX9Rzb+;u5_qe#se$(H|xuO%MNT&ua^N|xK3dwZkZD*XPxy1IJl-S^M;*!n*XYkt_N zK5xS7*PDL-*1aCD|8}-n{_m0reM1pfOs@!Zk{JL2o(md|sS7U0i5JN?MK`6sSDH`V%**S|=<=F{Xd zHr~B%-P_uf|NoShbL3|caA0W6;`s9YdwBA!X>%8E-@g6Y^=1DXR(!oVE2plGdBI7u zmZzvKQVxXxZpJu=q&uW{eInUpTc){EIa2{K9lUM-;uKN z$oAS-!9wj#o2AV>rvGei7IL3<*=}dle&uy@51TTny{-E&OX6Zn>dxDrBO+E>{x~`D z@TQg!U+&eB6C=)cr34lKv2A>HuIZY{kMD~Y7wv26^|#uxf4W43$VEp`h4Z;Qd74+S!=aA|M$04Ki;TZ8!2?Rbov(eZS{eH z@8_S$j*EziS!I9U$&@+B^8aza7gc}QK1Wo$w{8vl{IKEbmkl31`>%O)@vvX|JdgMHYXNr+9Ev$6e2%|g`@o#x)$6l2!L=h2k4$=d$W=!eq-%bD$_&n>Uo7cBUF zs`t|2{gdads#MtPeR|`Zoa}ErH(%_u+@(72bN$`f_jQ8jY?rxn|JU04lfLa?um1LC zqW6s*f!_~jv%J~<`~AG?cN0I}|MzXXYG3}o$Vb_FdqW-teE7Ai^wLwI(=VqUlVn-> zyVj$)Z||}Od;NvMM@~=kp8hW4K4X<{LrCAY9zE8^-_>{K9XGdIYbyEg-P%|0&rc3x z=vd_U`RhO1Fy^G6H#cv3G(E1;_0j8fyZw^*Z~d(->bHKk!d8egCcgH3`e(NPB$3pAzU}=Ue^%AH-^*t3crMA}x;k;g z$v@?L|7<#Q>E=rNPup^DtG%`Hmp)xp(c8P|>5KpM|6k5F`q$3?Pr5UIa>lF!*(^8e zs`~0nBHlk=k>2ZPWwfMl@nY5P64vAKlW%0l)%?`oulRQUuM_J%-#9*syVocIE<+mG zIIdVd-@ku<{JN}5|Nh2iO|RdSe|Oi_|EH#YTr2mZ{`{6-UyEvysvB^DwFT5SyH#|1 zX9jAdG?ocJV0GC2*5Z0MI5)wG3)7fp30N~XUFNq{u@n)Ck;u0^D7U=m*WWp2bwy9P zUOu!ud&wd;;j?PH+m`Tlp$fh)H|{aMoFCCw|HhQj%4$jdLJP%>>T~{_RlR$u?&qGL zLh)rcQ-z-Eay)(We)IcX>*M$Dd!t(A%kW;t>VEb8-*J+gP8VI0x2=o0wLWr@snnmk z?-6YA9INI`zMW|KbEOp1;j()1FS7B8sr@<^vlBd$H9M}ao9cXW!qbrGzR-{h)^}=! zs^wBYNwT=k{=X{uc*>Qf+~Qt$?yfx_?%yA`zvP^wz^?tT|Jv;RJomlG*5~sszrXYU z$4Pnb>Mh&;e4cyiqrBaM$9vrxwk=bx{?|3FIo_ho>3GXK|JmpN*Ihojth1)BKlk5p zzq!*q?Nl$e%Ip7YiDY+zgrt;0!23D>*fOaD*J zyDD_Q_WNBS^Iz6a=QZC+H08HxzkmB_(lXAPy7NE3zn`$%{n}?)iv_=}HnsqP?%%+nRWMl+vV|W)0+~i&wEJXR>njh;WY|JiwDwps3^8P78pSA_hsIXlzX{h4*1sfk?OkHpOW ze=qGX-zdJ(?V20E(JQ&SZqYo`Tkk$+WNNw=k0NN6u6qP;5%EcKigWirXD}`|BokC7Jc}ncXpv}6yKWX zJ5E1{WLYRv{l9O={6oc`YVG9Tn=!+{X`%g|R{TBP>-8sF?_zek-M{NA1k1oD;{_^g7U-c~SuZ!KSvhVxS z{gZ!0hwpWK6!O4+f3U2P+=k!lceu=deyFha-ri^KiM`iUH28Saqa1Rc`@gAq{QBC< znmFYLS8Xr7v;2R_16)*JFk$-p_pk5fX<0fd?Uw%|^>6=ooc%TaOyv3S>;FRkt$({~ z-Q3BFV5LaJ0Ul6!@2s&4U1mZ$V;sYi%I^`@pvZ+6Mhy&1#v&Xl9PQ~dx8E;%z-&2t z^1r#C9tzrarbpbUIr;GLCHuI2dvfN;*lN99m~f>?hx_%lQv&CI)^D*;d@DOK?tr$p zxc6`2^mAT&9`eo#esy1S`nk;IsRQ+cDk z{@w5_zMm_us!TX&%HbF3JMn7zxf79obFEZ2UO)4o^3weC|MrCZuKe`;^^=p6H`%|h z`<21H;c=G3p}eDHU1Lf^8q+-knn&;Qt`S^j@%t}#z(k#h z_WQJ3*|_fymj4)XZvR!54ldauyY-!d)xJEZFHS#b%yG(I_a&!QuDxFTt`Mua*5!VW z)->MFpJ)93`(&_vuRlIN_&)!C<-^avE8^!L-zR53fBWyBd+yF({_b7g%T4bauBl8o z7WCk}_p@0Hc8LmlGWBa~_<#RiyrFFC7kxfn?>Ss=eqP(3yXZtVQ_uQ%{os;F-UfI7 zth3$HT4ySI-ael`XAUF=a#^dYtFx=#em(c|`FrcTe*fQ#=Bhe@<&cQRX#$`PE;-8L zjmSxxL!rT;k}-~9%J+q$h=K>qYMdr;f#soOOpw-d`zg#hmTmv;e(Dqat5=!9Iq&oQ zb({q%CayQX9hq#h_IvEy;wLA*s~uC-OD*;Kb4c~G$~T#~OdZyFhhM)vD^`7OLwvkO z`irt%{rk^5`QWl<_x-=?j?{m?KY!8>|8@JKlK5@fZ{Aiu&3P`0S=lsx zE`Nn@&kBKx1g+TlfB!`6%b0k^!e))-jnB_sem?ej$@_}GKUaMH{N?Za`uK0JzZ$2j zemije`T6`+Y6liv75VV|wEu<8Zhaze|7p#!(0nV(ZdQN!Z1~5f8Q@S^Aj)#$XMSt! zoS&vI_VcCN_02;suN5XJg9?O<%@JDY1;S=g&~<80CEC%0vX8~+I>U_Z_lxxYCcWK# z^4=Xon?>zRe-B&!cQ4)N6+B6I`IY_E`)U)`&(ZJu(xR^)tMpb*Cw^ZH-`&FFvO?if zKg##nwqJYfb^iHd?YZ}hx7i-wf9d|SXZ5hN0A7E7KjnA1qwT(Tw_ZOHD&4;Kk+ape ze?~WTn)((t8)X%J)#_Y)uBX3bq4V)*k>j`4iR!H>mOZ5GzUA2QKR-V|T~mI)cKea3 zY*X*$Pn~D~{(P`|`#t;gb8}9*6s080|MFdm;gZGVgdYuGKF#_6NNBC$!?#91oC3D2 zlK=KSa#K(?pUZjs<-t0!YYLB@sEE z|F<<$KFTV$t9*OE==d~a`8AvcN3xh+yg7KH_}|~%&!>Hq%xudp__bpBa`iizUi{}9 zzsppf7yR}{yr*VRdwFtPnf%=|aEn=fhMF>~&f^T{l{7 z`Iq0GQp-7=zE8j3ANhR#vnisotG@i>k6pk0_t#zR@jfpqKmClW{Te!dQO=%}x&LZ| zw|&-;3I=yJbr$}%y&%W`{`$`~#~fbN@o#W!XJ@)ErD6JT7gS=X+bv1=M3~o^75F8d+QT^;=rE?eZJf z#ZPH|`*(HT`-$#y6N6i>6@NZ!?)_i;n;sf_UkcbOaOnVqI_S!z}LbP`wEDuoa zWiGH@kYDKceP!?)F;~KP`NI;N9l;$EtT9f0~~E_gcGr-Htb|Rel!_9BB9w zzcc9lb>C^tPej#irkzX^I5K(irPJ9=73cO}XX&syZGWjSefpXA2Vbm?TCDW$#Rk2q z*22KYD;|Uj0UBie||owQ7& ze=bfgda?I??fN7C?*88T?DgA!vBl>Lr=7g5!0}Y0JgRTcZ_A0#AM8u`UETYX=eP9M zyw#coWrx}9TaV29tlzs-Ve04ivae*S`HFM38C))|jox-bRL&;D^2Q}8*MECH*hmH_ ztoc$o%Q(Gn&cf=KONI2e&0l{hf@=>`>-ObI)pE+!aeM0@-r%$h*&_4zQ0L@J^GrM1 z*S7Vn*MHpdZx5^hWMoNGaX9zCXGYQOlmDw#w~HS-gdRo?4<0e?Vc4;QR~J28xAcH| zVQJbsF+xvIFQAaOq4Kx(nZhqJXPfp-_IUb7-fm5JvgOpyt1KN&o+oF8&b(2TblU0d ztqpPK-HJUm z4KlUg_k8ZnpYn0u=l9#E*KfU3{O|egpHBCAr%(15kML!FAGGDS?mN&h@9~XkvFgp= zYHojy{1vdX=lXKbS*wKhloWV8w=51zny3D7g~f_5m7ivDGoRlVQs?Vh-SnqU+urK# zEBpSv?OUsT8!quj$WPSttJ>1$V>4;3o8Q{`%YDS1(?N-)aT=)VNZnp`i+lB(c=OAC zCmlh;$hl7-!wi(XZuf1FLzl`@IKbT?wZKRfR0tqfAZOJ;As6`DuXg*>4b^;mp4<3; zTO%^LZ=$nM^?z`>TT;I#XXTNT7Z(e)H#r?FTA;3;dgA~6`}!YkqqlqgSt=es;m51% z=RIu<{|j~2fBNFD5_fg6DWlEuoBONZ-GBLQPV7t@cE=Z0d+zG5yj=9icKQ8mh95to z^LD!O#cob$JTmK}oa;iFyFZ(ojqVk937vT>ir+Oo#K(_ z{&zBmJwABr@6V6>cYj)0aoGz@|&Y!*eX+(Ci$l1FUt@4v9zFf5xy1%t-?val{Yb^!*eLQ}v zzuO=G==Z-b*+TM`OJ2wB&Dy#p{p?Tvr(ddi8Q#BtyJ?0L%fipqyY&^PJbwR{nVH$h zH9UO!k>uxF(hm1F&Z$1@F@5DfyA3kWR1D^ye_+b!WXjN`eAvkK&dTfRy-N?ge}ALs zS+M2hGTVt?`;~Q-76gijGFx8Wx39_e{ySTXb*2t|?=H>aj=S9W{AHs0v>Wrq*UxWaH%Zo_o$0CD{ME*zfgw{{Nrzz27uG|5EK& zyLqeqrxVI`oI>SQ=hkmo)@)n7rLFno{vXt!e z^Yf>h?)&kmTj;Y*>Tm4>^Osu|KkIm&Iz3kH)-*e_d-$qU-!Q*`ubNpTOB;oo8jL$*Sh>vtH0l`{SiwoCBA(9 z%KF>qZNS%A1;Ogi&xeYCsP_;5%i_}k3T~9p?-hT*>hSn`gD4_!A*_I6#yEy6b7lxb zxCl)bDjFT!YAPC+@BiWIdFk!Fe9I&Am|qq?5Rp}$mMkwZU&bz`&h5OS?tSZ6;Rjt` zQ{9i84)^#y{a2mFM?~`e-(3Gqv9rGF+nOW!m8YXs?(M7HedPDI%-$yLbvqX2>^3n| z`0&1~eV_Hb($0CC_uR?y`g3~syGfe%I|>#aDJq^G^~d^49J2%4^d^<$vrT;u1?MUi z>=$!y+q&PiFnzl0#ey^0Q9nMfzPotGV&}diVZtfDTb|u{AGa;!*Z-6I|13EoCv)rT z8ktY#Q-oKCd;eaRIxEy}|K{jh`Iak8EvD(ls=ZyEyYGGN`|3;Y?(fXs{`};8_y0eO zzFrOQzV7?|FLUSqkNe^}|LV_q9QN47DxTxdzwbBLD|{JV$6Ks34XdeG!RAo-e*)je zpIbMEJWgi}jg2xGcw#}vCdG-c-X{oQ$%lQurBSf0fcajr4_3QTyOD^zd z=IpyA(U%n6-!HNC_x0jm!Iszm?fKavR_zor{cim=TT!v=YbGYM?v`Kdd)@OlcirCA z)k|vsNv>U3__y=%rF|I}l{$|fJEoHN^|`0sHjy8ncihi%+Hh+# z^^3{2+Dn6vFFY(%-M9Zb!v_n?C-)<-zn|saS^qNDPyB4;`s?5SMc-Q`tCRk#-0p{C z=Ksa{b-_ved4I1ge{x~Hex%aJco}Q8kAGILoAhI9c-+Jr#bq|je}X1%|HTO>Tqp{% zeSWX_U+Siy30rNaJbwSVy6@Af(A7&$ufJ0^`-pt~-_lOg$GfL6>#hwnsZVg|o3mAl z`}0|MtLq9HeLSbv?AsrB@Ll@LxqOoxPe*Q>Q?*`DAlmQKx6aQ-FW-HgHTmxMZ`-|p ze_*#)Dg5Gm+HvzNap5vM*_d7X!}O**A9bDXeW(6=wMtx)sX*PY`oFDP=7R=^w*UUs ze)azR<+Z=Rovh&B)7G{KEJnomS1sLI>qDr?|bSWgsZJp32DEu4?a^EY$z* z>YUf_w9T`A_sM&{0j-~WKPmtHrCH49_rDdJ`G~vzM{4Ks8hf4Pc6Lke7y9d{Tkm@3 zYZR|lVE@~1&-eYGJFbaH{=Pncs$TNqWTF3;^#4veqQB=u(~*BRmA(w?Zw9=5uKmU4 zWRka|d;7clKTmSL-1Osgy~@Y`JAS5hetoHNHD$sz4X>wve)Dg*;a0Kx{}JmIrrKQU z{&e$@`?NUU0!<_%0PVC*g_o;PDwDxayw~BwWzHO+lz4|4_rw^lK%?~Vf zQ8Ot6(^ruPtPZwYEyd9#c!gf9`Lbu;P8gy5L8z^Y;Wkiq5+z^Dcc}rQ5CA{pxBa=@C}bnf|}qd0(DeTyKivywCNY zeiUZ@e{r|m`_DtyZk4!@4U1)!*-FzD?e? z|5AnGhUZta8IF9D{q~4!?ZOGO&hy`>(~Vw!Kl6UxUvb-I?)SdV{}=!AJ&HpK7YI0`^!)LioU)5{8#3Dob$iwe!cVIeJs6iYyN#!-1N2VZB^JY^=)?h z=PxmaOf}tQu{nO<-{;)^ZUOVn4Eq@`oY{T&7G&H4Qu%>uz!j4~tA1EcnxN-ilg*%2 zKb7SX(&#Z8Dzt&+$(zl~irR9y&S%a~zi;XHv?7Xc$@44aJkh)j8W)XkRjlV+F!yj^ z;?lZwJJUl&J;ARx&$+Ju^>4tkA3y$n_qI7-bmKf*7SoRU?Q`E>pRP0UXZ>H{S&x6e z4PL&a_Wq3(NA&GhTdrDdmNTL3eB!q`q3anhB))#VN#+Ot-IB>?{{K6zH~9wh?Y}SP ztj&*8SpHw=^hCcL+d8}cV9USv4nE)f`{?fKbNlbtpM2{8Xxr>-H9VE%3kZ-G>R=)?b_RFC!!1 z_S&?D`ssBy+rD0^4_c)0>!JPM2{M-ZQdb|@{&%gN{Pq1m?k}zVb0V^{-1h61Ba?-z z-0JJT-9CSMXYun>KTeBh^Zof%epl;l_x^c7)iK}V`HeJeDDa9~N_?^1X(<{~O2Yx*HkSO`kl+nrZy3r4(1j|kL=B z@HihIvn{0UNBN@o_|0y&obNCF{{F`42SE?wTfhJP@K3HiZ-Tf^`qksrdo(8~OGm|P zEWd9XR99EmU29+SccDe7@PVRfwKXsPef}207w-PkNG`eh`$m*{S>FYaTEQ*_U3wE3~|5!{48h_Ur$yO>?}m^8P}9+j_hC|7|{$*+xGx6_~bm z^DL%o^@pAX>%N}TeBt_g%YW}`k7RqOxb8i*$o62}|7zcM<+#hP%Rm3sl(AhW`{&;W z?o0Oq3-@1}ps^-4*Vg3AzkPCVWnDjZT(j`lft*2)m=B%)&JX9d+UCY+xc~u-={4vx>H*6#PZ`cnKgn5l6&oJc3r$yop-n` zWd2Har_a7`s~?`9_xb(x$JgH%KC(Pf*W@tg)XVMvCa(^EIg#u9^iw~#|Ly0Bx|;aq zs%=$Wchc#V{keAj2~{Q+-(Q+v|M;rWV{h}jDj)sV?R0yTk>vDP@ASj(&#&fpTwY%K z$La66+E><}%WSQ7h*a*j&A+(eS&n-c^MU=v`&0H_fn*>3_r%Af3u6@qf$eEt-l_&Q)?YFS{H$l#ic=< z;gBP!;ey<`bI1k_k(+*>x*FUlLKK`14lJwUm>tseS?48NWm&$t`%O0GJmcF9bN+i} zGyV9*rCt3e;HSle%QH>W@9eh*&7A+8#5`@YOvL$`?_cM{O3SY@d|>$l)QbDPux$SM z;vd0p>uk6E`!sv{-mArbYU^$LjIJ?!_-IkWfVI7@|zTc(GHO# z-6qffU3|TMy59e%*P>Ow&3XUhMquuIbN@$2CSOs1YyIi-SL+u>Kb#DT0{FkKxmb}A z@c3$!v9q-IMXt3EA6Wjs_y307X~yq-V*0l?-0RDDVahzmy}Dib{KxNtD_?J(Q)>VJ zWAn4O_V&k)e-%kT? z^5gZAJwMAL&rY${k6!S%6PyulIW0JxW#a3X#k)+vDW`sa%dg9Q2SOO@m=jj9)q~>( zDM%N%vQ{u&SR{Qq6+OWlgf@sX1e^W<58fk}YPwnhU!@qP+kR+RGI3tj3q{{wTjrb$ z@NEb=_y0pjp6k@&1RM6-#aq5US$d)<$u|AY@9J|qzJH%nFaO?@Y0ur``}esOFR?v- z@A`YtlD;3z%tc=L(~kuSoO_?9 zK5ajBY~E-2Xup~K)7m#**-`6Myk+vv;*=BhmG^(E^ySnmosR7GpL5}#x__39fAJpS z^)n5s{C?|iet%(o%-Xl?y6W{;qjI;;H?P~jeBJSR>2r0er<~e(-p)1GeTM(5%1z&1 z{8_Q?c+s!Li=G*%ZQPgK*BxejAd5rfT<^<26Yp-ED|>C8;g;8$Y(@VbC+^<==Kbs= zN%6hU|GbWG3;eRO|IaM`i545bdMQJi0(mS>mj7#OYg5;^&iTK|#w1PTLjBxS8J}|W zQ9OYY?F{-1pEmlh5kku#ja@7ii~)l3&1n5MffMZxSF;&@q_$@(&u(EWfOrll}Vr!v62C zzs_Q`+yDGWb@eK@gAW$yD9)QP;l^?AWL>7+@iqIE&L?g+y<+qH{9o~|;wyR8yJ-IVHBW!UullS$ciW=FVV{$yUfa@P^ZdT}i^7Ec zfBt=Ys4IWF&Q*5X;?H`4O`oHjm1bG{-+J8i^v(H~)4ru#%3|ut>}{+#bE~$t?EmQ} zmsuPCt(;Ro|M0u={Ju4Ji~j}xeam3^pUnw0V6>&=#zT(M%7{}mN)X$x+szZ+^K znv5Pe4htedNqUX-;a%YDfJCfV1ZsJ8oWz(mF+xyLGb8+-?<{?ta$?Wl zS(on^=2#xQWZkvL&0(o2W6rOF7xxplzqeR^Em>}*OtE+8yqK+C*B<=c+vbq-{QLW` z^xW?<;gLR?AATx*{_ySRw*4!AGCy{{9&BNu<6R7cmd9mZU-QfL{ag9_K%C{bPm_)cz5nr{UGf+p|J&~(E+pxrY`U6vDoxbytzKuuE&h59|fAZpEtLCll+vMKLxc1*KpD&~IJl=u>w4!;N;EUI&I*N z*Zcd+xyrKhpIVsIzwUhTo$l3}ww`|CE6}p;cg9^{;&L7!hCf0W1X z3{2}u{@u6B#`exmt@?AU76;D? zfA}N&Qe4cs*S&6SOKhhW?~TgtaB*(Fb^rEOQ?Ikn-ICgsa^!N1<**q=3rq9hW>#h5{dFJ9fGYek2efExu3hK`c?j{*|z`WjB7j|an>t8SN1j>_@#aJ=k)zOdTXBC;EeQt z{$Rn8d7tm!zpwumGIm+7KjFuHcE%a(@-+cfZ*FXKezb@6&)*9-WM991yS9Y!pZ^=L z=c`};I0L$b;gy9XdcbjnxHgD0geIm4p-00k(2&a6z4mMPP$I{Hp>Y*QNm%MMEx)3d z>Gs-|qW-lHxhJ(%_CD=dR^(&re!Hm0=DGcp=69BV4$6G=m^OcsCttO1W9p^j&%b~6 zexBL1#*{m#u5r$-Oh3)`JLXfG=fBe5JhkaS-Lhxf|9*RE!&j;9-uFsi{{1~pmj6H# z*PnZN-%Pg9I`vjgmEFXBZ}Qq_8`K+TF~slxY-{wN|KHL56Tq8mzMa|lGes`{cf3WS z<-=|A2c;P2F~8^L+S;DQ@}ovB{MEz9Z+|Jr*Jte24u8$n-fpt(vuGRNv|Rl-BmZ06 z>!W=e9<^+7pX}N>dGm7>y)SE~?08}7^rkA$+OrWj4`g$(*Qba*WFG5ftJ z*pyL+eRG24;aP#Qu6MuPO*?P+-lAlOPUG{QQ~tIraY=A8hQ;-*w}?dUvxa)1G4<*SNpTsXiUp@ANkE z{PeB+@4pule`Edq-PBbFA3QgIf93PDx6fj2mY4?Zar3lUWNP^5%gWC;zgGT#@}kgo zOUcG#Vay9o|NAHLfBpZ^-@@SbR*36@jC%VYORUS@d~n{`wNmo(jkmABDR$>?^-ov0 zxBZuydF#l0^rF~dK`2WF;{`42lcmTlXHY9G0JMHJwIBn%?YtnA#p-jJ;`W+%#gmF3 znldgr>A7=BwzZYYy{%?&Mz2#nTxYsPh_J%cVy(sAjnDT~RjW)FK0592T$yci zBHqfWy05wW?DOTHH4A4k*xmbGU47v&drMIXf3`21ef@{3KAEe=YQOG&yinC_`M>)6 z%Rk?|bf-Li|9tzymA}(>KmB9BCv5-YyzTBL|93pIm>;*v<$CtS{_W4Y4nL~i- zwfR3;zSXoAUE`j1`R#LUy~ri)IsYDfeq;IHDq5uV*53MSH?k&F_|<1v?f*An`u+VY zEeZ|=oU0c(^>h1c-Z^@A-#lK+c4!WBRPh5F%m10qeb8`mSjQ6dfA7TAS2stX=WKx) zpmH?rh>JS9%qQIg+zmDF zx%cnecHay;|DT*=DRke^P;n#sQRDQl7qZn=_0~kHZhZd5J6Y4?>5t!EZ!yf*H@)|3 z_xk5++OwD{{Py>Mzs#DvT5`gvmD^=LhwQ$tvEk>Rs^-@lf16*iFZt`}Z|(T;fTMNN z!n^#1Q;YviUL3`&9JT9)*n-6OhgypkeAkYj2w9H@8oxTRyW!vUfP3rPzM?H4Q)oD_ zg=r7NjA^aS9MIqgrASc!ZVPCqTU56FPAT-TUM6~?mX~3_)_TqlQ`_ad_ME?Bv2D)l z7ssTRnYo+WZuWkZ@iM5>_W7OSQ?}3RbIv#P=%@aTUgPurAa^rN$wWxuYO`t8w$4M!IKR-ei& z_u-Swcem>-9#8i~_tmZX+j7;pdDVVZ zHD8xWtL}U9GF_!_y3WK1<28$4{JF=N>HqW(dr^vQ`(3r}W8dCPb}lwwH{Bw_*rDpY z!iTR_Il)V^`F@mDp}n;=&u(PtmGJSM5&^YjkNo}nS4bG1=GN*R$Yg9KSNb!HSMJ~USn~Gn z^M0A?98V^kzgyATd;LQ3C+EMVC03t)2HC#(^(-$!Ki1~CecWox*YBpE+PUrLT=Q?U zn71X~pKYQ4x>M)*f9ve6Y7J$2p*@xkstz4>*)m-ei`zbA6ilgaTl z?L0ecKc{upKR&-t@8j=p{GNaKx93f*s5wyd>1oc=b(>~sXhogd?-Rx~Nzpc5Yx!Na zB}I?;Z&bXtw<-zfJCbd({9bXDEqgqhzwnQm&iVQi4%@%7o2ESH$JfZ+`X`HTh}iMG1eh_Hi$FaVZ$gZ8$s)E6DIF;K`$#; zFbeEoulwD|uJZP`HovV(#^3@cYlzGSL%RZ@!sdKJ9JaHvbppN0U$g ztS`J7WO?-T-C|Y0ZF_iQ&iMf}m(VjMkB-@;QDNC=e`S7u^Y(3}18-I=ke!lQNeD|*hKWq2!fA|^n zm-+g9%j5rF6h=Bd|MyqOzV3dlQ26hE(@ug8H~<%CjbflCWK==$P8IY3h-naK&~ri? zV{dTa1`QapnospcZ}c2sUBUQ3sqscOQ$_iD!3Xyb{<}H9&bMt(k||SM#owMS`LkrE zSKMyv+cc{Rj>+n32{%=mw0 z8+ZM^Jj;LYKF>W+asKE3AEnn%YVNZ(Q`=bGS~SP`tx+W}Q~dht96w^MpHJU(jbp>d ziozTcnG3#4``)qzV)#x^w#5y zRt8gsw8pSJk84tl_P;l;KV71~|My*?{hNy0kLcU|-!4>r?(=Lu`H5xcIls-xeHp`5 zSNS^3(!_3qf0Fk~y{iHfo}I|%izr_8tf6n7tH_y;+u!fIttq!zrarr`Og~zyJ?`B+ z?TycW+}}{Sc}w+&6E9ZCe3B{q&UMXV!p&LsCt{Qzyoubo;#}-`FPn{dbC1ZWc#FMM zJni^>7SknfSAGX8nujC)@M)MTUKtxP5ZceU z|F1jk@%!i2X_o)u79V_kLE2)cWyw=r$;#e_`ny+EuUp!!`+j}*{$HV)-xCh;|M*<| zrseyE8}rs*sndyF^Vjy%Pu=DBcK`l6#cDqPhR^DCcG3Iq*I#_pYVJZ{9EOOHo{0 zzxZCLo|e>$@MV;LXUZ5CyWMS9g)ifJONF`K2c^&To?00GZI9B&(0h5$KhJr2W8LxF zlXc%u`MG-TWBtj~na+RwR+c3CVNQK+?;_By{GyC|dn$#%t2F}7HeC4Evp!n=v+KO# z^=l_Szp?z+@4uOr-|b?r{m3=Df1f2wz~+{%yZ=PPS<5l?6fa?zy966|v{r^GB zt;CwQQML&e??=eo{QSg}^Vhqb$K3@Gt@AAt81^$>aGHH`DY7p?bv9YsP91m~x=)(C zsMuS4;{Km++o$in^qTqY%7goV&R*#}Ri=a4@_TJkr-rxAzRs(b^0S3-~~JmDy-HG&RB# z=Yor%X2uu30*r0suM`}38>|$HyN+>I_|*s+Q%>Fr#HMeH)Z^^wSJ8l zBg-pw(D3j1S;iP8qXB66w`ZO(x^n{TK|aT>Ba6YL=iht(n78jIrSF~NHsAhr)!zDh z*WX`%T=?Rb(_1@vP&4VmDyDhN_f}m$SqiZ;pp#)gV?d`I#?bx=&<>@dO@TTX1(X+P zrUbhVQwF$>1$$XeWah8?`)v28t#|vg?!Uh}Z~eCL`!$=3_nY6Jw?T7>j1iE{gv5eNj!l4g25v@+bUYyJxce z;BD}UDM1emh54X!jh^q@n1${VBTzd>SbQ#e#yhc`!Ia_C&ipmMl$hd#A1K|m0JWw} zVjdim&dd2Bb*qwbUh=(jVwF3}?yqN;uQA|1oj23;Ufu7vMY{Xs!JC(Tbr0k-n0)=V z!2;dRRmumr8(vu$abv_fXy|C!JvlM-+SQ?yWd&n^ta}=?PHB|ktl<0k-2VShnYH`= zPJ8wHY8_JyC^rPig32DNzB5grbOXuRV3tEL_Xnm0E4Q~Fg=7D`y#z5jjr#?`I&Z`Ru1@?Wqq{LQ~srvK+RY_vXfQ*gyR z2LIx(Iy2D+7aEs|K45jYoX5-U42fxY#4iBt)><)76|>CP!gPfpJKcRU$wjZcKiLfx0=yac18c9tEzYIFcW`Z&T#7w z+k;PNF?-9oL7d_3#`7^~TS^>eg97MmK7*b-+-YE!F0f@;!FWOL_Z_qFou#j@`CPws z`}XXW_1AtH`^L4Ni@bjP>*oKFdArwq51+R4=C*0`%jGhZ~L!uYrg+A|9a;S=zzBwS`O#_ zhw%ObrQ?{GhWjLMRXV`k(0%&?M#4JH5x~44b=xFvNZMRb%epP+rjmHPj+pAdKhN#; z4ITHfp7?qG`@fAT@7hKq@4t-|vD7Ve>5LsXO2_3nm;MgUT`NI#w_S zAnEujq#^R5ocb<7I6hXm2ffhf>YYTfNiV+0`T5D}Zn7{{>07j*6-LJTz2bQ)ATKHWBj z8{8#1vDiW5x&3F;w>v}H1B4xHJ0LkY!x>Zt@S4x{M)On#sIJ{|e_ruX6jK?PazR6a zW_L>TK}>LV#by|pa}gGeTEf%W=6nu z55ogJB-0?di5C=|Y_rd(qN_i^&F~I2=P@v{+;RY|Hs5eEMhQKL_Aoq=A z@_60GH1w!7;`+d(pe%70Ju9DB%%IQkX-D=Nw2)?K>;W0Y;fAro;}ghkn|D&#Xp!ll zu-GB}*gu$?8nZZZY!+{RvoqwemitL-|FBB8Wzdoq)R&iLsJv}>4ebn`h66e*6^sVl zCT++$5tQpDn1ePm z1Y!eF3#ht>Cq;yPTN*$cE)#@zvY^L{6Vo0B4$g}hjbCn1%beA0qBq1Ygd-GG4sat< zJ3XwJJu`0|1B1dEPZ!4!co>o6qmpe0Oba-3buQe$uOGg@^mSP0YS}AQ|JJ;I`s;V= znrpv z8doQFGwf%a@Le|LFM2{b11b!R9Ts7NA?+6LHAof(WoL*ohh9(>s~oWmJ$@F<1eM7?yAMVo#~LUPteD7P%8 zbscBJ{Pzw&CDwnkyVo_ndrJRDt@pxNNA*>vtd;fOvxzg~eSmL6)^&y#@84f%6-X6Y z;dE~QeEkKS!|`G7czE$5a<$7N0~atAeP&svwi zn=)g;My4l!!mrQ2k82Eg4@1VO+{8fifDHk4dar&>F+)!?vw|9=7)Ms9Q|5CGS{_%>m&qr48314{N|K~61Yi1@F z{mb5MZNt0uYib#WQ=CBOlx^hI0dIN+6#>vp*mw&xO|os@8H}nk7}Wkhbvxkood37; z_wQY$eJ=W3eW-pN+vL=uZj={hm#C=YdlAf=&1C z*}M*DSVrZ5fBl-@ktw<))f` z|N1r5tg*N6am{~q8O#6M7MAk;xS`{c^GAbF7xnw_ojk?O*Wu z*k1eJzog%a?^4^d>FSgN-0LqGn{K^ZFPE~ne$%)4RqwL?+`NAO#r*WCRUuaUf-a|h z=85&+UENyqY1-%a*C(rV%4B_;#qi|M=`vHB2j&b?`&e}#0gVXv##^9r_1m#Ij0iC> ztFa9v@i6)T6Gnxy*I}Q%Qe^e~6?cpN#aI0MxoOqgX~ANv7%yb--`6=G_~l#H^M-pB zhkNU|I-Or1^#A)|(rtCoAAj4zyFB?3oAS=bjllCkx8?$%ir>pxHWyx#hHj^(Xg zyEHz@{LOm4<2Ps+78W>C+Mu&I*3DPxlv!2o%TV;Mb^lA|I_3p0w|8K4kpgyt7O$D7 zV62Iq1!@xe?swIJ&%D60;VITz``8>-KmW7;!=KNhcU2d@KNn{5)1)~&w)j9co6qJJ zpZ2V`!P)&j;?b|>eBFIy;m_>1&!6XSS^oRyFQ>x2d!1gdEVYii+46DK`swp~pI>(E zIL-Ow?S17s-LL0QyMI13J5=1ZFrhpn@Same+ zP+g~V*mc6^`HZVMcUAR8Y8?M`dH&y?HM?$EmKjwtGkxdKRa_me(QaW9pJ99Un%pOz z*!B1G747%`yYT0p{rkeDadm&!zH6WUz5-m$EWDQW`{&P3-}Z$4e%~JU`+LXx{H=RW z{47s|I6VjCbTj=baGw=ir9p@Z-k=s-(d`Hm^h)w3s4hI)eGlDBPl6U0PhWj*!;7%f zKkFaUPQsYckV$)zFoyVWLEr}Rd@eZK!b|Lk>p!#wQ%|2*$4!}aU;Z|7L8 ztoN^9ug<7h%Rc#YeD=d{^XA`Y$aw$v`75+^bjt4 zgd6W%XUOVB$|KFSRRko?ietrnhJAd)=wSt!AQV&pkS2ZZDWvZT zZy#-04q8P~e19j}cyXf{XfAVhuElh;uJna@ptXG$vMm3vExR2$>+}1^o9mYEyJ_>c zYSX&&$DiL-e*Lw&{`-e-0dF3ET(ic_eRuV*ukG*b^S^&wTWA04>n?YVZyzhBim$$+ zoqcZq`Zk$z@yvBM-uJIr{rO|$eD|V%uV)+ipR2!Sy=Uw1&(aKQ_wJ98MGZIxCVTM* ztPJK%=)$?66LidOr05BPi)IATxNJS6!@2$Umi+%2eg6`3X`hYyh2jIR_RLvv*S5x9 z>+6b=nx((rUk`r&`}FzvmF`O)-@YrnzuNdNQ^munPuo_0JHK1!`8xOeUjP4n_!wDy z=l0vmJ0)+orfx5Nes1n1J4;K=!ljP!@$pN8uawltO#b}e{`T%_70Wzrh67TC%2U@n z$U5{Knc}J%;?-)`G1cPn2e)Yz4J#i_>2o-_acbmB@0$f@i&lCaG2U({VX{lQS6^Ao z{_lsq_vVUTS-)L#!_jUQ8^(YmsRq!i)u4COzX(3S=rF%h*c4S*L#TiOo8p9a{85$C_ZPHMl&&2vw?)z6=lUa`Tr zyndJba>vE;`f-<;QuluRck1lDUw_3Pum1a2`T4`|lS5vd?a#lY-!g61|J47&uPbcY zctXsl-*qV6A*LbtfyJS7+C~-*~y!+m}v_4+rZsMQ6i@sVjdOdz!yJyz_mppQO zr>C7+{d4}g_IsI({tQ09U#LQF*@8N0w?F~IhHjHvED)n$k~72#7!2Mno{oBD?Hi|r zkL3(2e%`-UE1doB*}9M2rj=WF_kX;$PW<`#z5jRAW$ym+-fa3h`&$+BKBvt|pR2y# zXn)lDYxCt(cW2t~y0*HuW!;8UM$`Y7Zw7w0f4jK+Hq$(Y8)bDa?$8K@-s_bnSioSw zz1S5c+!_vSW0hgZv9@2N409z!`DPB2|BI*Yz5eI_pLel>U-sAi-I`JJ@`1j*z22-z zzpZy{blbm$t?s?))Z*$RHCL`>e0z3&^NZW&))m?F-W}hsZmIqE-@V!KdG?F{+xX;7 z)0WyAx3eZj@X#XXBK!MAzdPd$fBg9E|K@&__4A3{=Fh)govc3Dd(QdiOa2$_RC#;r z*vpbtv5Q{TnEv;z)ZMqCL7hR2t=tmjGDn3CZ4Jx~rdMJoqXwsr&I5*o#DeK){>kRJ zbGA0n^nY=;-tM?Hg59R+8|}qo-@kV`@izbEzo7q1AD@oZKPLZv{hdEMe<#}%ufJcl zSK|Mrc^`kR{cipJmtkF9>LKsnM_)f(B>VUC@+;cUcb3%m*w@t`E0eh&-CKXo{GI+g zdvp75tAF+@Wk#Q^f34!DO9%9;m|KR39)T#Q)qPjq1w} zo{g`{8G6D#%Zu)>`D0O+dA01_`+L*a#Iw&8eU82!^K6}cd41mhjcoecl5KYG=bpDa zE@u7K@|S<-?*8wUZB)6eKHTov{;kV@8;a`hm3RNH{ncx${qLOYI>UWSZ-4xpoNbp~ zA2;RM;_v6rUtb?Do@;6Tuf|UOb*$d>C9$_H=K5{*HkrHr*?!ISN6pn9a5nU+x>%rP zvDOCW2C-GwR8Z58v~U5#hK(&8?WnP{ML?sD-Qm6Ie_es=F~;G=bGvoV>95u7dp-Rc z!?B;m+aLdX7Pr4_@7k*c*WN8Jsk>9ZF3ne$bnKYlEA z`txsA!v74T*pJ(HFYiHZ6|IU3G*Zw{J zXz{vAUM#wdx!65_Zz!t`;|8t$-Do#)r?SW}=sbR-h3dtGP)2r!)t`1-pl0U?H-+DP z4HvWjd1p&J_lsWh^LCZ*?>oQsW7l6(KX-nwu;MfI^8H6XF8zJGx;J|z`}v@aB{uu7 zEZ%Z-eMrvz$B&=8zs!65=gxEgyxRHVD=)l|%lbE6cV_tK`E~y@bG;7;Gu%Gao`ITK z9fTR#8GIvjy-<_RHc--u{wctV>b?x65B2XEZd9MG|Fe5#plSGF+2i_m`%D`*rfn#- z$^Lz0*6pR=-e}O?|RkopC9Y;WdC2g)-Sj8`+BB7}>F@ZQQ;0`k($uC!)X4TrC;5`J?*Di~#%96~{yW5P93Ey6u9pnA|ym6XF?sJ=;OXD^k)$f|JwYV;Ib+5VA zzdgN7(cgPNUf(CIu+Dsz`?_cUYwXljvi=G8-IPB5xbU6n^xDjWcP>V+&t~*zD4A<_ z5G^IYW|3itd7dJInj~IC9bk00{!-WmRd|Qr1HEg1j%V)tC$1lNL^Cwk^uK2OnxEaK zdp5f1UAuGj+J@y9-|Rn{{oit%GdLtRm^Q|o{eSv>oSI@ha!E1&_xp)E_18VC&kKB= z>v=$!A^KEX1X>zaW@KmRP0;m5OT#J;7!tg13UH&kEJLN>ddA(=(`&!Ii8T85_xE?t z-P=B%kFT2@~Ut7yv!IW_S=T>X5f8k}@2YW_#hCCKjL4$?{<_5+|Io;rt5BJxD4-20?-PiW; zXt%iQ<>a&V7gL%!;R&Wh?ZeOKm;axCTVv<{?nTi~pKs5tuKro>1h#x5%d&c@-qghH zs0Jo%XX0Zhn;j*MR=3r2Sup&#d}u#vKp)6seV0`(mOV+%wkl-zlAj2(%CtXx+CAO( z`?6>DPeVV?ugd7veZbkU@pJxngc=S31%r+T<_1Th+}Wt2+Zvd$sde~j&9ErAM&04f zbv1Z!8B99xvqtaMyL)x>?PT~|f3KHa^K5_Eg+I2S&^>>1t2t^werRuCX4uYzngk>q z4lo{I@Z9E#s@CAQHAB&o{QLWS+iE_aHTR5ehSxL)rm@!jdb!-UwcKj1nP~s4|GrC| z4OoO2{TWnbq)6+baZV zYC&9dU;`5$R<*15GbgCzRKuH?FZ>s5YpZ`Z>;L7KTeKF<`XBl;c8<;pkLaMOfcTjGOcr34PT+Uk`Q~x^G^ndjE2|qYu z^dE3Gyk6UbX69Wk3x*eFrA+Eziy>ZOU}U<^ZNaeP-YE~%xVx~np`4*)wpAlMT<$0d zWdCzt|FOR<>)+xIv&O$16-){CJGTgLPf92N{W{Po_pfTIa4 z2J(cB#sgUf{!1_5!F*#esOhoM?f<`j`?P!u_pUm+Zbprb+hrhAMRd{?m`8UqVr z9M0D7oGHojP3r+?!``%O`@kyUrX6r+;$yHo^uZrBP&b4#vNKelT~mv8VRJvr9_9zi zJpYkmdV$Y_3Y%%ZC;IK4v`aWP9MEN&$FRfotPHAw7iKmvH=Gkvi$N7G=x$(ch`w@0 z5jBa-<*ZsP+N#qtW&Lw%lZ2A2XeUN{|KbP&%JQUUYevAaUJ zfFS^zVrzz79+MRi!M8?v!LxeV@^IA)P6vb;bVJs9!t*kiVW#$gAt9MlkPp@T48;cw z3tCs1A`AkhkORk9_AsNWM!5eLR|V68wd=2yb=}6 ze!jPDex&}Py+NJf4i}0m9TFHA*%_EsZi=DCP6IQ;cX*b8FeDrfSTnGBY|=%P*ct)> zpW_=+H5%u!*f3rQ-gX3$4Z&$BPo#jMKzU9ks+9}W8QB?ZQ@z)q3O{gb{Lj?Ovw-{I zCxL4W3=9mOu6{1-oD!NclMM|S7+5}Z2Kc%2a!GM9Ffj0Xdbk8JFfb^9Fb5k014D6D z)fWZ^#>tt^&H>;?uD-XzUy6QU)x%G(Tt-@siW*K^IkK>%RBoPidH@- zs;l`vr}+F|hUa4IGmrKuELgE@UYF~RpJ$k!*R`?VebFpEc~3&d!xSUNuJ?b8?cO~| z_^Eav?eE@vY1^c80u1c#HmVuBJoot6>`BV%G4Eh6iR!ADzA@#qc%q`w=ZdL-4LY1-D`W3f3Ia}-n6TiC7pN* z&nR&6MNSEH5L9ED5*oy_WKqsV1`gw(G;f-wX^47O4@QX}-P;S_}*f91M)@nG7rp3=E763=C4B z7-wKwzyudjSip>6gJk>t98NMYFr5LdXNllE8t&_-ZOHS@rm*AP%3HeLI~dZ+Cfb#(_&#q$9J1{NOHSp$lG3R|La|(^l{jmvE3Oae?=bQ77RlYfVIjwy8 z$LZt8gDxN6_2%EcZThG4X6vl}ICZnb!_NKtll5Zl?3cfJcW&+1jfNH0E(+;yZcf@P zJg;(Ns^0v08oPHYN+md-2opUr|A6@%p28!?YI8;A+-3Uz&G5m~R?R~{f9;yKk@p0{ zvERFAKfS+NTXSdn13SBpE~U@W7aSx%?dM$@{Kq-Lh-1ag%tLKk9C*U`9VX~+yM5s4 zo6na|=I7_RU7K-dPas2?Q?2zBg)aX&(AVL zGve&W3K8x9A2m8|-jbK97X6vf>AYjMk3@F*?*BKc@BQb>Haqy6i^r;^fcrOK*bLjqYW!E_#p0}*dAJ;Ojd0zbL4Xcvs z=dZKWcF(;aQ2X|KqYQTygL4&Q7Hj=1dz%a4XBaFCnKvw9ZxCf^lsr~+#AyA(8%wSQ zRVBaHPR!HVqAC*FSF4`>`P!bW*ue*>p7Fc{{H&I%=|oR zwxCh69VmUn%e%a^d|7BlWvNBQnfZBkj&)#Jdl~vGGYrBG_YNgS5Q=nf|vx- z7y)6X7RUGnyJRMpWaj537F8}%RF3cq_6K`_Lr_XZ)5zS@ConiVF{7ZmskObcr*Fcf h=^M80*}Lz+(F-@9y#$360|O(d%m6V}Km-#01OVAZLj?c; literal 0 HcmV?d00001 diff --git a/src/mac/icons/dev/86Box.icns b/src/mac/icons/dev/86Box.icns new file mode 100644 index 0000000000000000000000000000000000000000..5ff137b55a47114bcd3988ab666df6e9d0d9ef3a GIT binary patch literal 217773 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�HSwEDAB>dhqi?XvaP<*s{7h4jM|SXvGo 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�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 literal 0 HcmV?d00001 diff --git a/src/mac/icons/release/86Box.icns b/src/mac/icons/release/86Box.icns new file mode 100644 index 0000000000000000000000000000000000000000..4f15661ed03c6ffbe15ed4bcc8359d9d64417f8a GIT binary patch literal 196323 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

    @75(!#)zA>N?4P=i69 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 A_y7O^ literal 0 HcmV?d00001 From 47284831880de010571d680c71d4ca48453de813 Mon Sep 17 00:00:00 2001 From: dob205 Date: Wed, 10 Nov 2021 10:01:37 +0100 Subject: [PATCH 113/140] Updating the CMakeLists.txt to create macOS app bundles Changes the CMakeLists.txt to enable the creation of macOS app bundles via cmake --build build --target install including all necessary dylibs for a functioning macOS compile. --- src/CMakeLists.txt | 70 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49025d4dd..db085ceec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,15 +9,32 @@ # CMake build script. # # Authors: David Hrdlička, +# dob205 # # Copyright 2020,2021 David Hrdlička. +# Copyright 2021 dob205. # -# WIN32 marks us as a GUI app on Windows -add_executable(86Box WIN32 86box.c config.c random.c timer.c io.c acpi.c apm.c - dma.c ddma.c nmi.c pic.c pit.c port_92.c ppi.c pci.c mca.c usb.c - device.c nvr.c nvr_at.c nvr_ps2.c) +# Prepare the macOS app bundle icon depending on the release channel +if(RELEASE_BUILD) + set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/release/86Box.icns) +elseif(BETA_BUILD) + set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/beta/86Box.icns) +elseif(ALPHA_BUILD) + set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/dev/86Box.icns) +else() + set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/branch/86Box.icns) +endif() +set_source_files_properties(${APP_ICON_MACOSX} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources") + +# WIN32 marks us as a GUI app on Windows +# MACOSX_BUNDLE prepares a macOS application bundle including with the app icon +add_executable(86Box WIN32 MACOSX_BUNDLE 86box.c config.c random.c timer.c io.c acpi.c apm.c + dma.c ddma.c nmi.c pic.c pit.c port_92.c ppi.c pci.c mca.c usb.c + device.c nvr.c nvr_at.c nvr_ps2.c ${APP_ICON_MACOSX}) + if(NEW_DYNAREC) add_compile_definitions(USE_NEW_DYNAREC) endif() @@ -36,6 +53,7 @@ endif() if(DEV_BRANCH) add_compile_definitions(DEV_BRANCH) + set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/branch/86Box.icns) endif() if(VNC) @@ -63,13 +81,41 @@ if(MINGW) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".dll.a") endif() +#some macOS specific configuration steps if(APPLE) - # Force using the newest library if it's installed by homebrew - set(CMAKE_FIND_FRAMEWORK LAST) + # Force using the newest library if it's installed by homebrew + set(CMAKE_FIND_FRAMEWORK LAST) + + # prepare stuff for macOS app bundles + set(CMAKE_MACOSX_BUNDLE 1) + + # setting our compilation target to macOS Mojave (macOS version 10.14), can be eventually changed to macOS 10.13 High Sierra + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") + + # set the Info.plist properly + set_target_properties(86Box PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist.in) + set(MACOSX_BUNDLE_GUI_IDENTIFIER net.86Box.86Box) + set(MACOSX_BUNDLE_BUNDLE_NAME 86Box) + set(MACOSX_BUNDLE_BUNDLE_VERSION 3.0) + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "3.0") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "3.0.0") + set(MACOSX_BUNDLE_ICON_FILE 86Box.icns) + set(MACOSX_BUNDLE_INFO_STRING "A emulator of old computers") + set(MACOSX_BUNDLE_COPYRIGHT "© 2007-2021 Sarah Walker, Miran Grča, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others") + + + # preparing the code signing for easier distribution, Apple dev certificate needed at one point + #set(XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES") + #set(XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-") + #set(XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/mac/codesign/dev/app.entitlements) + endif() find_package(Freetype REQUIRED) include_directories(${FREETYPE_INCLUDE_DIRS}) +if(APPLE) + target_link_libraries(86Box Freetype::Freetype) # bundles freetype for the macOS app bundle +endif() find_package(OpenAL REQUIRED) include_directories(${OPENAL_INCLUDE_DIR}) @@ -120,6 +166,18 @@ if(MINITRACE) endif() install(TARGETS 86Box) + + +# adjustments for macOS app bundles +if(APPLE) + set(APPS ${CMAKE_CURRENT_BINARY_DIR}/86Box.app) + install(CODE " + include(InstallRequiredSystemLibraries) + include(BundleUtilities) + fixup_bundle(\"${APPS}\" \"\" \"\")" + COMPONENT Runtime) +endif() + if(VCPKG_TOOLCHAIN) x_vcpkg_install_local_dependencies(TARGETS 86Box DESTINATION "bin") endif() From 9f78c37f37517b7e1f0fac44a7fec1814fcb5cb2 Mon Sep 17 00:00:00 2001 From: dob205 Date: Wed, 10 Nov 2021 10:26:00 +0100 Subject: [PATCH 114/140] Tweaking things to fix potential compile errors Should hopefully make GitHub Actions happy --- src/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db085ceec..d09b4ed34 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,7 +53,6 @@ endif() if(DEV_BRANCH) add_compile_definitions(DEV_BRANCH) - set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/mac/icons/branch/86Box.icns) endif() if(VNC) @@ -170,6 +169,10 @@ install(TARGETS 86Box) # adjustments for macOS app bundles if(APPLE) + install(TARGETS 86Box + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION bin COMPONENT Runtime + ) set(APPS ${CMAKE_CURRENT_BINARY_DIR}/86Box.app) install(CODE " include(InstallRequiredSystemLibraries) From 99097d5555aa1d591300049658a879f39dd6ac0f Mon Sep 17 00:00:00 2001 From: dob205 Date: Wed, 10 Nov 2021 10:40:51 +0100 Subject: [PATCH 115/140] Adjusting the install command This change should hopefully make the GitHub Actions instance happy for CMake. --- src/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d09b4ed34..8d2ba286f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,7 +164,11 @@ if(MINITRACE) target_link_libraries(86Box minitrace) endif() -install(TARGETS 86Box) +if(APPLE) + install(TARGETS 86Box DESTINATION "bin") +else() + install(TARGETS 86Box) +endif() # adjustments for macOS app bundles From 23b01383e07062a3182b7f5a46bd39544d117ae0 Mon Sep 17 00:00:00 2001 From: dob205 Date: Wed, 10 Nov 2021 11:13:10 +0100 Subject: [PATCH 116/140] Fixing compiling with normal user permissions This should enable compiling things on macOS without resorting to use sudo before cmake --build build --target install. --- src/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d2ba286f..3e82eabe0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -173,10 +173,6 @@ endif() # adjustments for macOS app bundles if(APPLE) - install(TARGETS 86Box - BUNDLE DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION bin COMPONENT Runtime - ) set(APPS ${CMAKE_CURRENT_BINARY_DIR}/86Box.app) install(CODE " include(InstallRequiredSystemLibraries) From 38feb548ba88ba3e4d615f8002be6037e691970a Mon Sep 17 00:00:00 2001 From: mariuszkurek Date: Wed, 10 Nov 2021 14:38:16 +0100 Subject: [PATCH 117/140] Fix build on case-sensitive filesystems --- src/mac/icons/branch/{86box.icns => 86Box.icns} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename src/mac/icons/branch/{86box.icns => 86Box.icns} (100%) diff --git a/src/mac/icons/branch/86box.icns b/src/mac/icons/branch/86Box.icns similarity index 100% rename from src/mac/icons/branch/86box.icns rename to src/mac/icons/branch/86Box.icns From 64d428606101744f3a582313d02d46fb1d061a52 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 12 Nov 2021 01:30:31 +0600 Subject: [PATCH 118/140] Fix startup crash on macOS when loading floppy images --- src/floppy/fdd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index f8016793a..72f79940b 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -497,7 +497,7 @@ fdd_load(int drive, char *fn) while (loaders[c].ext) { if (!strcasecmp(p, (char *) loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { driveloaders[drive] = c; - strcpy(floppyfns[drive], fn); + if (floppyfns[drive] != fn) strcpy(floppyfns[drive], fn); d86f_setup(drive); loaders[c].load(drive, floppyfns[drive]); drive_empty[drive] = 0; From b4f5ff7ad156ef450aed1ad0293fe59e226dcd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Fri, 12 Nov 2021 22:41:01 +0100 Subject: [PATCH 119/140] Separate language dialog, and minor language fixes --- src/include/86box/resource.h | 9 ++- src/include/86box/win.h | 3 + src/win/CMakeLists.txt | 2 +- src/win/Makefile.mingw | 2 +- src/win/languages/en-US.rc | 24 +++++- src/win/languages/hu-HU.rc | 67 ++++++++++------- src/win/win_lang.c | 142 +++++++++++++++++++++++++++++++++++ src/win/win_ui.c | 4 + 8 files changed, 221 insertions(+), 32 deletions(-) create mode 100644 src/win/win_lang.c diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index eaadaccd6..306a9c839 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -29,6 +29,7 @@ #define DLG_SND_GAIN 103 /* top-level dialog */ #define DLG_NEW_FLOPPY 104 /* top-level dialog */ #define DLG_SPECIFY_DIM 105 /* top-level dialog */ +#define DLG_PROG_SETT 106 /* top-level dialog */ #define DLG_CONFIG 110 /* top-level dialog */ #define DLG_CFG_MACHINE 111 /* sub-dialog of config */ #define DLG_CFG_VIDEO 112 /* sub-dialog of config */ @@ -122,7 +123,6 @@ #define IDC_RADIO_TS_DISABLED 1006 #define IDC_RADIO_TS_LOCAL 1007 #define IDC_RADIO_TS_UTC 1008 -#define IDC_COMBO_LANG 1009 #define IDC_COMBO_MACHINE_TYPE 1010 #define IDC_COMBO_MACHINE 1011 /* machine/cpu config */ @@ -264,6 +264,11 @@ #define IDC_COMBO_DISK_SIZE 1201 #define IDC_COMBO_RPM_MODE 1202 +#define IDC_COMBO_LANG 1009 /* change language dialog */ +#define IDC_CHECKBOX_GLOBAL 1300 +#define IDC_BUTTON_SYSTEM 1301 +#define IDC_BUTTON_DEFAULT 1302 + /* For the DeviceConfig code, re-do later. */ #define IDC_CONFIG_BASE 1300 #define IDC_CONFIGURE_VID 1300 @@ -351,6 +356,8 @@ #define IDM_DISCORD 40090 #endif +#define IDM_VID_PROG_SETT 40091 + #if defined(DEV_BRANCH) && defined(USE_OPENGL) #define IDM_VID_GL_FPS_BLITTER 40100 #define IDM_VID_GL_FPS_25 40101 diff --git a/src/include/86box/win.h b/src/include/86box/win.h index da4d9fb05..33e55f1d4 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -184,6 +184,9 @@ extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); /* Functions in win_specify_dim.c: */ extern void SpecifyDimensionsDialogCreate(HWND hwnd); +/* Functions in win_lang.c: */ +extern void ProgSettDlgCreate(HWND hwnd); + /* Functions in win_settings.c: */ #define SETTINGS_PAGE_MACHINE 0 diff --git a/src/win/CMakeLists.txt b/src/win/CMakeLists.txt index e1b3fd942..727644f7b 100644 --- a/src/win/CMakeLists.txt +++ b/src/win/CMakeLists.txt @@ -20,7 +20,7 @@ add_library(plat OBJECT win.c win_dynld.c win_cdrom.c win_thread.c add_library(ui OBJECT win_ui.c win_stbar.c win_sdl.c win_dialog.c win_about.c win_settings.c win_devconf.c win_snd_gain.c win_specify_dim.c win_new_floppy.c - win_jsconf.c win_media_menu.c 86Box.rc) + win_jsconf.c win_media_menu.c win_lang.c 86Box.rc) if(MSVC) # MSVC complains when we include the manifest from 86Box.rc... diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 90ef6136a..ddafd98d0 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -444,7 +444,7 @@ else UIOBJ := win_ui.o win_stbar.o \ win_sdl.o \ win_dialog.o win_about.o \ - win_settings.o win_devconf.o win_snd_gain.o win_specify_dim.o \ + win_settings.o win_devconf.o win_snd_gain.o win_specify_dim.o win_lang.o \ win_new_floppy.o win_jsconf.o win_media_menu.o endif diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index e08aad513..4c7460213 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -18,14 +18,14 @@ BEGIN MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT MENUITEM SEPARATOR - MENUITEM "&Hard Reset", IDM_ACTION_HRESET + MENUITEM "&Hard Reset...", IDM_ACTION_HRESET MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD MENUITEM SEPARATOR MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC MENUITEM SEPARATOR MENUITEM "&Pause", IDM_ACTION_PAUSE MENUITEM SEPARATOR - MENUITEM "E&xit", IDM_ACTION_EXIT + MENUITEM "E&xit...", IDM_ACTION_EXIT END POPUP "&View" BEGIN @@ -47,7 +47,7 @@ BEGIN #endif END MENUITEM SEPARATOR - MENUITEM "Specify dimensions", IDM_VID_SPECIFY_DIM + MENUITEM "Specify dimensions...", IDM_VID_SPECIFY_DIM MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 POPUP "&Window scale factor" BEGIN @@ -62,6 +62,7 @@ BEGIN MENUITEM "&Linear", IDM_VID_FILTER_LINEAR END MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI + MENUITEM "Dis&play language...", IDM_VID_PROG_SETT MENUITEM SEPARATOR MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Fullscreen &stretch mode" @@ -268,6 +269,23 @@ END // // Dialog // + +DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 286, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Change Display Language" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK", IDOK, 166, 64, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 222, 64, 50, 14 + COMBOBOX IDC_COMBO_LANG, 10, 18, 266, 16, CBS_DROPDOWNLIST | CBS_HASSTRINGS +#if 0 + AUTOCHECKBOX "Use these settings as global &defaults", IDC_CHECKBOX_GLOBAL, 8, 67, 152, 8 +#endif + PUSHBUTTON "&System Language", IDC_BUTTON_SYSTEM, 120, 35, 82, 14 + PUSHBUTTON "&Default", IDC_BUTTON_DEFAULT, 206, 35, 60, 14 + LTEXT "Language:", 0, 9, 8, 34, 8 +END + DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Status" diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index bd9e7425a..4604fcb91 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -21,14 +21,14 @@ BEGIN MENUITEM "A &billentyűzet elfogást igényel", IDM_ACTION_KBD_REQ_CAPTURE MENUITEM "A &jobb oldali CTRL a bal ALT", IDM_ACTION_RCTRL_IS_LALT MENUITEM SEPARATOR - MENUITEM "Hardveres &újraindítás", IDM_ACTION_HRESET + MENUITEM "Hardveres &újraindítás...", IDM_ACTION_HRESET MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD MENUITEM SEPARATOR MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC MENUITEM SEPARATOR MENUITEM "&Szüneteltetés", IDM_ACTION_PAUSE MENUITEM SEPARATOR - MENUITEM "&Kilépés", IDM_ACTION_EXIT + MENUITEM "&Kilépés...", IDM_ACTION_EXIT END POPUP "&Nézet" BEGIN @@ -50,7 +50,7 @@ BEGIN #endif END MENUITEM SEPARATOR - MENUITEM "Méretek kézi megadása", IDM_VID_SPECIFY_DIM + MENUITEM "Méretek kézi megadása...", IDM_VID_SPECIFY_DIM MENUITEM "&Rögzített 4:3 képarány", IDM_VID_FORCE43 POPUP "&Ablak méretezési tényező" BEGIN @@ -65,6 +65,7 @@ BEGIN MENUITEM "&Lineáris", IDM_VID_FILTER_LINEAR END MENUITEM "Hi&DPI méretezés", IDM_VID_HIDPI + MENUITEM "&Nyelvi beállítások...", IDM_VID_PROG_SETT MENUITEM SEPARATOR MENUITEM "&Teljes képernyő\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Teljes képernyős &méretezés" @@ -271,6 +272,22 @@ END // // Dialog // +DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 286, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Nyelvi beállítások" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK", IDOK, 166, 64, 50, 14 + PUSHBUTTON "Mégse", IDCANCEL, 222, 64, 50, 14 + COMBOBOX IDC_COMBO_LANG, 10, 18, 266, 16, CBS_DROPDOWNLIST | CBS_HASSTRINGS +#if 0 + AUTOCHECKBOX "Ezen beállítások használata mint alapérték", IDC_CHECKBOX_GLOBAL, 8, 67, 152, 8 +#endif + PUSHBUTTON "A &rendszer nyelve", IDC_BUTTON_SYSTEM, 120, 35, 82, 14 + PUSHBUTTON "&Alapértelmezett", IDC_BUTTON_DEFAULT, 206, 35, 60, 14 + LTEXT "Nyelv:", 0, 9, 8, 34, 8 +END + DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Status" @@ -328,25 +345,23 @@ BEGIN WS_TABSTOP END -DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 +DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 203, 66 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Főablak méreteinek megadása" FONT 9, "Segoe UI" BEGIN - LTEXT "Szél.:",IDT_1709,7,9,24,12 - EDITTEXT IDC_EDIT_WIDTH,33,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Szélesség:",IDT_1709,7, 9, 34, 12 + EDITTEXT IDC_EDIT_WIDTH,44, 7, 45, 12,ES_AUTOHSCROLL | ES_NUMBER CONTROL "",IDC_WIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,76,6, - 12,12 - LTEXT "Mag.:",IDT_1710,97,9,24,12 - EDITTEXT IDC_EDIT_HEIGHT,123,7,45,12,ES_AUTOHSCROLL | ES_NUMBER + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS, 87, 6, 10, 12 + LTEXT "Magasság:",IDT_1710,103, 8, 35, 12 + EDITTEXT IDC_EDIT_HEIGHT, 140, 7, 45, 12 ,ES_AUTOHSCROLL | ES_NUMBER CONTROL "",IDC_HEIGHTSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,166,6, - 12,12 - CONTROL "Rögzítés erre a méretre",IDC_CHECK_LOCK_SIZE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,26,94,10 - DEFPUSHBUTTON "OK",IDOK,30,45,50,14 - PUSHBUTTON "Mégse",IDCANCEL,99,45,50,14 + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,183, 6, 10, 12 + CONTROL "Rögzítés a megadott méretre",IDC_CHECK_LOCK_SIZE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7, 26, 123, 10 + DEFPUSHBUTTON "OK",IDOK,42, 45, 50, 14 + PUSHBUTTON "Mégse",IDCANCEL,112, 45, 50, 14 END DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 200 @@ -371,20 +386,20 @@ BEGIN LTEXT "FPU-egység:",IDT_1707,7,66,59,10 COMBOBOX IDC_COMBO_WS,71,83,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Várakozási cikl.:",IDT_1703,7,85,60,10 + LTEXT "Várak. ciklusok:",IDT_1703,7,85,60,10 EDITTEXT IDC_MEMTEXT,70,102,45,12,ES_AUTOHSCROLL | ES_NUMBER CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, 12,12 LTEXT "MB",IDT_1705,123,104,10,10 LTEXT "Memória:",IDT_1706,7,104,30,10 - GROUPBOX "Idő szinkronizáció",IDC_TIME_SYNC,7,135,100,56 + GROUPBOX "Idő szinkronizáció",IDC_TIME_SYNC,7,135,114,56 CONTROL "Letiltva",IDC_RADIO_TS_DISABLED,"Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,147,84,10 - CONTROL "Engedély. (helyi idő)", IDC_RADIO_TS_LOCAL,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,84,10 - CONTROL "Engedély. (UTC)", IDC_RADIO_TS_UTC,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,84,10 + CONTROL "Engedélyezve (helyi idő)", IDC_RADIO_TS_LOCAL,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,102,10 + CONTROL "Engedélyezve (UTC)", IDC_RADIO_TS_UTC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,102,10 #ifdef USE_DYNAREC CONTROL "Dinamikus újrafordítás",IDC_CHECK_DYNAREC,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 @@ -594,9 +609,9 @@ BEGIN EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Szektorok:",IDT_1726,154,35,27,10 - LTEXT "Fejek:",IDT_1727,81,35,29,8 - LTEXT "Cilinderek:",IDT_1728,7,35,32,12 + LTEXT "Szektor:",IDT_1726,154,35,27,10 + LTEXT "Fej:",IDT_1727,81,35,29,8 + LTEXT "Cilinder:",IDT_1728,7,35,32,12 LTEXT "Méret (MB):",IDT_1729,7,54,33,8 LTEXT "Típus:",IDT_1730,86,54,24,8 LTEXT "Fájlnév:",IDT_1731,7,7,204,9 @@ -682,7 +697,7 @@ BEGIN LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,137,253,60 LTEXT "ZIP-meghajtók:",IDT_1759,7,127,253,8 - COMBOBOX IDC_COMBO_ZIP_BUS,33,205,90,12,CBS_DROPDOWNLIST | + COMBOBOX IDC_COMBO_ZIP_BUS,33, 205, 84, 14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Busz:",IDT_1753,7,207,24,8 COMBOBOX IDC_COMBO_ZIP_ID,170,205,90,12,CBS_DROPDOWNLIST | diff --git a/src/win/win_lang.c b/src/win/win_lang.c new file mode 100644 index 000000000..8c69048ab --- /dev/null +++ b/src/win/win_lang.c @@ -0,0 +1,142 @@ +/* + * 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. + * + * Handle the dialog for specifying the dimensions of the main window. + * + * + * + * Authors: Laci bá' + * + * Copyright 2021 Laci bá' + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/plat.h> +#include <86box/sound.h> +#include <86box/win.h> + +/* Language */ +static LCID temp_language; + +int enum_helper, c; + +BOOL CALLBACK +EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) +{ + wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; + LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); + wchar_t dispname[MAX_PATH + 1]; + GetLocaleInfoEx(temp, LOCALE_SENGLISHDISPLAYNAME, dispname, MAX_PATH); + SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)dispname); + SendMessage((HWND)lParam, CB_SETITEMDATA, c, (LPARAM)wIDLanguage); + + pclog("widl: %u, langid: %u, c: %u\n", wIDLanguage, lang_id, c); + if (wIDLanguage == lang_id) + enum_helper = c; + c++; + + return 1; +} + +/* Load available languages */ +static void +progsett_fill_languages(HWND hdlg) +{ + temp_language = GetThreadUILanguage(); + HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + + SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); + + enum_helper = -1; c = 0; + EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); + pclog("enum_helper is %d\n", enum_helper); + + SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); + pclog("win_fill_languages\n"); +} + +/* This returns 1 if any variable has changed, 0 if not. */ +static int +progsett_settings_changed(void) +{ + int i = 0; + + /* Language */ + i = i || has_language_changed(temp_language); + + return i; +} + +/* This saves the settings back to the global variables. */ +static void +progsett_settings_save(void) +{ + /* Language */ + set_language(temp_language); +} + +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INITDIALOG: + /* Language */ + temp_language = lang_id; + pclog("temp_language is %u\n", lang_id); + progsett_fill_languages(hdlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (progsett_settings_changed()) + progsett_settings_save(); + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + + case IDC_COMBO_LANG: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + int index = SendMessage(combo, CB_GETCURSEL, 0, 0); + temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); + pclog("combobox changed -> temp_language = %u", temp_language); + } + default: + break; + } + break; + } + + return(FALSE); +} + + +void +ProgSettDlgCreate(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_PROG_SETT, hwnd, ProgSettDlgProcedure); +} diff --git a/src/win/win_ui.c b/src/win/win_ui.c index a099489aa..57ef417a2 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -810,6 +810,10 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) doresize = 1; config_save(); break; + + case IDM_VID_PROG_SETT: + ProgSettDlgCreate(hwnd); + break; case IDM_VID_SPECIFY_DIM: SpecifyDimensionsDialogCreate(hwnd); From 0bab2e144ac17d08117a5ded552ac3e49e0c840f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Fri, 12 Nov 2021 22:41:30 +0100 Subject: [PATCH 120/140] Reinit media menu, and store the system language too --- src/include/86box/86box.h | 2 ++ src/win/win.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index a49fb198f..abfaf5d21 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -65,6 +65,8 @@ extern "C" { #endif /* Global variables. */ +extern uint32_t lang_sys; /* (-) system language code */ + extern int dump_on_exit; /* (O) dump regs on exit*/ extern int do_dump_config; /* (O) dump cfg after load */ extern int start_in_fullscreen; /* (O) start in fullscreen */ diff --git a/src/win/win.c b/src/win/win.c index 1aa25a8c9..88f48b958 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -67,7 +67,7 @@ typedef struct { /* Platform Public data, specific. */ HINSTANCE hinstance; /* application instance */ HANDLE ghMutex; -uint32_t lang_id; /* current language ID used */ +uint32_t lang_id, lang_sys; /* current and system language ID */ DWORD dwSubLangID; int acp_utf8; /* Windows supports UTF-8 codepage */ volatile int cpu_thread_run = 1; @@ -260,10 +260,14 @@ set_language(uint32_t id) lang_id = id; SetThreadUILanguage(lang_id); - SetMenu(hwndMain, LoadMenu(hinstance, L"MainMenu")); - /* Load the strings table for this ID. */ LoadCommonStrings(); + + /* Reload main menu */ + SetMenu(hwndMain, LoadMenu(hinstance, L"MainMenu")); + + /* Re-init media menu */ + media_menu_init(); } } @@ -466,7 +470,8 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) sprintf(emu_version, "%s v%s", EMU_NAME, EMU_VERSION); /* First, set our (default) language. */ - set_language(GetThreadUILanguage()); + lang_sys = GetThreadUILanguage(); + set_language(lang_sys); /* Process the command line for options. */ argc = ProcessCommandLine(&argv); From 80c01b9bfed353182e4177f6f1854177181d2b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Fri, 12 Nov 2021 22:43:18 +0100 Subject: [PATCH 121/140] Settings dialog cleanup --- src/win/languages/en-US.rc | 3 --- src/win/languages/hu-HU.rc | 3 --- src/win/win_settings.c | 55 -------------------------------------- 3 files changed, 61 deletions(-) diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index 4c7460213..cf5956691 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -338,9 +338,6 @@ BEGIN CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 - LTEXT "Language:",IDT_1700,7,237,41,10 - COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP END DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 4604fcb91..84f4b4ecf 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -340,9 +340,6 @@ BEGIN CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 - LTEXT "Nyelv:",IDT_1700,7,237,41,10 - COMBOBOX IDC_COMBO_LANG,48,236,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP END DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 203, 66 diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 1a1aa12a1..3f3b4511d 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -78,9 +78,6 @@ static int first_cat = 0; static int dpi = 96; -/* Language */ -static LCID temp_language; - /* Machine category */ static int temp_machine_type, temp_machine, temp_cpu, temp_wait_states, temp_fpu, temp_sync; static cpu_family_t *temp_cpu_f; @@ -319,40 +316,6 @@ settings_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn return(i); } -int enum_helper, c; - -BOOL CALLBACK -EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) -{ - wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; - LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); - SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)temp); - SendMessage((HWND)lParam, CB_SETITEMDATA, c, (LPARAM)wIDLanguage); - - pclog("widl: %u, langid: %u, c: %u\n", wIDLanguage, lang_id, c); - if (wIDLanguage == lang_id) - enum_helper = c; - c++; - - return 1; -} - -/* Load available languages */ -static void -win_fill_languages(HWND hdlg) -{ - temp_language = GetThreadUILanguage(); - HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); - - SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); - - enum_helper = -1; c = 0; - EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); - pclog("enum_helper is %d\n", enum_helper); - - SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); - pclog("win_fill_languages\n"); -} /* This does the initial read of global variables into the temporary ones. */ static void @@ -360,11 +323,6 @@ win_settings_init(void) { int i = 0; - /* Language */ - temp_language = lang_id; - pclog("temp_language is %u\n", lang_id); - win_fill_languages(hwndParentDialog); - /* Machine category */ temp_machine_type = machines[machine].type; temp_machine = machine; @@ -490,9 +448,6 @@ win_settings_changed(void) { int i = 0, j = 0; - /* Language */ - i = i || has_language_changed(temp_language); - /* Machine category */ i = i || (machine != temp_machine); i = i || (cpu_f != temp_cpu_f); @@ -583,9 +538,6 @@ win_settings_save(void) pc_reset_hard_close(); - /* Language */ - set_language(temp_language); - /* Machine category */ machine = temp_machine; cpu_f = temp_cpu_f; @@ -5238,13 +5190,6 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) EndDialog(hdlg, 0); win_notify_dlg_closed(); return TRUE; - case IDC_COMBO_LANG: - if (HIWORD(wParam) == CBN_SELCHANGE) { - HWND combo = GetDlgItem(hwndParentDialog, IDC_COMBO_LANG); - int index = SendMessage(combo, CB_GETCURSEL, 0, 0); - temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); - pclog("combobox changed -> temp_language = %u", temp_language); - } } break; From 6119e3a0192df90c6fa720758537ba5e9fe4a3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 20:05:48 +0100 Subject: [PATCH 122/140] Adjustments in config to write explicitly the mem_size This will help manager developers to decide the VM's memory size without knowing the actual machine table. --- src/config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/config.c b/src/config.c index 7323b6a81..0bd8dbfe3 100644 --- a/src/config.c +++ b/src/config.c @@ -2327,9 +2327,8 @@ save_machine(void) else config_set_string(cat, "fpu_type", (char *) fpu_get_internal_name(cpu_f, cpu, fpu_type)); - if (mem_size == 4096) + //Write the mem_size explicitly to the setttings in order to help managers to display it without having the actual machine table config_delete_var(cat, "mem_size"); - else config_set_int(cat, "mem_size", mem_size); config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); From 2d30052238154a15470d03da65d126e93f7d6bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 21:35:43 +0100 Subject: [PATCH 123/140] Remove ifdef, add default language constant, and separate text filler code from pc_init --- src/86box.c | 17 +++++++++++------ src/include/86box/86box.h | 4 ++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/86box.c b/src/86box.c index c67d01ff8..16c4ab4ce 100644 --- a/src/86box.c +++ b/src/86box.c @@ -434,8 +434,8 @@ usage: printf("-E or --nographic - forces the old behavior\n"); #endif printf("-F or --fullscreen - start in fullscreen mode\n"); -#ifdef _WIN32 printf("-G or --lang langid - start the application with the specified language\n"); +#ifdef _WIN32 printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); #endif printf("-L or --logfile path - set 'path' to be the logfile\n"); @@ -519,7 +519,8 @@ usage: !strcasecmp(argv[c], "-G")) { - //This function is currently unimplemented for *nix. +#endif + //This function is currently unimplemented for *nix but has placeholders. lang_init = plat_language_code(argv[++c]); if (!lang_init) @@ -528,7 +529,6 @@ usage: //The return value of 0 only means that the code is invalid, // not related to that translation is exists or not for the // selected language. -#endif } else if (!strcasecmp(argv[c], "--test")) { /* some (undocumented) test function here.. */ @@ -922,8 +922,6 @@ pc_reset_hard_close(void) void pc_reset_hard_init(void) { - wchar_t wcpufamily[2048], wcpu[2048], wmachine[2048], *wcp; - /* * First, we reset the modules that are not part of * the actual machine, but which support some of the @@ -1025,7 +1023,14 @@ pc_reset_hard_init(void) pc_full_speed(); cycles = cycles_main = 0; + + update_mouse_msg(); +} +void update_mouse_msg() +{ + wchar_t wcpufamily[2048], wcpu[2048], wmachine[2048], *wcp; + mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); if (!cpu_override) @@ -1037,6 +1042,7 @@ pc_reset_hard_init(void) if (wcp) /* remove parentheses */ *(wcp - 1) = L'\0'; mbstowcs(wcpu, cpu_s->name, strlen(cpu_s->name)+1); + swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls", EMU_NAME_W, EMU_VERSION_W, wmachine, wcpufamily, wcpu, plat_get_string(IDS_2077)); @@ -1045,7 +1051,6 @@ pc_reset_hard_init(void) (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); } - void pc_reset_hard(void) { diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index abfaf5d21..c27f1d93e 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -33,6 +33,9 @@ #define SCREENSHOT_PATH "screenshots" +/* Default language 0xFFFF = from system, 0x409 = en-US */ +#define DEFAULT_LANGUAGE 0x0409 + #if defined(ENABLE_BUSLOGIC_LOG) || \ defined(ENABLE_CDROM_LOG) || \ defined(ENABLE_D86F_LOG) || \ @@ -173,6 +176,7 @@ extern void fatal(const char *fmt, ...); extern void set_screen_size(int x, int y); extern void reset_screen_size(void); extern void set_screen_size_natural(void); +extern void update_mouse_msg(); #if 0 extern void pc_reload(wchar_t *fn); #endif From dddff5a89289d319caa3145bb91f36f5fb5f995c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 21:36:20 +0100 Subject: [PATCH 124/140] Adjustments in Hungarian translation --- src/win/languages/hu-HU.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 84f4b4ecf..0f7a06259 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -752,7 +752,7 @@ BEGIN IDS_2049 "Hiba" IDS_2050 "Végzetes hiba" IDS_2051 "" - IDS_2052 "Használja a CTRL+ALT+PAGE DOWN kombinációt az ablakhoz való visszatéréshez." + IDS_2052 "Használja a CTRL+ALT+PAGE DOWN gombokat az ablakhoz való visszatéréshez." IDS_2053 "Sebesség" IDS_2054 "ZIP %03i %i (%s): %ls" IDS_2055 "ZIP-lemezképek (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" @@ -781,7 +781,7 @@ BEGIN IDS_2074 "Egyéb cserélhető tárolók" IDS_2075 "Egyéb perifériák" IDS_2076 "Felületi képfájlok (*.86F)\0*.86F\0" - IDS_2077 "Az egér elfogásához kattintson az ablakba" + IDS_2077 "Kattintson az egér elfogásához" IDS_2078 "Nyomja meg az F8+F12-t az egér elengédéséhez" IDS_2079 "Nyomja meg az F8+F12-t vagy a középső gombot az egér elengédéséhez" END From 87cbbdf992f7e65da20254d77447fa8e66c29cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 21:37:27 +0100 Subject: [PATCH 125/140] Implement language local config saving --- src/config.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/config.c b/src/config.c index 7323b6a81..499624f50 100644 --- a/src/config.c +++ b/src/config.c @@ -567,15 +567,8 @@ load_general(void) confirm_exit = config_get_int(cat, "confirm_exit", 1); confirm_save = config_get_int(cat, "confirm_save", 1); -#ifdef USE_LANGUAGE - /* - * Currently, 86Box is English (US) only, but in the future - * (version 3.0 at the earliest) other languages will be - * added, therefore it is better to future-proof the code. - */ - plat_langid = config_get_hex16(cat, "language", 0x0409); -#endif - + lang_id = config_get_hex16(cat, "language", DEFAULT_LANGUAGE); + #if USE_DISCORD enable_discord = !!config_get_int(cat, "enable_discord", 0); #endif @@ -2211,12 +2204,10 @@ save_general(void) else config_delete_var(cat, "confirm_save"); -#ifdef USE_LANGUAGE - if (plat_langid == 0x0409) + if (lang_id == DEFAULT_LANGUAGE) config_delete_var(cat, "language"); else - config_set_hex16(cat, "language", plat_langid); -#endif + config_set_hex16(cat, "language", lang_id); #if USE_DISCORD if (enable_discord) @@ -2941,7 +2932,9 @@ save_other_removable_devices(void) void config_save(void) -{ +{ + pclog("config_save"); + save_general(); /* General */ save_machine(); /* Machine */ save_video(); /* Video */ From 7e4abcbfbd364e2da7321b3b8fcc8cb6b04aee84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 21:37:51 +0100 Subject: [PATCH 126/140] Implement system language as 0xFFFF --- src/win/win.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/win/win.c b/src/win/win.c index 88f48b958..4c8e7ac27 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -255,6 +255,13 @@ void set_language(uint32_t id) { pclog("set_language %u, lang_id %u\n", id, lang_id); + if (id == 0xFFFF) + { + set_language(lang_sys); + lang_id = id; + return; + } + if (lang_id != id) { /* Set our new language ID. */ lang_id = id; @@ -471,7 +478,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) /* First, set our (default) language. */ lang_sys = GetThreadUILanguage(); - set_language(lang_sys); + set_language(DEFAULT_LANGUAGE); /* Process the command line for options. */ argc = ProcessCommandLine(&argv); @@ -1201,6 +1208,9 @@ plat_vid_reload_options(void) uint32_t plat_language_code(char* langcode) { + if (!strcmp(langcode, "system")) + return 0xFFFF; + int len = mbstoc16s(NULL, langcode, 0) + 1; wchar_t *temp = malloc(len * sizeof(wchar_t)); mbstoc16s(temp, langcode, len); From 3fa1e88d7d79549191b49aa8d8510cf333464f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 21:39:07 +0100 Subject: [PATCH 127/140] Initial addition of system language to the dialog Also update everything and save the config without hard reset. --- src/win/win_lang.c | 56 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/win/win_lang.c b/src/win/win_lang.c index 8c69048ab..cc7882840 100644 --- a/src/win/win_lang.c +++ b/src/win/win_lang.c @@ -30,12 +30,16 @@ #include <86box/plat.h> #include <86box/sound.h> #include <86box/win.h> +#include <86box/ui.h> +#include <86box/resource.h> /* Language */ static LCID temp_language; int enum_helper, c; +HWND hwndProgSett; + BOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) { @@ -62,8 +66,12 @@ progsett_fill_languages(HWND hdlg) HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); + SendMessage(lang_combo, CB_ADDSTRING, 0, (LPARAM)L"(System Default)"); + SendMessage(lang_combo, CB_SETITEMDATA, 0, 0xFFFF); - enum_helper = -1; c = 0; + enum_helper = 0; c = 1; + //if no one is selected, then it was 0xFFFF or unsupported language, in either case go with index enum_helper=0 + //also start enum index from c=1 EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); pclog("enum_helper is %d\n", enum_helper); @@ -83,12 +91,37 @@ progsett_settings_changed(void) return i; } +/* IndexOf by ItemData */ +static int +progsett_indexof(HWND combo, LPARAM itemdata) +{ + int i; + for (i = 0; i < SendMessage(combo, CB_GETCOUNT, 0, 0); i++) + if (SendMessage(combo, CB_GETITEMDATA, i, 0) == itemdata) + return i; + + return -1; +} + /* This saves the settings back to the global variables. */ static void progsett_settings_save(void) -{ +{ /* Language */ set_language(temp_language); + + pclog("done"); + + /* Update title bar */ + update_mouse_msg(); + + /* Update status bar */ + config_changed = 1; + ui_sb_set_ready(0); + ui_sb_update_panes(); + + /* Save the language changes */ + config_save(); } #if defined(__amd64__) || defined(__aarch64__) @@ -100,6 +133,7 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: + hwndProgSett = hdlg; /* Language */ temp_language = lang_id; pclog("temp_language is %u\n", lang_id); @@ -107,10 +141,10 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - if (progsett_settings_changed()) - progsett_settings_save(); + switch (LOWORD(wParam)) { + case IDOK: + if (progsett_settings_changed()) + progsett_settings_save(); EndDialog(hdlg, 0); return TRUE; @@ -125,6 +159,16 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); pclog("combobox changed -> temp_language = %u", temp_language); } + break; + + case IDC_BUTTON_DEFAULT: { + HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + int index = progsett_indexof(combo, DEFAULT_LANGUAGE); + SendMessage(combo, CB_SETCURSEL, index, 0); + temp_language = DEFAULT_LANGUAGE; + pclog("combobox changed -> temp_language = %u", temp_language); + break; + } default: break; } From 7ae10144adac28ff3c1561a95c899be69adfc13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 22:36:13 +0100 Subject: [PATCH 128/140] Cumulative changes Move to translateable (System Default) message Move change language to Tools menu Redesign the language dialog Add the translators' name to the About dialog, to make the translation process more attractive --- src/include/86box/language.h | 2 +- src/include/86box/resource.h | 1 - src/win/languages/en-US.rc | 37 +++++++++++++++++++++++------------- src/win/languages/hu-HU.rc | 37 +++++++++++++++++++++++------------- src/win/win_lang.c | 2 +- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 7e096fbf4..a1f3ce3aa 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -229,7 +229,7 @@ #define IDS_6146 6146 // "1.5%% below perfect RPM" #define IDS_6147 6147 // "2%% below perfect RPM" -#define IDS_7168 7168 // "English (United States)" +#define IDS_7168 7168 // "(System Default)" #define IDS_LANG_ENUS IDS_7168 diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index 306a9c839..2a13b01f1 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -266,7 +266,6 @@ #define IDC_COMBO_LANG 1009 /* change language dialog */ #define IDC_CHECKBOX_GLOBAL 1300 -#define IDC_BUTTON_SYSTEM 1301 #define IDC_BUTTON_DEFAULT 1302 /* For the DeviceConfig code, re-do later. */ diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index cf5956691..a171fe941 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -62,7 +62,6 @@ BEGIN MENUITEM "&Linear", IDM_VID_FILTER_LINEAR END MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI - MENUITEM "Dis&play language...", IDM_VID_PROG_SETT MENUITEM SEPARATOR MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Fullscreen &stretch mode" @@ -99,6 +98,8 @@ BEGIN BEGIN MENUITEM "&Settings...", IDM_CONFIG MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Change dis&play language...", IDM_VID_PROG_SETT # ifdef USE_DISCORD MENUITEM SEPARATOR MENUITEM "Enable &Discord integration", IDM_DISCORD @@ -270,20 +271,17 @@ END // Dialog // -DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 286, 86 +DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 240, 86 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Change Display Language" FONT 9, "Segoe UI" BEGIN - DEFPUSHBUTTON "OK", IDOK, 166, 64, 50, 14 - PUSHBUTTON "Cancel", IDCANCEL, 222, 64, 50, 14 - COMBOBOX IDC_COMBO_LANG, 10, 18, 266, 16, CBS_DROPDOWNLIST | CBS_HASSTRINGS -#if 0 - AUTOCHECKBOX "Use these settings as global &defaults", IDC_CHECKBOX_GLOBAL, 8, 67, 152, 8 -#endif - PUSHBUTTON "&System Language", IDC_BUTTON_SYSTEM, 120, 35, 82, 14 - PUSHBUTTON "&Default", IDC_BUTTON_DEFAULT, 206, 35, 60, 14 - LTEXT "Language:", 0, 9, 8, 34, 8 + DEFPUSHBUTTON "OK", IDOK, 123, 65, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 179, 65, 50, 14 + COMBOBOX IDC_COMBO_LANG, 13, 18, 213, 22, CBS_DROPDOWNLIST | CBS_HASSTRINGS + AUTOCHECKBOX "Save these settings as &global defaults", IDC_CHECKBOX_GLOBAL, 13, 50, 217, 8 , WS_DISABLED + PUSHBUTTON "&Default", IDC_BUTTON_DEFAULT, 162, 32, 60, 14 + LTEXT "Language:", 0, 13, 8, 34, 8 END DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 @@ -834,7 +832,20 @@ BEGIN IDS_2123 "Save" IDS_2124 "About 86Box" IDS_2125 "86Box v" EMU_VERSION - IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." + + IDS_2126 "An emulator of old computers\n\n" + + "Authors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\n" + + /* + Translate the following line as "Translated by: \n\n". + If there were previous translators, don't erase their name, just add yours to the end of line. + */ + + "This is the program's base language.\n\n" + + "Released under the GNU General Public License version 2 or later. See LICENSE for more information." + IDS_2127 "OK" IDS_2128 "Hardware not available" #ifdef _WIN32 @@ -979,7 +990,7 @@ BEGIN IDS_6146 "1.5%% below perfect RPM" IDS_6147 "2%% below perfect RPM" - IDS_7168 "English (United States)" + IDS_7168 "(System Default)" END #define IDS_LANG_ENUS IDS_7168 diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc index 0f7a06259..4abbdb43d 100644 --- a/src/win/languages/hu-HU.rc +++ b/src/win/languages/hu-HU.rc @@ -4,6 +4,8 @@ // Translated by Laci bá', 2021 // +#define TRANSLATORS_NAME "Laci bá'" + #ifdef _WIN32 LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT #pragma code_page(65001) @@ -65,7 +67,6 @@ BEGIN MENUITEM "&Lineáris", IDM_VID_FILTER_LINEAR END MENUITEM "Hi&DPI méretezés", IDM_VID_HIDPI - MENUITEM "&Nyelvi beállítások...", IDM_VID_PROG_SETT MENUITEM SEPARATOR MENUITEM "&Teljes képernyő\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Teljes képernyős &méretezés" @@ -102,6 +103,8 @@ BEGIN BEGIN MENUITEM "&Beállítások...", IDM_CONFIG MENUITEM "Állapotsori ikonok &frissítése", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "A &program nyelvének módosítása...", IDM_VID_PROG_SETT # ifdef USE_DISCORD MENUITEM SEPARATOR MENUITEM "&Discord integráció engedélyezése", IDM_DISCORD @@ -272,20 +275,17 @@ END // // Dialog // -DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 286, 86 +DLG_PROG_SETT DIALOG DISCARDABLE 0, 0, 240, 86 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Nyelvi beállítások" FONT 9, "Segoe UI" BEGIN - DEFPUSHBUTTON "OK", IDOK, 166, 64, 50, 14 - PUSHBUTTON "Mégse", IDCANCEL, 222, 64, 50, 14 - COMBOBOX IDC_COMBO_LANG, 10, 18, 266, 16, CBS_DROPDOWNLIST | CBS_HASSTRINGS -#if 0 - AUTOCHECKBOX "Ezen beállítások használata mint alapérték", IDC_CHECKBOX_GLOBAL, 8, 67, 152, 8 -#endif - PUSHBUTTON "A &rendszer nyelve", IDC_BUTTON_SYSTEM, 120, 35, 82, 14 - PUSHBUTTON "&Alapértelmezett", IDC_BUTTON_DEFAULT, 206, 35, 60, 14 - LTEXT "Nyelv:", 0, 9, 8, 34, 8 + DEFPUSHBUTTON "OK", IDOK, 123, 65, 50, 14 + PUSHBUTTON "Mégse", IDCANCEL, 179, 65, 50, 14 + COMBOBOX IDC_COMBO_LANG, 13, 18, 213, 22, CBS_DROPDOWNLIST | CBS_HASSTRINGS + AUTOCHECKBOX "Beállítások mentése &globális alapértékként", IDC_CHECKBOX_GLOBAL, 13, 50, 217, 8, WS_DISABLED + PUSHBUTTON "&Alapértelmezett", IDC_BUTTON_DEFAULT, 162, 32, 60, 14 + LTEXT "Nyelv:", 0, 13, 8, 34, 8 END DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 @@ -834,7 +834,18 @@ BEGIN IDS_2123 "Mentés" IDS_2124 "A 86Box névjegye" IDS_2125 "86Box v" EMU_VERSION - IDS_2126 "Régi számítógépek emulátora\n\nFejlesztők: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, és mások.\n\nMegjelent a GNU General Public License v2 alatt. További információért lásd a LICENSE fájlt. " + IDS_2126 "Régi számítógépek emulátora\n\n" + + "Fejlesztők: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\n" + + /* + Translate the following line as "Translated by: \n\n". + If there were previous translators, don't erase their name, just add yours to the end of line. + */ + + "Fordította: Laci bá'\n\n" + + "Megjelent a GNU General Public License v2 vagy újabb alatt. További információért lásd a LICENSE fájlt." IDS_2127 "OK" IDS_2128 "Hardver nem elérhető" #ifdef _WIN32 @@ -979,7 +990,7 @@ BEGIN IDS_6146 "1.5%%-kal a tökéletes RPM alatt" IDS_6147 "2%%-kal a tökéletes RPM alatt" - IDS_7168 "magyar (Magyarország)" + IDS_7168 "(A rendszer nyelve)" END #define IDS_LANG_ENUS IDS_7168 diff --git a/src/win/win_lang.c b/src/win/win_lang.c index cc7882840..805856b6d 100644 --- a/src/win/win_lang.c +++ b/src/win/win_lang.c @@ -66,7 +66,7 @@ progsett_fill_languages(HWND hdlg) HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); - SendMessage(lang_combo, CB_ADDSTRING, 0, (LPARAM)L"(System Default)"); + SendMessage(lang_combo, CB_ADDSTRING, 0, win_get_string(IDS_7168)); SendMessage(lang_combo, CB_SETITEMDATA, 0, 0xFFFF); enum_helper = 0; c = 1; From c705803c1d7373e54a11fa6beaf9e41b836b2119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 22:54:31 +0100 Subject: [PATCH 129/140] Remove translators text from en-US about --- src/win/languages/en-US.rc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc index a171fe941..f21f91de5 100644 --- a/src/win/languages/en-US.rc +++ b/src/win/languages/en-US.rc @@ -838,11 +838,11 @@ BEGIN "Authors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\n" /* - Translate the following line as "Translated by: \n\n". - If there were previous translators, don't erase their name, just add yours to the end of line. + Here uncomment following line and add your name like "Translated by: \n\n". + If such a line exists with name of previous translators, don't erase their name, just add yours to the end of line. */ - - "This is the program's base language.\n\n" + + //"Translated by: \n\n" "Released under the GNU General Public License version 2 or later. See LICENSE for more information." From 758d8acb63bf5bf9d41c66fc00ee4ec35dfa358e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 13 Nov 2021 22:57:01 +0100 Subject: [PATCH 130/140] Temporarily reverted all keyboard changes. --- src/device/kbc_at.c | 2324 ------------------------------- src/device/kbd_at.c | 1162 ---------------- src/device/keyboard_at.c | 2834 ++++++++++++++------------------------ src/device/mouse_ps2.c | 55 +- 4 files changed, 1074 insertions(+), 5301 deletions(-) delete mode 100644 src/device/kbc_at.c delete mode 100644 src/device/kbd_at.c diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c deleted file mode 100644 index bb756f67d..000000000 --- a/src/device/kbc_at.c +++ /dev/null @@ -1,2324 +0,0 @@ -/* - * 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. - * - * Intel 8042 (AT keyboard controller) emulation. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * EngiNerd - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. - * Copyright 2020 EngiNerd. - */ -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include -#include <86box/86box.h> -#include "cpu.h" -#include <86box/timer.h> -#include <86box/io.h> -#include <86box/pic.h> -#include <86box/pit.h> -#include <86box/ppi.h> -#include <86box/mem.h> -#include <86box/device.h> -#include <86box/machine.h> -#include <86box/m_xt_xi8088.h> -#include <86box/m_at_t3100e.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/sound.h> -#include <86box/snd_speaker.h> -#include <86box/video.h> -#include <86box/keyboard.h> - - -#define STAT_PARITY 0x80 -#define STAT_RTIMEOUT 0x40 -#define STAT_TTIMEOUT 0x20 -#define STAT_MFULL 0x20 -#define STAT_UNLOCKED 0x10 -#define STAT_CD 0x08 -#define STAT_SYSFLAG 0x04 -#define STAT_IFULL 0x02 -#define STAT_OFULL 0x01 - -#define RESET_DELAY_TIME 1000 /* 100 ms */ - -#define CCB_UNUSED 0x80 -#define CCB_TRANSLATE 0x40 -#define CCB_PCMODE 0x20 -#define CCB_ENABLEKBD 0x10 -#define CCB_IGNORELOCK 0x08 -#define CCB_SYSTEM 0x04 -#define CCB_ENABLEMINT 0x02 -#define CCB_ENABLEKINT 0x01 - -#define CCB_MASK 0x68 -#define MODE_MASK 0x6c - -#define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ -/* This only differs in that translation is forced off. */ -#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x07 - -#define KBC_FLAG_PS2 0x04 - -/* We need to redefine this: - Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 - for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling - controller mode, normally set according to the flags, but togglable on - AMIKey: - 0000 0000 0x00 IBM, AT - 0000 0001 0x01 MR - 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 - 0001 0000 0x10 Olivetti - 0010 0000 0x20 Toshiba - 0011 0000 0x30 Quadtel - 0100 0000 0x40 Phoenix MultiKey/42 - 0101 0000 0x50 AMI KF - 0101 0001 0x51 AMI KH - 0101 0010 0x52 AMIKey - 0101 0011 0x53 AMIKey-2 - 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) - 0110 0000 0x60 Award - 0110 0001 0x61 Award 286 (has some AMI commands apparently) - 0111 0000 0x70 Siemens -*/ - -/* Standard IBM controller */ -#define KBC_VEN_GENERIC 0x00 -/* All commands are standard PS/2 */ -#define KBC_VEN_IBM_MCA 0x08 -/* Standard IBM commands, differs in input port bits */ -#define KBC_VEN_IBM_PS1 0x10 -/* Olivetti - proprietary commands and port 62h with switches - readout */ -#define KBC_VEN_OLIVETTI 0x20 -/* Toshiba T3100e - has a bunch of proprietary commands, also sets - IFULL on command AA */ -#define KBC_VEN_TOSHIBA 0x28 -/* Standard IBM commands, uses input port as a switches readout */ -#define KBC_VEN_NCR 0x30 -/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the - polarity of the video type bit in the input port is inverted */ -#define KBC_VEN_XI8088 0x38 -/* QuadtelKey - currently guesswork */ -#define KBC_VEN_QUADTEL 0x40 -/* Phoenix MultiKey/42 - not yet implemented */ -#define KBC_VEN_PHOENIX 0x48 -/* Generic commands, XI8088-like input port handling of video type, - maybe we just need a flag for that? */ -#define KBC_VEN_ACER 0x50 -/* AMI KF/KH/AMIKey/AMIKey-2 */ -#define KBC_VEN_AMI 0xf0 -/* Standard AMI commands, differs in input port bits */ -#define KBC_VEN_INTEL_AMI 0xf8 -#define KBC_VEN_MASK 0xf8 - - -/* Flags should be fully 32-bit: - Bits 7- 0: Vendor and revision/variant; - Bits 15- 8: Input port mask; - Bits 23-16: Input port bits that are always on; - Bits 31-24: Flags: - Bit 0: Invert P1 video type bit polarity; - Bit 1: Is PS/2; - Bit 2: Translation forced always off. - - So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ - - -typedef struct { - uint8_t *c_in, *c_data, /* Data to controller */ - *d_in, *d_data, /* Data to device */ - *inhibit; - - void (*process)(void *priv); - void *priv; -} kbc_dev_t; - -typedef struct { - uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, - secr_phase, mem_index, ami_stat, ami_mode, - kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, - kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit; - - uint8_t mem_int[0x40], mem[0x240]; - - uint16_t last_irq, kbc_phase; - - uint32_t flags; - - kbc_dev_t * kbc_devs[2]; - - pc_timer_t pulse_cb, send_delay_timer; - - uint8_t (*write60_ven)(void *p, uint8_t val); - uint8_t (*write64_ven)(void *p, uint8_t val); - - void * log; -} atkbc_t; - - -enum -{ - CHANNEL_KBC = 0, - CHANNEL_KBD, - CHANNEL_MOUSE -}; - -enum -{ - KBD_MAIN_LOOP = 0, - KBD_CMD_PROCESS -}; - -enum -{ - MOUSE_MAIN_LOOP_1 = 0, - MOUSE_CMD_PROCESS, - MOUSE_CMD_END, - MOUSE_MAIN_LOOP_2 -}; - -enum { - KBC_MAIN_LOOP = 0, - KBC_RESET = 1, - KBC_WAIT = 4, - KBC_WAIT_FOR_KBD, - KBC_WAIT_FOR_MOUSE, - KBC_WAIT_FOR_BOTH -}; - - -static void kbc_wait(atkbc_t *dev, uint8_t flags); - - -/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ -uint8_t keyboard_mode = 0x42; - -uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; - - -uint8_t mouse_queue[16]; -int mouse_queue_start = 0, mouse_queue_end = 0; -static void (*mouse_write)(uint8_t val, void *priv) = NULL; -static void *mouse_p = NULL; -static uint8_t sc_or = 0; -static atkbc_t *saved_kbc = NULL; - - -/* Non-translated to translated scan codes. */ -static const uint8_t nont_to_t[256] = { - 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, - 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, - 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, - 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, - 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, - 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, - 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, - 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, - 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, - 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, - 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, - 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, - 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, - 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, - 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, - 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, - 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -}; - - -#define UISTR_LEN 256 -static char kbc_str[UISTR_LEN]; /* UI output string */ - - -extern void ui_sb_bugui(char *__str); - - -static void -kbc_status(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsprintf(kbc_str, fmt, ap); - ui_sb_bugui(kbc_str); - va_end(ap); -} - - -#define ENABLE_KBC_AT_LOG 1 -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) -int kbc_at_do_log = ENABLE_KBC_AT_LOG; - - -static void -kbc_log(atkbc_t *dev, const char *fmt, ...) -{ - va_list ap; - - if ((dev == NULL) || (dev->log == NULL)) - return; - - if (kbc_at_do_log) { - va_start(ap, fmt); - log_out(dev->log, fmt, ap); - va_end(ap); - } -} -#else -#define kbc_log(dev, fmt, ...) -#endif - - -static void -kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) -{ - uint8_t ch = (channel > 0) ? channel : 1; - uint8_t do_irq = (dev->mem[0x20] & ch); - int translate = (channel == 1) && (keyboard_mode & 0x60); - - if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) - return; - - stat_hi |= dev->inhibit; - - if (!dev->kbc_send_pending) { - dev->kbc_send_pending = 1; - dev->kbc_to_send = val; - dev->kbc_channel = channel; - dev->kbc_stat_hi = stat_hi; - return; - } - - if (translate) { - /* Allow for scan code translation. */ - if (val == 0xf0) { - kbc_log(dev, "Translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if ((sc_or == 0x80) && (val & 0x80)) { - kbc_log(dev, "Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - } - - dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; - if (do_irq) { - kbc_log(dev, "[%04X:%08X] IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); - picint(dev->last_irq); - } - kbc_log(dev, "%02X coming from channel %i (%i)\n", val, channel, do_irq); - dev->ob = translate ? (nont_to_t[val] | sc_or) : val; - - dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); - if (ch == 2) - dev->status |= STAT_MFULL; - - if (translate && (sc_or == 0x80)) - sc_or = 0; -} - - -static void -write_output(atkbc_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbc_log(dev, "Write output port: %02X (old: %02X)\n", val, dev->p2); - - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - val |= ((dev->mem[0x20] << 4) & 0x30); - - dev->kbc_devs[0]->inhibit = (val & 0x40); - dev->kbc_devs[1]->inhibit = (val & 0x08); - - if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) { - kbc_log(dev, "write_output(): IRQ 12\n"); - picint(1 << 12); - } else - picintc(1 << 12); - } - if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) { - kbc_log(dev, "write_output(): IRQ 1\n"); - picint(1 << 1); - } else - picintc(1 << 1); - } - if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->p2 ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->p2 = val; -} - - -static void -write_cmd(atkbc_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbc_log(dev, "Write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) - val &= ~CCB_TRANSLATE; - - dev->mem[0x20] = val; - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbc_log(dev, "Keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { - keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->p2); - - kbc_log(dev, "Mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - kbc_log(dev, "Command byte now: %02X (%02X)\n", dev->mem[0x20], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbc_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_p2 = dev->p2 & ~(0xf0 | mask); - kbc_log(dev, "pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - -static void -set_enable_kbd(atkbc_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xef; - dev->mem[0x20] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbc_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xdf; - dev->mem[0x20] |= (enable ? 0x00 : 0x20); -} - - -static void -kbc_transmit(atkbc_t *dev, uint8_t val) -{ - kbc_send_to_ob(dev, val, 0, 0x00); -} - - -static void -kbc_command(atkbc_t *dev) -{ - uint8_t mask, val = dev->ib; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - int bad = 1; - - if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { - if (dev-> kbc_phase < 16) - kbc_transmit(dev, dev->mem[dev->kbc_phase]); - else if (dev-> kbc_phase == 16) - kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); - else if (dev-> kbc_phase == 17) - kbc_transmit(dev, dev->p2); - else if (dev-> kbc_phase == 18) - kbc_transmit(dev, dev->status); - - dev->kbc_phase++; - if (dev->kbc_phase == 19) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } - return; - } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { - val = ami_copr[dev->kbc_phase]; - kbc_transmit(dev, val); - if (val == 0x00) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } else - dev->kbc_phase++; - return; - } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { - /* load security */ - kbc_log(dev, "Load security\n"); - dev->mem[0x50 + dev->kbc_in - 0x01] = val; - if ((dev->kbc_in == 0x80) && (val != 0x00)) { - /* Security string too long, set it to 0x00. */ - dev->mem[0x50] = 0x00; - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else if (val == 0x00) { - /* Security string finished. */ - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else /* Increase pointer and request another byte. */ - dev->kbc_in++; - return; - } - - /* If the written port is 64, go straight to the beginning of the command. */ - if (!(dev->status & STAT_CD) && dev->kbc_in) { - /* Write data to controller. */ - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (dev->kbc_cmd) { - case 0x60 ... 0x7f: - if (dev->kbc_cmd == 0x60) - write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; - break; - - case 0xc7: /* or input port with system data */ - dev->p1 |= val; - break; - - case 0xcb: /* set keyboard mode */ - kbc_log(dev, "New AMIKey mode: %02X\n", val); - dev->ami_mode = val; - dev->flags &= ~KBC_FLAG_PS2; - if (val & 1) - dev->flags |= KBC_FLAG_PS2; -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) - log_set_dev_name(dev->kbc_log, (dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); -#endif - break; - - case 0xd1: /* write output port */ - if (dev->p2_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->p2 & 0x0c); - } - kbc_log(dev, "Write %02X to output port\n", val); - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbc_log(dev, "Write %02X to keyboard output buffer\n", val); - /* Should be channel 1, but we send to 0 to avoid translation, - since bytes output using this command do *NOT* get translated. */ - kbc_send_to_ob(dev, val, 0, 0x00); - break; - - case 0xd3: /* write to mouse output buffer */ - kbc_log(dev, "Write %02X to mouse output buffer\n", val); - if (dev->flags & KBC_FLAG_PS2) - kbc_send_to_ob(dev, val, 2, 0x00); - break; - - case 0xd4: /* write to mouse */ - kbc_log(dev, "Write %02X to mouse\n", val); - - if (dev->flags & KBC_FLAG_PS2) { - set_enable_mouse(dev, 1); - dev->mem[0x20] &= ~0x20; - if (dev->kbc_devs[1] && !dev->kbc_devs[1]->c_in) { - kbc_log(dev, "Transmitting %02X to mouse...\n", dev->ib); - dev->kbc_devs[1]->d_data = val; - dev->kbc_devs[1]->d_in = 1; - dev->kbc_wait_for_response = 2; - } else - kbc_send_to_ob(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - - if (bad) - kbc_log(dev, "Bad controller command %02x data %02x\n", dev->kbc_cmd, val); - } - } else { - /* Controller command. */ - kbc_log(dev, "Controller command: %02X\n", val); - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (val) { - /* Read data from KBC memory. */ - case 0x20 ... 0x3f: - kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); - break; - - /* Write data to KBC memory. */ - case 0x60 ... 0x7f: - dev->kbc_in = 1; - break; - - case 0xaa: /* self-test */ - kbc_log(dev, "Self-test\n"); - write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - dev->in_cmd = dev->mouse_in_cmd = 0; - dev->status &= ~STAT_OFULL; - dev->last_irq = 0; - dev->kbc_phase = 0; - - /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ - if (dev->flags & KBC_FLAG_PS2) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - kbc_transmit(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbc_log(dev, "Interface test\n"); - /* No error. */ - kbc_transmit(dev, 0x00); - break; - - case 0xac: /* diagnostic dump */ - kbc_log(dev, "Diagnostic dump\n"); - kbc_transmit(dev, dev->mem[0x20]); - dev->kbc_phase = 1; - break; - - case 0xad: /* disable keyboard */ - kbc_log(dev, "Disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbc_log(dev, "Enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xc7: /* or input port with system data */ - kbc_log(dev, "Phoenix - or input port with system data\n"); - dev->kbc_in = 1; - break; - - case 0xca: /* read keyboard mode */ - kbc_log(dev, "AMI - Read keyboard mode\n"); - kbc_transmit(dev, dev->ami_mode); - break; - - case 0xcb: /* set keyboard mode */ - kbc_log(dev, "ATkbc: AMI - Set keyboard mode\n"); - dev->kbc_in = 1; - break; - - case 0xd0: /* read output port */ - kbc_log(dev, "Read output port\n"); - mask = 0xff; - if (dev->mem[0x20] & 0x10) - mask &= 0xbf; - if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) - mask &= 0xf7; - kbc_transmit(dev, dev->p2 & mask); - break; - - case 0xd1: /* write output port */ - kbc_log(dev, "Write output port\n"); - dev->kbc_in = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbc_log(dev, "Write keyboard output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - dev->kbc_in = 1; - else - kbc_transmit(dev, 0x00); /* NCR */ - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbc_log(dev, "%sable A20\n", (val == 0xdd) ? "Dis": "En"); - write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbc_log(dev, "Read test inputs\n"); - kbc_transmit(dev, 0x00); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - if (bad) - kbc_log(dev, "Bad controller command %02X\n", val); - } - - /* If the command needs data, remember the command. */ - if (dev->kbc_in || (dev->kbc_phase > 0)) - dev->kbc_cmd = val; - } -} - - -static void -kbc_dev_data_to_ob(atkbc_t *dev, uint8_t channel) -{ - if (channel == 0) - return; - - dev->kbc_devs[channel - 1]->c_in = 0; - kbc_log(dev, "Forwarding %02X from channel %i...\n", dev->kbc_devs[channel - 1]->c_data, channel); - kbc_send_to_ob(dev, dev->kbc_devs[channel - 1]->c_data, channel, 0x00); -} - - -static void -kbc_main_loop_scan(atkbc_t *dev) -{ - uint8_t port_dis = dev->mem[0x20] & 0x30; - uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); - - if (!ps2) - port_dis |= 0x20; - - if (!(dev->status & STAT_OFULL)) { - if (port_dis & 0x20) { - if (!(port_dis & 0x10)) { - kbc_log(dev, "kbc_process(): Main loop, Scan: AUX DIS, KBD EN\n"); - /* Enable communication with keyboard. */ - dev->p2 &= 0xbf; - dev->kbc_devs[0]->inhibit = 0; - kbc_wait(dev, 1); - } else - kbc_log(dev, "kbc_process(): Main loop, Scan: AUX DIS, KBD DIS\n"); - } else { - /* Enable communication with mouse. */ - dev->p2 &= 0xf7; - dev->kbc_devs[1]->inhibit = 0; - if (dev->mem[0x20] & 0x10) { - kbc_log(dev, "kbc_process(): Main loop, Scan: AUX EN , KBD DIS\n"); - kbc_wait(dev, 2); - } else { - /* Enable communication with keyboard. */ - kbc_log(dev, "kbc_process(): Main loop, Scan: AUX EN , KBD EN\n"); - dev->p2 &= 0xbf; - dev->kbc_devs[0]->inhibit = 0; - kbc_wait(dev, 3); - } - } - } else - kbc_log(dev, "kbc_process(): Main loop, Scan: IBF not full and OBF full, do nothing\n"); -} - - -static uint8_t -kbc_reset_cmd(atkbc_t *dev) -{ - uint8_t ret = 0; - - if ((dev->status & STAT_CD) || (dev->kbc_poll_phase == KBC_WAIT_FOR_NOBF)) { - kbc_log(dev, " Resetting command\n"); - dev->kbc_phase = 0; - dev->kbc_in = 0; - dev->kbc_in_cmd = 0; - dev->kbc_poll_phase = KBC_MAIN_LOOP; - ret = 1; - } - - return ret; -} - - -static uint8_t -kbc_process_cmd(atkbdt_t *dev, uint8_t restart) -{ - uint8_t ret = 0; - - if (restart) - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - ret = 1; - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - if (!dev->kbc_wait_for_response && !(dev->status & STAT_OFULL)) - kbc_main_loop_scan(dev); - - return ret; -} - - -static void -kbc_process_ib(atkbc_t *dev) -{ - if ((dev->status & STAT_CD) || (kbc->flags & KBC_FLAG_PS2) || !(dev->status & STAT_OFULL)) - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) - (void) kbc_process_cmd(dev, 1); - else if ((kbc->flags & KBC_FLAG_PS2) || !(dev->status & STAT_OFULL)) - /* The AT KBC does *NOT* send data to the keyboard if OBF. */ - set_enable_mouse(dev, 1); - dev->mem[0x20] &= ~0x10; - if (dev->kbc_devs[0] && !dev->kbc_devs[0]->c_in) { - dev->kbc_devs[0]->d_data = val; - dev->kbc_devs[0]->d_in = 1; - dev->kbc_wait_for_response = 1; - } else - kbc_send_to_ob(dev, 0xfe, 1, 0x40); - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - if (!dev->kbc_wait_for_response && !(dev->status & STAT_OFULL)) - kbc_main_loop_scan(dev); - } -} - - -static void -kbc_wait(atkbc_t *dev, uint8_t flags) -{ - if ((flags & 1) && dev->kbc_devs[0]->c_in) { - /* Disable communication with mouse. */ - dev->p2 |= 0x08; - dev->kbc_devs[1]->inhibit = 1; - /* Send keyboard byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_KBD); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if ((flags & 2) && dev->kbc_devs[1]->c_in) { - /* Disable communication with keyboard. */ - dev->p2 |= 0x40; - dev->kbc_devs[0]->inhibit = 1; - /* Send mouse byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if (dev->status & STAT_IFULL) { - /* Disable communication with keyboard and mouse. */ - dev->p2 |= 0x48; - dev->kbc_devs[0]->inhibit = dev->kbc_devs[1]->inhibit = 1; - kbc_process_ib(dev); - } else - dev->kbc_poll_phase = KBC_WAIT | flags; -} - - -/* Controller processing */ -static void -kbc_process(atkbc_t *dev) -{ - /* If we're waiting for the response from the keyboard or mouse, do nothing - until the device has repsonded back. */ - if (dev->kbc_wait_for_response > 0) { - if (dev->kbc_devs[dev->kbc_wait_for_response - 1]->c_in) - dev->kbc_wait_for_response = 0; - else - return; - } - - if (dev->kbc_send_pending) { - kbc_log(dev, "Sending delayed %02X on channel %i with high status %02X\n", - dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - dev->kbc_send_pending = 0; - } - - /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ - if ((dev->kbc_poll_phase == KBC_RESET) || (dev->kbc_poll_phase >= KBC_WAIT_FOR_NIBF) || - !(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { - case KBC_RESET: - kbc_log(dev, "kbc_process(): Reset loop()\n"); - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { - (void) kbc_process_cmd(dev, 1); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } - } - break; - case KBC_MAIN_LOOP: - if (dev->status & STAT_IFULL) { - kbc_log(dev, "kbc_process(): Main loop, IBF full, process\n"); - kbc_process_ib(dev); - } else - kbc_main_loop_scan(dev); - break; - case KBC_SCAN_KBD: - case KBC_SCAN_MOUSE: - case KBC_SCAN_BOTH: - kbc_log(dev, "kbc_process(): Scan: Phase %i\n", dev->kbc_poll_phase); - kbc_wait(dev, dev->kbc_poll_phase & 3); - break; - case KBC_WAIT_FOR_NOBF: - kbc_log(dev, "kbc_process(): Waiting for !OBF\n"); - - if (dev->status & STAT_IFULL) { - /* Host writing a command aborts the current command. */ - (void) !kbc_reset_cmd(dev); - - /* Process the input buffer. */ - kbc_process_ib(dev); - } else if (!dev->status & STAT_OFULL) { - /* Not aborted and OBF cleared - process command. */ - kbc_log(dev, " Continuing commmand\n"); - - if (kbc_process_cmd(dev, 0)) - return; - } - break; - case KBC_WAIT_FOR_IBF: - kbc_log(dev, "kbc_process(): Waiting for IBF\n"); - - if (dev->status & STAT_IFULL) { - /* IBF, process if port 60h, otherwise abort the current command. */ - dev->status &= ~STAT_IFULL; - - if (!kbc_reset_cmd(dev)) - kbc_log(dev, " Continuing commmand\n"); - - /* Process command. */ - if (kbc_process_cmd(dev, 0)) - return; - } - break; - default: - kbc_log(dev, "kbc_process(): Invalid phase %i\n", dev->kbc_poll_phase); - break; - } -} - - -static void -kbd_poll(void *priv) -{ - atkbc_t *dev = (atkbc_t *) priv; - uint8_t i; - - if (dev == NULL) - return; - - timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - - /* Device processing */ - for (i = 0; i < 2; i++) { - if (dev->kbc_devs[i] && dev->kbd_devs[i]->priv && dev->kbd_devs[i]->process) - dev->kbc_devs[i]->process(dev->kbc_devs[i]->priv); - } - - /* Controller processing */ - kbc_process(dev); -} - - -static void -pulse_poll(void *priv) -{ - atkbc_t *dev = (atkbc_t *)priv; - - kbc_log(dev, "pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); - write_output(dev, dev->p2 | dev->old_p2); -} - - -static uint8_t -write64_generic(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - - switch (val) { - case 0xa4: /* check if password installed */ - if (dev->flags & KBC_FLAG_PS2) { - kbc_log(dev, "Check if password installed\n"); - kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); - return 0; - } - break; - - case 0xa5: /* load security */ - if (dev->flags & KBC_FLAG_PS2) { - kbc_log(dev, "Load security\n"); - dev->kbc_in = 1; - return 0; - } - break; - - case 0xa7: /* disable mouse port */ - if (dev->flags & KBC_FLAG_PS2) { - kbc_log(dev, "Disable mouse port\n"); - return 0; - } - break; - - case 0xa8: /*Enable mouse port*/ - if (dev->flags & KBC_FLAG_PS2) { - kbc_log(dev, "Enable mouse port\n"); - return 0; - } - break; - - case 0xa9: /*Test mouse port*/ - kbc_log(dev, "Test mouse port\n"); - if (dev->flags & KBC_FLAG_PS2) { - /* No error, this is testing the channel 2 interface. */ - kbc_transmit(dev, 0x00); - return 0; - } - break; - - case 0xaf: /* read keyboard version */ - kbc_log(dev, "Read keyboard version\n"); - kbc_transmit(dev, 0x00); - return 0; - - case 0xc0: /* read input port */ - /* IBM PS/1: - Bit 2 and 4 ignored (we return always 0), - Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". - Intel AMI: - Bit 2 ignored (we return always 1), - Bit 4 must be 1, - Bit 6 must be 1 or else error in SMM. - Acer: - Bit 2 must be 0, - Bit 4 must be 0, - Bit 6 ignored. - P6RP4: - Bit 2 must be 1 or CMOS setup is disabled. */ - kbc_log(dev, "Read input port\n"); - fixed_bits = 4; - /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ - if (kbc_ven == KBC_VEN_INTEL_AMI) - fixed_bits |= 0x40; - if (kbc_ven == KBC_VEN_IBM_PS1) { - current_drive = fdc_get_current_drive(); - kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); - } else if (kbc_ven == KBC_VEN_NCR) { - /* switch settings - * bit 7: keyboard disable - * bit 6: display type (0 color, 1 mono) - * bit 5: power-on default speed (0 high, 1 low) - * bit 4: sense RAM size (0 unsupported, 1 512k on system board) - * bit 3: coprocessor detect - * bit 2: unused - * bit 1: high/auto speed - * bit 0: dma mode - */ - kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); - } else { - if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); - else - kbc_transmit(dev, dev->p1 | fixed_bits); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); - } - return 0; - - case 0xd3: /* write mouse output buffer */ - if (dev->flags & KBC_FLAG_PS2) { - kbc_log(dev, "Write mouse output buffer\n"); - dev->kbc_in = 1; - return 0; - } - break; - - case 0xd4: /* write to mouse */ - kbc_log(dev, "Write to mouse\n"); - dev->kbc_in = 1; - return 0; - - case 0xf0 ... 0xff: - kbc_log(dev, "Pulse %01X\n", val & 0x0f); - pulse_output(dev, val & 0x0f); - return 0; - } - - kbc_log(dev, "Bad command %02X\n", val); - return 1; -} - - -static uint8_t -write60_ami(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - uint16_t index = 0x00c0; - - switch(dev->kbc_cmd) { - /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ - case 0x40 ... 0x5f: - kbc_log(dev, "AMI - Alias write to %08X\n", dev->kbc_cmd); - if (dev->kbc_cmd == 0x40) - write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; - return 0; - - case 0xaf: /* set extended controller RAM */ - kbc_log(dev, "AMI - Set extended controller RAM, input phase %i\n", dev->secr_phase); - if (dev->secr_phase == 0) { - dev->mem_index = val; - dev->kbc_in = 1; - dev->secr_phase++; - } else if (dev->secr_phase == 1) { - if (dev->mem_index == 0x20) - write_cmd(dev, val); - else - dev->mem[dev->mem_index] = val; - dev->secr_phase = 0; - } - return 0; - - case 0xb8: - kbc_log(dev, "AMIKey-3 - Memory index %02X\n", val); - dev->mem_index = val; - return 0; - - case 0xbb: - kbc_log(dev, "AMIKey-3 - write %02X to memory index %02X\n", val, dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - dev->mem[index + dev->mem_index] = val; - } else if (dev->mem_index == 0x60) - write_cmd(dev, val); - else if (dev->mem_index == 0x42) - dev->status = val; - else if (dev->mem_index >= 0x40) - dev->mem[dev->mem_index - 0x40] = val; - else - dev->mem_int[dev->mem_index] = val; - return 0; - - case 0xbd: - kbc_log(dev, "AMIKey-3 - write %02X to config index %02X\n", val, dev->mem_index); - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - dev->status = val; - break; - case 0x01: /* Password_ptr */ - dev->mem[0x1c] = val; - break; - case 0x02: /* Wakeup_Tsk_Reg */ - dev->mem[0x1e] = val; - break; - case 0x03: /* CCB */ - write_cmd(dev, val); - break; - case 0x04: /* Debounce_time */ - dev->mem[0x4d] = val; - break; - case 0x05: /* Pulse_Width */ - dev->mem[0x4e] = val; - break; - case 0x06: /* Pk_sel_byte */ - dev->mem[0x4c] = val; - break; - case 0x07: /* Func_Tsk_Reg */ - dev->mem[0x7e] = val; - break; - case 0x08: /* TypematicRate */ - dev->mem[0x80] = val; - break; - case 0x09: /* Led_Flag_Byte */ - dev->mem[0x81] = val; - break; - case 0x0a: /* Kbms_Command_St */ - dev->mem[0x87] = val; - break; - case 0x0b: /* Delay_Count_Byte */ - dev->mem[0x86] = val; - break; - case 0x0c: /* KBC_Flags */ - dev->mem[0x9b] = val; - break; - case 0x0d: /* SCODE_HK1 */ - dev->mem[0x50] = val; - break; - case 0x0e: /* SCODE_HK2 */ - dev->mem[0x51] = val; - break; - case 0x0f: /* SCODE_HK3 */ - dev->mem[0x52] = val; - break; - case 0x10: /* SCODE_HK4 */ - dev->mem[0x53] = val; - break; - case 0x11: /* SCODE_HK5 */ - dev->mem[0x54] = val; - break; - case 0x12: /* SCODE_HK6 */ - dev->mem[0x55] = val; - break; - case 0x13: /* TASK_HK1 */ - dev->mem[0x56] = val; - break; - case 0x14: /* TASK_HK2 */ - dev->mem[0x57] = val; - break; - case 0x15: /* TASK_HK3 */ - dev->mem[0x58] = val; - break; - case 0x16: /* TASK_HK4 */ - dev->mem[0x59] = val; - break; - case 0x17: /* TASK_HK5 */ - dev->mem[0x5a] = val; - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - dev->mem[0x5b] = val; - break; - case 0x19: /* Batt_Alarm_Reg1 */ - dev->mem[0x5c] = val; - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - dev->mem[0x5d] = val; - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - dev->mem[0x5e] = val; - break; - case 0x1c: /* Kbc_State1 */ - dev->mem[0x9d] = val; - break; - case 0x1d: /* Aux_Config */ - dev->mem[0x75] = val; - break; - case 0x1e: /* Kbc_State3 */ - dev->mem[0x73] = val; - break; - } - return 0; - - case 0xc1: /* write input port */ - kbc_log(dev, "AMI MegaKey - write %02X to input port\n", val); - dev->p1 = val; - return 0; - - case 0xcb: /* set keyboard mode */ - kbc_log(dev, "AMI - Set keyboard mode\n"); - return 0; - } - - return 1; -} - - -static uint8_t -write64_ami(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - uint16_t index = 0x00c0; - - switch (val) { - case 0x00 ... 0x1f: - kbc_log(dev, "AMI - Alias read from %08X\n", val); - kbc_transmit(dev, dev->mem[val + 0x20]); - return 0; - - case 0x40 ... 0x5f: - kbc_log(dev, "AMI - Alias write to %08X\n", dev->kbc_cmd); - dev->kbc_in = 1; - return 0; - - case 0xa0: /* copyright message */ - kbc_log(dev, "AMI - Get copyright message\n"); - kbc_transmit(dev, ami_copr[0]); - dev->kbc_phase = 1; - return 0; - - case 0xa1: /* get controller version */ - kbc_log(dev, "AMI - Get controller version\n"); - // kbc_transmit(dev, 'H'); - kbc_transmit(dev, '5'); - return 0; - - case 0xa2: /* clear keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Clear KBC lines P22 and P23\n"); - write_output(dev, dev->p2 & 0xf3); - kbc_transmit(dev, 0x00); - return 0; - } - break; - - case 0xa3: /* set keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Set KBC lines P22 and P23\n"); - write_output(dev, dev->p2 | 0x0c); - kbc_transmit(dev, 0x00); - return 0; - } - break; - - case 0xa4: /* write clock = low */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Write clock = low\n"); - dev->ami_stat &= 0xfe; - return 0; - } - break; - - case 0xa5: /* write clock = high */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Write clock = high\n"); - dev->ami_stat |= 0x01; - return 0; - } - break; - - case 0xa6: /* read clock */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Read clock\n"); - kbc_transmit(dev, !!(dev->ami_stat & 1)); - return 0; - } - break; - - case 0xa7: /* write cache bad */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Write cache bad\n"); - dev->ami_stat &= 0xfd; - return 0; - } - break; - - case 0xa8: /* write cache good */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Write cache good\n"); - dev->ami_stat |= 0x02; - return 0; - } - break; - - case 0xa9: /* read cache */ - if (!(dev->flags & KBC_FLAG_PS2)) { - kbc_log(dev, "AMI - Read cache\n"); - kbc_transmit(dev, !!(dev->ami_stat & 2)); - return 0; - } - break; - - case 0xaf: /* set extended controller RAM */ - kbc_log(dev, "AMI - Set extended controller RAM\n"); - dev->kbc_in = 1; - return 0; - - case 0xb0 ... 0xb3: - /* set KBC lines P10-P13 (input port bits 0-3) low */ - kbc_log(dev, "AMI - Set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { - dev->p1 &= ~(1 << (val & 0x03)); - } - kbc_transmit(dev, 0x00); - return 0; - - case 0xb4: case 0xb5: - /* set KBC lines P22-P23 (output port bits 2-3) low */ - kbc_log(dev, "AMI - Set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 & ~(4 << (val & 0x01))); - kbc_transmit(dev, 0x00); - return 0; - -#if 0 - case 0xb8 ... 0xbb: -#else - case 0xb9: -#endif - /* set KBC lines P10-P13 (input port bits 0-3) high */ - kbc_log(dev, "AMI - Set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { - dev->p1 |= (1 << (val & 0x03)); - kbc_transmit(dev, 0x00); - } - return 0; - - case 0xb8: - kbc_log(dev, "AMIKey-3 - memory index\n"); - dev->kbc_in = 1; - return 0; - - case 0xba: - kbc_log(dev, "AMIKey-3 - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - kbc_transmit(dev, dev->mem[index + dev->mem_index]); - } else if (dev->mem_index == 0x42) - kbc_transmit(dev, dev->status); - else if (dev->mem_index >= 0x40) - kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); - else - kbc_transmit(dev, dev->mem_int[dev->mem_index]); - return 0; - - case 0xbb: - kbc_log(dev, "AMIKey-3 - write to memory index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - -#if 0 - case 0xbc: case 0xbd: - /* set KBC lines P22-P23 (output port bits 2-3) high */ - kbc_log(dev, "AMI - Set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 | (4 << (val & 0x01))); - kbc_transmit(dev, 0x00); - return 0; -#endif - - case 0xbc: - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - kbc_transmit(dev, dev->status); - break; - case 0x01: /* Password_ptr */ - kbc_transmit(dev, dev->mem[0x1c]); - break; - case 0x02: /* Wakeup_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x1e]); - break; - case 0x03: /* CCB */ - kbc_transmit(dev, dev->mem[0x20]); - break; - case 0x04: /* Debounce_time */ - kbc_transmit(dev, dev->mem[0x4d]); - break; - case 0x05: /* Pulse_Width */ - kbc_transmit(dev, dev->mem[0x4e]); - break; - case 0x06: /* Pk_sel_byte */ - kbc_transmit(dev, dev->mem[0x4c]); - break; - case 0x07: /* Func_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x7e]); - break; - case 0x08: /* TypematicRate */ - kbc_transmit(dev, dev->mem[0x80]); - break; - case 0x09: /* Led_Flag_Byte */ - kbc_transmit(dev, dev->mem[0x81]); - break; - case 0x0a: /* Kbms_Command_St */ - kbc_transmit(dev, dev->mem[0x87]); - break; - case 0x0b: /* Delay_Count_Byte */ - kbc_transmit(dev, dev->mem[0x86]); - break; - case 0x0c: /* KBC_Flags */ - kbc_transmit(dev, dev->mem[0x9b]); - break; - case 0x0d: /* SCODE_HK1 */ - kbc_transmit(dev, dev->mem[0x50]); - break; - case 0x0e: /* SCODE_HK2 */ - kbc_transmit(dev, dev->mem[0x51]); - break; - case 0x0f: /* SCODE_HK3 */ - kbc_transmit(dev, dev->mem[0x52]); - break; - case 0x10: /* SCODE_HK4 */ - kbc_transmit(dev, dev->mem[0x53]); - break; - case 0x11: /* SCODE_HK5 */ - kbc_transmit(dev, dev->mem[0x54]); - break; - case 0x12: /* SCODE_HK6 */ - kbc_transmit(dev, dev->mem[0x55]); - break; - case 0x13: /* TASK_HK1 */ - kbc_transmit(dev, dev->mem[0x56]); - break; - case 0x14: /* TASK_HK2 */ - kbc_transmit(dev, dev->mem[0x57]); - break; - case 0x15: /* TASK_HK3 */ - kbc_transmit(dev, dev->mem[0x58]); - break; - case 0x16: /* TASK_HK4 */ - kbc_transmit(dev, dev->mem[0x59]); - break; - case 0x17: /* TASK_HK5 */ - kbc_transmit(dev, dev->mem[0x5a]); - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - kbc_transmit(dev, dev->mem[0x5b]); - break; - case 0x19: /* Batt_Alarm_Reg1 */ - kbc_transmit(dev, dev->mem[0x5c]); - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - kbc_transmit(dev, dev->mem[0x5d]); - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x5e]); - break; - case 0x1c: /* Kbc_State1 */ - kbc_transmit(dev, dev->mem[0x9d]); - break; - case 0x1d: /* Aux_Config */ - kbc_transmit(dev, dev->mem[0x75]); - break; - case 0x1e: /* Kbc_State3 */ - kbc_transmit(dev, dev->mem[0x73]); - break; - default: - kbc_transmit(dev, 0x00); - break; - } - kbc_log(dev, "AMIKey-3 - read from config index %02X\n", dev->mem_index); - return 0; - - case 0xbd: - kbc_log(dev, "AMIKey-3 - write to config index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - - case 0xc1: /* write input port */ - kbc_log(dev, "AMIKey-3 - write input port\n"); - dev->kbc_in = 1; - return 0; - - case 0xc8: case 0xc9: - /* - * (un)block KBC lines P22/P23 - * (allow command D1 to change bits 2/3 of the output port) - */ - kbc_log(dev, "AMI - %slock KBC lines P22 and P23\n", (val & 1) ? "B" : "Unb"); - dev->p2_locked = (val & 1); - return 0; - - case 0xef: /* ??? - sent by AMI486 */ - kbc_log(dev, "??? - sent by AMI486\n"); - return 0; - } - - return write64_generic(dev, val); -} - - -static uint8_t -write64_ibm_mca(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch (val) { - case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ - kbc_log(dev, "Copy bits 0 to 3 of input port to status bits 4 to 7\n"); - dev->status &= 0x0f; - dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); - return 0; - - case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ - kbc_log(dev, "Copy bits 4 to 7 of input port to status bits 4 to 7\n"); - dev->status &= 0x0f; - dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); - return 0; - - case 0xaf: - kbc_log(dev, "Bad KBC command AF\n"); - return 1; - - case 0xf0 ... 0xff: - kbc_log(dev, "Pulse: %01X\n", (val & 0x03) | 0x0c); - pulse_output(dev, (val & 0x03) | 0x0c); - return 0; - } - - return write64_generic(dev, val); -} - - -static uint8_t -write60_quadtel(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch(dev->kbc_cmd) { - case 0xcf: /*??? - sent by MegaPC BIOS*/ - kbc_log(dev, "??? - sent by MegaPC BIOS\n"); - return 0; - } - - return 1; -} - - -static uint8_t -write64_olivetti(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch (val) { - /* This appears to be a clone of "Read input port", in which case, the bis would be: - 7: M290 (AT KBC): - Keyboard lock (1 = unlocked, 0 = locked); - M300 (PS/2 KBC): - Bus expansion board present (1 = present, 0 = not present); - 6: Usually: - Display (1 = MDA, 0 = CGA, but can have its polarity inverted); - 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); - 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); - 3: Fast Ram check (if inactive keyboard works erratically); - 2: Keyboard fuse present - This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; - 1: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Mouse data in; - 0: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Key data in. - */ - case 0x80: /* Olivetti-specific command */ - /* - * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) - * bits 4-6: ??? - * bit 3: fast ram check (if inactive keyboard works erratically) - * bit 2: keyboard fuse present - * bits 0-1: ??? - */ - kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); - return 0; - } - - return write64_generic(dev, val); -} - - -static uint8_t -write64_quadtel(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch (val) { - case 0xaf: - kbc_log(dev, "Bad KBC command AF\n"); - return 1; - - case 0xcf: /*??? - sent by MegaPC BIOS*/ - kbc_log(dev, "??? - sent by MegaPC BIOS\n"); - dev->kbc_in = 1; - return 0; - } - - return write64_generic(dev, val); -} - - -static uint8_t -write60_toshiba(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch(dev->kbc_cmd) { - case 0xb6: /* T3100e - set color/mono switch */ - kbc_log(dev, "T3100e - Set color/mono switch\n"); - t3100e_mono_set(val); - return 0; - } - - return 1; -} - - -static uint8_t -write64_toshiba(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *)priv; - - switch (val) { - case 0xaf: - kbc_log(dev, "Bad KBC command AF\n"); - return 1; - - case 0xb0: /* T3100e: Turbo on */ - kbc_log(dev, "T3100e: Turbo on\n"); - t3100e_turbo_set(1); - return 0; - - case 0xb1: /* T3100e: Turbo off */ - kbc_log(dev, "T3100e: Turbo off\n"); - t3100e_turbo_set(0); - return 0; - - case 0xb2: /* T3100e: Select external display */ - kbc_log(dev, "T3100e: Select external display\n"); - t3100e_display_set(0x00); - return 0; - - case 0xb3: /* T3100e: Select internal display */ - kcd_log("T3100e: Select internal display\n"); - t3100e_display_set(0x01); - return 0; - - case 0xb4: /* T3100e: Get configuration / status */ - kbc_log(dev, "T3100e: Get configuration / status\n"); - kbc_transmit(dev, t3100e_config_get()); - return 0; - - case 0xb5: /* T3100e: Get colour / mono byte */ - kbc_log(dev, "T3100e: Get colour / mono byte\n"); - kbc_transmit(dev, t3100e_mono_get()); - return 0; - - case 0xb6: /* T3100e: Set colour / mono byte */ - kbc_log(dev, "T3100e: Set colour / mono byte\n"); - dev->kbc_in = 1; - return 0; - - case 0xb7: /* T3100e: Emulate PS/2 keyboard */ - case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_FLAG_PS2; - if (val == 0xb7) { - kbc_log(dev, "T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_FLAG_PS2; - } else - kbc_log(dev, "T3100e: Emulate AT keyboard\n"); -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) - log_set_dev_name(dev->kbc_log, (dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); -#endif - return 0; - - case 0xbb: /* T3100e: Read 'Fn' key. - Return it for right Ctrl and right Alt; on the real - T3100e, these keystrokes could only be generated - using 'Fn'. */ - kbc_log(dev, "T3100e: Read 'Fn' key\n"); - if (keyboard_recv(0xb8) || /* Right Alt */ - keyboard_recv(0x9d)) /* Right Ctrl */ - kbc_transmit(dev, 0x04); - else - kbc_transmit(dev, 0x00); - return 0; - - case 0xbc: /* T3100e: Reset Fn+Key notification */ - kbc_log(dev, "T3100e: Reset Fn+Key notification\n"); - t3100e_notify_set(0x00); - return 0; - - case 0xc0: /*Read input port*/ - kbc_log(dev, "Read input port\n"); - - /* The T3100e returns all bits set except bit 6 which - * is set by t3100e_mono_set() */ - dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbc_transmit(dev, dev->p1); - return 0; - - } - - return write64_generic(dev, val); -} - - -static void -kbc_write(uint16_t port, uint8_t val, void *priv) -{ - atkbc_t *dev = (atkbc_t *)priv; - - kbc_log(dev, "[%04X:%08X] write(%04X, %02X)\n", CS, cpu_state.pc, port, val); - - switch (port) { - case 0x60: - dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - -#if 0 - if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { - dev->status &= ~STAT_IFULL; - write_output(dev, val); - dev->fast_a20_phase = 0; - } -#endif - break; - case 0x64: - dev->status |= (STAT_CD | STAT_IFULL); - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - -#if 0 - if (val == 0xd1) { - dev->status &= ~STAT_IFULL; - dev->fast_a20_phase = 1; - } else if (val == 0xfe) { - dev->status &= ~STAT_IFULL; - pulse_output(dev, 0x0e); - } else if ((val == 0xad) || (val == 0xae)) { - dev->status &= ~STAT_IFULL; - if (val & 0x01) - dev->mem[0x20] |= 0x10; - else - dev->mem[0x20] &= ~0x10; - } else if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); - } -#endif - break; - } -} - - -static uint8_t -kbc_read(uint16_t port, void *priv) -{ - atkbc_t *dev = (atkbc_t *)priv; - uint8_t ret = 0xff; - - // if (dev->flags & KBC_FLAG_PS2) - // cycles -= ISA_CYCLES(8); - - switch (port) { - case 0x60: - ret = dev->ob; - dev->status &= ~STAT_OFULL; - picintc(dev->last_irq); - dev->last_irq = 0; - break; - - case 0x64: - ret = dev->status; - break; - - default: - kbc_log(dev, "Reading unknown port %02X\n", port); - break; - } - - kbc_log(dev, "[%04X:%08X] read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); - - return(ret); -} - - -static void -kbc_reset(void *priv) -{ - atkbc_t *dev = (atkbc_t *)priv; - int i; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - - dev->status = STAT_UNLOCKED; - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; - write_output(dev, 0xcf); - dev->last_irq = 0; - dev->secr_phase = 0; - dev->in = 0; - dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); - - /* Set up the correct Video Type bits. */ - dev->p1 = video_is_mda() ? 0xf0 : 0xb0; - if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->p1 ^= 0x40; - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - dev->inhibit = ((dev->p1 & 0x80) >> 3); - else - dev->inhibit = 0x10; - kbc_log(dev, "Input port = %02x\n", dev->p1); - - keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); - - /* Enable keyboard, disable mouse. */ - set_enable_kbd(dev, 1); - keyboard_scan = 1; - set_enable_mouse(dev, 0); - mouse_scan = 0; - - dev->ob = 0xff; - - sc_or = 0; - - dev->mem[0x31] = 0xfe; -} - - -/* Reset the AT keyboard - this is needed for the PCI TRC and is done - until a better solution is found. */ -void -keyboard_at_reset(void) -{ - kbc_reset(SavedKbd); -} - - -void -kbc_dev_attach(kbc_dev_t *kbc_dev, int channel) -{ - if ((channel < 1) || (channel > 2)) - log_fatal(saved_kbc->log, "Attaching device to invalid channel %i\n", channel); - else { - kbc_log(saved_kbc, "Attaching device to channel %i\n", channel); - saved_kbc->kbc_devs[channel - 1] = kbc_dev; - } -} - - -static void -kbc_close(void *priv) -{ - atkbc_t *dev = (atkbc_t *)priv; - - kbc_reset(dev); - - /* Stop timers. */ - timer_disable(&dev->send_delay_timer); - -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) - log_close(dev->log); -#endif - - free(dev); -} - - -static void * -kbc_init(const device_t *info) -{ - atkbc_t *dev; - - dev = (atkbc_t *)malloc(sizeof(atkbc_t)); - memset(dev, 0x00, sizeof(atkbc_t)); - - dev->flags = info->local; - - video_reset(gfxcard); - dev->kbc_poll_phase = KBC_RESET; - - io_sethandler(0x0060, 1, kbc_read, NULL, NULL, kbc_write, NULL, NULL, dev); - io_sethandler(0x0064, 1, kbc_read, NULL, NULL, kbc_write, NULL, NULL, dev); - - timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); - -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBC_AT_LOG)) - dev->kbc_log = log_open((dev->flags & KBC_FLAG_PS2) ? "AT KBC" : "PS/2 KBC"); -#endif - - dev->write60_ven = NULL; - dev->write64_ven = NULL; - - switch(dev->flags & KBC_VEN_MASK) { - case KBC_VEN_ACER: - case KBC_VEN_GENERIC: - case KBC_VEN_NCR: - case KBC_VEN_IBM_PS1: - case KBC_VEN_XI8088: - dev->write64_ven = write64_generic; - break; - - case KBC_VEN_OLIVETTI: - /* The Olivetti controller is a special case - starts directly in the - main loop instead of the reset loop. */ - dev->kbc_poll_phase = KBC_MAIN_LOOP; - dev->write64_ven = write64_olivetti; - break; - - case KBC_VEN_AMI: - case KBC_VEN_INTEL_AMI: - dev->write60_ven = write60_ami; - dev->write64_ven = write64_ami; - break; - - case KBC_VEN_IBM_MCA: - dev->write64_ven = write64_ibm_mca; - break; - - case KBC_VEN_QUADTEL: - dev->write60_ven = write60_quadtel; - dev->write64_ven = write64_quadtel; - break; - - case KBC_VEN_TOSHIBA: - dev->write60_ven = write60_toshiba; - dev->write64_ven = write64_toshiba; - break; - } - - kbc_reset(dev); - - /* Local variable, needed for device attaching. */ - saved_kbc = dev; - - /* Add the actual keyboard. */ - device_add(&keyboard_at_kbd_device); - - return(dev); -} - - -const device_t keyboard_at_device = { - "PC/AT Keyboard", - 0, - KBC_TYPE_ISA | KBC_VEN_GENERIC, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_at_ami_device = { - "PC/AT Keyboard (AMI)", - 0, - KBC_TYPE_ISA | KBC_VEN_AMI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_at_toshiba_device = { - "PC/AT Keyboard (Toshiba)", - 0, - KBC_TYPE_ISA | KBC_VEN_TOSHIBA, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_at_olivetti_device = { - "PC/AT Keyboard (Olivetti)", - 0, - KBC_TYPE_ISA | KBC_VEN_OLIVETTI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_at_ncr_device = { - "PC/AT Keyboard (NCR)", - 0, - KBC_TYPE_ISA | KBC_VEN_NCR, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps1_device = { - "PS/2 Keyboard (IBM PS/1)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps1_pci_device = { - "PS/2 Keyboard (IBM PS/1)", - DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_xi8088_device = { - "PS/2 Keyboard (Xi8088)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_XI8088, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ami_device = { - "PS/2 Keyboard (AMI)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_olivetti_device = { - "PS/2 Keyboard (Olivetti)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_mca_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_mca_2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_quadtel_device = { - "PS/2 Keyboard (Quadtel/MegaPC)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_pci_device = { - "PS/2 Keyboard", - DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ami_pci_device = { - "PS/2 Keyboard (AMI)", - DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_intel_ami_pci_device = { - "PS/2 Keyboard (AMI)", - DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_acer_pci_device = { - "PS/2 Keyboard (Acer 90M002A)", - DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_ACER, - kbc_init, - kbc_close, - kbc_reset, - { NULL }, NULL, NULL, NULL -}; - - -void -keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) -{ -} - - -void -keyboard_at_adddata_mouse(uint8_t val) -{ - return; -} - - -void -keyboard_at_adddata_mouse_direct(uint8_t val) -{ - return; -} - - -void -keyboard_at_adddata_mouse_cmd(uint8_t val) -{ - return; -} - - -void -keyboard_at_mouse_reset(void) -{ - return; -} - - -uint8_t -keyboard_at_mouse_pos(void) -{ - return ((mouse_queue_end - mouse_queue_start) & 0xf); -} - - -int -keyboard_at_fixed_channel(void) -{ - return 0x000; -} - - -void -keyboard_at_set_mouse_scan(uint8_t val) -{ - atkbc_t *dev = SavedKbd; - uint8_t temp_mouse_scan = val ? 1 : 0; - - if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) - return; - - set_enable_mouse(dev, val ? 1 : 0); - - kbc_log(dev, "Mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); -} - - -uint8_t -keyboard_at_get_mouse_scan(void) -{ - atkbc_t *dev = SavedKbd; - - return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); -} - - -void -keyboard_at_set_a20_key(int state) -{ - atkbc_t *dev = SavedKbd; - - write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); -} - - -void -keyboard_at_set_mode(int ps2) -{ - atkbc_t *dev = SavedKbd; - - if (ps2) - dev->flags |= KBC_FLAG_PS2; - else - dev->flags &= ~KBC_FLAG_PS2; -} diff --git a/src/device/kbd_at.c b/src/device/kbd_at.c deleted file mode 100644 index f24177d37..000000000 --- a/src/device/kbd_at.c +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * 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. - * - * Intel 8042 (AT keyboard controller) emulation. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * EngiNerd - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. - * Copyright 2020 EngiNerd. - */ -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include -#include <86box/86box.h> -#include <86box/timer.h> -#include <86box/device.h> -#include <86box/log.h> -#include <86box/keyboard.h> - - -// static uint8_t key_queue[16]; -// static int key_queue_start = 0, key_queue_end = 0; -// static uint8_t kbd_last_scan_code; - -typedef struct { - uint8_t in, cmd, in_cmd, state, last_byte; - - uint8_t queue[16]; - - uint16_t phase; - - int quueue_start, queue_end; - - void * log; - - kbc_dev_t kd; -} atkbd_t; - - -enum -{ - CHANNEL_KBC = 0, - CHANNEL_KBD, - CHANNEL_MOUSE -}; - -enum -{ - KBD_MAIN_LOOP = 0, - KBD_CMD_PROCESS -}; - -enum -{ - MOUSE_MAIN_LOOP_1 = 0, - MOUSE_CMD_PROCESS, - MOUSE_CMD_END, - MOUSE_MAIN_LOOP_2 -}; - -enum { - KBC_MAIN_LOOP = 0, - KBC_RESET = 1, - KBC_WAIT = 4, - KBC_WAIT_FOR_KBD, - KBC_WAIT_FOR_MOUSE, - KBC_WAIT_FOR_BOTH -}; - - -static void kbd_cmd_process(atkbd_t *dev); - - -/* bit 0 = repeat, bit 1 = makes break code? */ -uint8_t keyboard_set3_flags[512]; -uint8_t keyboard_set3_all_repeat; -uint8_t keyboard_set3_all_break; - - -static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK - - -#ifdef USE_SET1 -static const scancode scancode_set1[512] = { - { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ - { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/ - { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/ - { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/ - { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/ - { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/ - { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/ - { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/ - { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/ - { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/ - { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/ - { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/ - { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/ - { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/ - { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/ - { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/ - { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/ - { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/ - { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/ - { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/ - { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/ - { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/ - { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/ - { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/ - { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/ - { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/ - { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/ - { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/ - { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/ - { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/ - { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/ - { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/ - - { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/ - { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/ - { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/ - { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/ - { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/ - { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/ - { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/ - { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/ - { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/ - { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/ - { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/ - { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/ - { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/ - { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/ - { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/ - { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/ - { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/ - { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/ - { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/ - { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/ - { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/ - { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/ - { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/ - { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/ - { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/ - { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/ - { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/ - { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/ - { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/ - { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/ - { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/ - { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/ - - { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/ - { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/ - { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/ - { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/ - { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/ - { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/ - { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/ - { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/ - { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/ - { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ - { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/ - { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/ - { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/ - { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/ - { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/ - { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/ - { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/ - { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/ - { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/ - { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/ - { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/ - { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/ - { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/ - { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/ - { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/ - { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/ - { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/ - { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/ - { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/ - { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/ - { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/ - - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ - { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/ - { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/ -}; -#endif - -static const scancode scancode_set2[512] = { - { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/ - { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/ - { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/ - { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/ - { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/ - { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/ - { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/ - { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/ - { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/ - { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/ - { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/ - { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/ - { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/ - { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/ - { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/ - { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/ - { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/ - { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/ - { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/ - { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/ - { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/ - { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/ - { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/ - { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/ - { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/ - { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/ - { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/ - { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/ - { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/ - { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/ - { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/ - { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/ - - { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ - { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ - { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ - { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ - { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ - { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ - { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ - { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ - { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ - { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ - { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ - { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ - { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ - { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ - { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ - { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ - { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ - { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ - { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ - { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ - { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ - { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ - { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ - { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ - { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ - { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ - { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ - { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ - { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ - { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ - { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ - { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - - { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ - { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ - { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ - { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ - { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ - { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ - { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ - { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ - { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ - { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ - { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ - { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ - { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/ - { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ - { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ - { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ - { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/ - { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/ - { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/ - { {0xe0,0x72,0},{0xe0,0xF0,0x72,0} }, { {0xe0,0x7A,0},{0xe0,0xF0,0x7A,0} }, { {0xe0,0x70,0},{0xe0,0xF0,0x70,0} }, { {0xe0,0x71,0},{0xe0,0xF0,0x71,0} }, /*150*/ - { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ - { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/ - { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/ - { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/ - { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ - { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ - { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ - { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ - { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ - { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ - { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ - { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ - { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ -}; - -static const scancode scancode_set3[512] = { - { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/ - { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/ - { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/ - { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/ - { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/ - { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/ - { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/ - { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/ - { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/ - { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/ - { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/ - { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/ - { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/ - { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/ - { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/ - { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/ - { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/ - { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/ - { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/ - { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/ - { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/ - { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/ - { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/ - { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/ - { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/ - { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/ - { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/ - { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/ - { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/ - { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/ - - { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ - { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ - { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ - { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ - { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ - { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ - { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ - { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ - { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ - { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ - { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ - { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ - { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ - { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ - { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ - { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ - { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ - { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ - { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ - { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ - { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ - { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ - { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ - { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ - { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ - { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ - { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ - { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ - { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ - { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ - { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - - { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ - { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ - { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ - { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ - { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ - { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ - { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ - { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ - { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ - { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ - { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ - { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ - { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/ - { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ - { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ - { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ - { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/ - { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/ - { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/ - { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/ - { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ - { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/ - { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/ - { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/ - { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ - { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ - { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ - { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ - { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ - { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ - { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ - { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ - { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ - { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ - { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ -}; - - -static void add_data_kbd(uint16_t val); - - -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) -int kbd_at_do_log = ENABLE_KBD_AT_LOG; - - -static void -kbd_log(atkbd_t *dev, const char *fmt, ...) -{ - va_list ap; - - if ((dev == NULL) || (dev->log == NULL)) - return; - - if (kbd_at_do_log) { - va_start(ap, fmt); - log_out(dev->log, fmt, ap); - va_end(ap); - } -} -#else -#define kbd_log(dev, fmt, ...) -#endif - - -/* TODO: Get rid of keyboard_mode entirely - keyboard.c just need to know which scan codes to - send break codes for and which to repeat. - The break code stuff, though, might also be doable on the AT keyboard side, if F0 F0 - is never sent. */ -static void -set_scancode_map(atkbd_t *dev) -{ - switch (keyboard_mode & 3) { -#ifdef USE_SET1 - case 1: - default: - keyboard_set_table(scancode_set1); - break; -#else - default: -#endif - case 2: - keyboard_set_table(scancode_set2); - break; - - case 3: - keyboard_set_table(scancode_set3); - break; - } - - if (keyboard_mode & 0x20) -#ifdef USE_SET1 - keyboard_set_table(scancode_set1); -#else - keyboard_set_table(scancode_set2); -#endif -} - - - -/* TODO: Move the queues to the device. */ -static void -kbc_queue_reset(uint8_t channel) -{ - if (channel == 2) { - mouse_queue_start = mouse_queue_end = 0; - memset(mouse_queue, 0x00, sizeof(mouse_queue)); - } else if (channel == 1) { - dev->queue_start = dev->queue_end = 0; - memset(dev->queue, 0x00, sizeof(dev->queue)); - } -} - - -static void -add_data_kbd_queue(atkbd_t *dev, uint8_t val) -{ - if (!keyboard_scan || (dev->queue_end >= 16)) { - kbd_log(dev, "Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (dev->queue_end >= 16)); - return; - } - - kbd_log(dev, "dev->queue[%02X] = %02X;\n", dev->queue_end, val); - dev->queue[dev->queue_end] = val; - dev->queue_end = (dev->queue_end + 1) & 0xf; -} - - -static void -kbd_send_to_host(atkbd_t *dev, uint8_t val) -{ - dev->kd.c_in = 1; - dev->kd.c_data = val; - - dev->last_byte = val; -} - - -static void -kbd_reset(atkbd_t *dev) -{ - kbc_queue_reset(1); - dev->kd.c_in = 0x00; - /* TODO: Move this to the keyboard struct. */ - dev->last_byte = 0x00; - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->phase = 0; - dev->in = 0; - - memset(keyboard_set3_flags, 0, 512); -} - - -static void -kbd_command(atkbd_t *dev) -{ - uint8_t val = dev->kd.d_data; - - if ((dev->phase > 0) && (dev->cmd == 0xff)) { - dev->phase++; - if (dev->phase == RESET_DELAY_TIME) { - kbd_send_to_host(dev, 0xaa); - dev->phase = 0; - dev->cmd = 0x00; - } - return; - } - - if (dev->phase == 2) { - dev->phase = 0; - - switch (dev->cmd) { - case 0xf2: - kbd_send_to_host(dev, 0x83); - break; - default: - log_fatal(dev->log, "Invalid command for phase 2: %02X\n", dev->cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->phase == 0) - dev->cmd = 0x00; - return; - } else if (dev->phase == 1) { - dev->phase = 0; - - switch (dev->cmd) { - case 0xf0: - kbd_log(dev, "Get scan code set: %02X\n", keyboard_mode & 3); - kbd_send_to_host(dev, keyboard_mode & 3); - break; - case 0xf2: - kbd_send_to_host(dev, 0xab); - dev->phase = 2; - break; - default: - log_fatal(dev->log, "Invalid command for phase 1: %02X\n", dev->cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->phase == 0) - dev->cmd = 0x00; - return; - } - - if (dev->in && (val < 0xed)) { - dev->in = 0; - dev->phase = 0; - - switch (dev->cmd) { - case 0xed: /* set/reset LEDs */ - kbd_log(dev, "Set LEDs: %02X\n", val); - kbd_send_to_host(dev, 0xfa); - break; - - case 0xf0: /* get/set scancode set */ - kbd_send_to_host(dev, 0xfa); - if (val == 0) - dev->phase = 1; - else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log(dev, "Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_send_to_host(dev, 0xfa); - break; - - default: - kbd_log(dev, "Bad keyboard 0060 write %02X command %02X\n", val, dev->cmd); - kbd_send_to_host(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - if (dev->phase == 0) - dev->cmd = 0x00; - } else { - /* No keyboard command in progress. */ - dev->in = 0; - dev->cmd = 0x00; - dev->phase = 0; - - switch (val) { - case 0x00: - kbd_log(dev, "Command 00\n"); - kbd_send_to_host(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log(dev, "Command 05 (NT 4.0)\n"); - kbd_send_to_host(dev, 0xfe); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log(dev, "Set/reset LEDs\n"); - kbd_send_to_host(dev, 0xfa); - - dev->in = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log(dev, "Diagnostic echo\n"); - kbd_send_to_host(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log(dev, "NOP (reserved for future use)\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log(dev, "Get/set scan code set\n"); - kbd_send_to_host(dev, 0xfa); - dev->in = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log(dev, "Read keyboard ID\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - kbd_send_to_host(dev, 0xfa); - dev->phase = 1; - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log(dev, "Set typematic rate/delay\n"); - kbd_send_to_host(dev, 0xfa); - dev->in = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log(dev, "Enable keyboard\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log(dev, "Set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log(dev, "val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", - val, keyboard_scan, dev->mem[0x20]); - kbd_send_to_host(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log(dev, "Set all keys to repeat\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log(dev, "Set all keys to give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log(dev, "Set all keys to give make codes only\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log(dev, "Set all keys to repeat and give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log(dev, "Reset last scan code\n"); - kbd_send_to_host(dev, dev->last_byte); - break; - - case 0xff: /* reset */ - kbd_log(dev, "Reset\n"); - kbd_reset(dev); - kbd_send_to_host(dev, 0xfa); - dev->phase = 1; - break; - - default: - kbd_log(dev, "Bad keyboard command %02X\n", val); - kbd_send_to_host(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if ((dev->in == 1) || (dev->phase > 0)) - dev->cmd = val; - } -} - - -static void -kbd_do_command(atkbd_t *dev) -{ - kbd_command(dev); - if (dev->kd.d_in) - dev->state = KBD_CMD_PROCESS; - else if ((dev->phase == 0) && !dev->in) { - dev->in_cmd = 0; - if (dev->kd.d_data != 0xf5) - keyboard_scan = 1; - dev->state = KBD_MAIN_LOOP; - } else { - keyboard_scan = 0; - dev->in_cmd = 1; - dev->state = KBD_CMD_PROCESS; - } -} - - -static void -kbd_nack(atkbd_t *dev) -{ - kbd_send_to_host(dev, 0xfe); - dev->state = KBD_MAIN_LOOP; -} - - -static void -kbd_main_loop(atkbd_t *dev) -{ - uint8_t scan = !dev->kd.inhibit && keyboard_scan; - - if (dev->kd.d_in) { - dev->kd.d_in = 0; - kbd_cmd_process(dev); - } else if (scan && (dev->queue_start != dev->queue_end)) { - /* Scan here. */ - kbd_log(dev, "Get %02X from FIFO\n", dev->queue[dev->queue_start]); - kbd_send_to_host(dev, dev->queue[dev->queue_start]); - dev->queue_start = (dev->queue_start + 1) & 0xf; - } -} - - -static void -kbd_cmd_process(atkbd_t *dev) -{ - uint8_t written = dev->kd.d_in; - - /* We want data, nothing has been written yet, return. */ - if (dev->in && !dev->kd.d_in) - return; - - dev->kd.d_in = 0; - - if (!written && !keyboard_scan && dev->in_cmd && (dev->phase > 0)) { - kbd_log(dev, "Keyboard not written, not scanning, in command, and phase > 0\n"); - kbd_do_command(dev); - } else if (dev->kd.d_data == 0xfe) { - kbd_log(dev, "Send last byte: %02X\n", dev->last_byte); - kbd_send_to_host(dev, dev->last_byte); - dev->state = KBD_MAIN_LOOP; - } else if (dev->kd.d_data == 0xee) { - kbd_log(dev, "Diagnostic echo: EE\n"); - kbd_send_to_host(dev, 0xee); - dev->state = KBD_MAIN_LOOP; - } else if (dev->kd.d_data >= 0xed) { - kbd_log(dev, "Command %02X\n", dev->kd.d_data); - if (!keyboard_scan && dev->in_cmd && (dev->cmd == 0xed)) { - kbd_log(dev, "Not scanning, in command, old command is ED\n"); - keyboard_scan = 1; - dev->in_cmd = 0; - } - kbd_do_command(dev); - } else { - if (!keyboard_scan && dev->in_cmd) { - if ((dev->cmd == 0xf3) && (dev->kd.d_data & 0x80)) { - kbd_log(dev, "Command F3 data %02X has bit 7 set\n", dev->kd.d_data); - kbd_nack(dev); - } else { - kbd_log(dev, "Command %02X data %02X\n", dev->cmd, dev->kd.d_data); - kbd_do_command(dev); - } - } else { - kbd_log(dev, "Scanning or not in command, NACK\n"); - kbd_nack(dev); - } - } -} - - -/* Keyboard processing */ -static void -kbd_process(atkbd_t *dev) -{ - /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ - if (dev->kd.c_in && dev->kd.d_in) - dev->kd.c_in = 0; - - /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ - if (!dev->kd.c_in) switch (dev->state) { - case KBD_MAIN_LOOP: - kbd_main_loop(dev); - break; - case KBD_CMD_PROCESS: - kbd_cmd_process(dev); - break; - } -} - - -static void -add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) -{ - int i; - - for (i = 0; i < len; i++) - add_data_kbd_queue(dev, val[i]); -} - - -static void -add_data_kbd(uint16_t val) -{ - atkbd_t *dev = SavedKbd; - uint8_t fake_shift[4]; - uint8_t num_lock = 0, shift_states = 0; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if (dev->in || (dev->phase > 0)) - return; - - keyboard_get_states(NULL, &num_lock, NULL); - shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && - (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) - t3100e_notify_set((val + 2) & 0x0f); - - switch(val) { - case FAKE_LSHIFT_ON: - kbd_log(dev, "Fake left shift on, scan code: "); - if (num_lock) { - if (shift_states) { - kbd_log(dev, "N/A (one or both shifts on)\n"); - break; - } else { - /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - add_data_vals(dev, fake_shift, 2); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - } else { - if (shift_states & STATE_LSHIFT) { - /* Num lock off and left shift pressed. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - add_data_vals(dev, fake_shift, 3); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - if (shift_states & STATE_RSHIFT) { - /* Num lock off and right shift pressed. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; - add_data_vals(dev, fake_shift, 3); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - kbd_log(dev, shift_states ? "" : "N/A (both shifts off)\n"); - } - break; - - case FAKE_LSHIFT_OFF: - kbd_log(dev, "Fake left shift off, scan code: "); - if (num_lock) { - if (shift_states) { - kbd_log(dev, "N/A (one or both shifts on)\n"); - break; - } else { - /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - add_data_vals(dev, fake_shift, 3); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - } else { - if (shift_states & STATE_LSHIFT) { - /* Num lock off and left shift pressed. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - add_data_vals(dev, fake_shift, 2); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - if (shift_states & STATE_RSHIFT) { - /* Num lock off and right shift pressed. */ - switch(keyboard_mode & 0x02) { - case 1: - fake_shift[0] = 0xe0; fake_shift[1] = 0x36; - add_data_vals(dev, fake_shift, 2); - break; - - case 2: - fake_shift[0] = 0xe0; fake_shift[1] = 0x59; - add_data_vals(dev, fake_shift, 2); - break; - - default: - kbd_log(dev, "N/A (scan code set %i)\n", keyboard_mode & 0x02); - break; - } - } - kbd_log(dev, shift_states ? "" : "N/A (both shifts off)\n"); - } - break; - - default: - add_data_kbd_queue(dev, val); - break; - } -} - - -static void -kbd_close(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - kbd_reset(dev); - - keyboard_scan = 0; - keyboard_send = NULL; - - /* Disable the scancode maps. */ - keyboard_set_table(NULL); - -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) - log_close(dev->log); -#endif - - kbc_dev_attach(NULL, 1); - - SavedKbd = NULL; - free(dev); -} - - -static void * -kbd_init(const device_t *info) -{ - atkbd_t *dev; - - dev = (atkbd_t *)malloc(sizeof(atkbd_t)); - memset(dev, 0x00, sizeof(atkbd_t)); - - kbc_dev_attach(&(dev->kd), 1); - - kbd_send_to_host(dev, 0xaa); - - keyboard_send = add_data_kbd; - -#if (!defined(RELEASE_BUILD) && defined(ENABLE_KBD_AT_LOG)) - dev->kbd_log = log_open("AT KBD"); -#endif - - kbd_reset(dev); - - /* We need this, sadly. */ - SavedKbd = dev; - - return(dev); -} - - -const device_t keyboard_at_kbd_device = { - "PC/AT Keyboard (Actual keyboard!)", - 0, - 0, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 6a3d9c370..81455f5a6 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,7 +57,9 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define RESET_DELAY_TIME 1000 /* 100 ms */ +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + +#define RESET_DELAY_TIME (100 * 10) /* 600ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -72,136 +74,50 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ -/* This only differs in that translation is forced off. */ -#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x07 +#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ +#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x03 -#define KBC_FLAG_PS2 0x04 - -/* We need to redefine this: - Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 - for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling - controller mode, normally set according to the flags, but togglable on - AMIKey: - 0000 0000 0x00 IBM, AT - 0000 0001 0x01 MR - 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 - 0001 0000 0x10 Olivetti - 0010 0000 0x20 Toshiba - 0011 0000 0x30 Quadtel - 0100 0000 0x40 Phoenix MultiKey/42 - 0101 0000 0x50 AMI KF - 0101 0001 0x51 AMI KH - 0101 0010 0x52 AMIKey - 0101 0011 0x53 AMIKey-2 - 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) - 0110 0000 0x60 Award - 0110 0001 0x61 Award 286 (has some AMI commands apparently) - 0111 0000 0x70 Siemens -*/ - -/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -/* All commands are standard PS/2 */ +#define KBC_VEN_AMI 0x04 #define KBC_VEN_IBM_MCA 0x08 -/* Standard IBM commands, differs in input port bits */ -#define KBC_VEN_IBM_PS1 0x10 -/* Olivetti - proprietary commands and port 62h with switches - readout */ -#define KBC_VEN_OLIVETTI 0x20 -/* Toshiba T3100e - has a bunch of proprietary commands, also sets - IFULL on command AA */ -#define KBC_VEN_TOSHIBA 0x28 -/* Standard IBM commands, uses input port as a switches readout */ -#define KBC_VEN_NCR 0x30 -/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the - polarity of the video type bit in the input port is inverted */ -#define KBC_VEN_XI8088 0x38 -/* QuadtelKey - currently guesswork */ -#define KBC_VEN_QUADTEL 0x40 -/* Phoenix MultiKey/42 - not yet implemented */ -#define KBC_VEN_PHOENIX 0x48 -/* Generic commands, XI8088-like input port handling of video type, - maybe we just need a flag for that? */ -#define KBC_VEN_ACER 0x50 -/* AMI KF/KH/AMIKey/AMIKey-2 */ -#define KBC_VEN_AMI 0xf0 -/* Standard AMI commands, differs in input port bits */ -#define KBC_VEN_INTEL_AMI 0xf8 -#define KBC_VEN_MASK 0xf8 - - -/* Flags should be fully 32-bit: - Bits 7- 0: Vendor and revision/variant; - Bits 15- 8: Input port mask; - Bits 23-16: Input port bits that are always on; - Bits 31-24: Flags: - Bit 0: Invert P1 video type bit polarity; - Bit 1: Is PS/2; - Bit 2: Translation forced always off. - - So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ +#define KBC_VEN_QUADTEL 0x0c +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_XI8088 0x14 +#define KBC_VEN_IBM_PS1 0x18 +#define KBC_VEN_ACER 0x1c +#define KBC_VEN_INTEL_AMI 0x20 +#define KBC_VEN_OLIVETTI 0x24 +#define KBC_VEN_NCR 0x28 +#define KBC_VEN_SAMSUNG 0x2c +#define KBC_VEN_MASK 0x3c typedef struct { - uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, - secr_phase, mem_index, ami_stat, ami_mode, - kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, - kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, - kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, - mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, - kbc_written[3], kbc_data[3]; + uint8_t command, status, old_status, out, old_out, secr_phase, + mem_addr, input_port, output_port, old_output_port, + key_command, output_locked, ami_stat, want60, + wantirq, key_wantdata, refresh, first_write, + ami_flags, pad[7]; - uint8_t mem_int[0x40], mem[0x240]; + uint8_t mem[0x100]; - uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; + int last_irq, old_last_irq, + reset_delay, + out_new, out_delayed; uint32_t flags; - pc_timer_t pulse_cb, send_delay_timer; + pc_timer_t refresh_time, pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); + + pc_timer_t send_delay_timer; } atkbd_t; -enum -{ - CHANNEL_KBC = 0, - CHANNEL_KBD, - CHANNEL_MOUSE -}; - -enum -{ - KBD_MAIN_LOOP = 0, - KBD_CMD_PROCESS -}; - -enum -{ - MOUSE_MAIN_LOOP_1 = 0, - MOUSE_CMD_PROCESS, - MOUSE_CMD_END, - MOUSE_MAIN_LOOP_2 -}; - -enum { - KBC_MAIN_LOOP = 0, - KBC_RESET = 1, - KBC_WAIT = 4, - KBC_WAIT_FOR_KBD, - KBC_WAIT_FOR_MOUSE, - KBC_WAIT_FOR_BOTH -}; - - -static void kbd_cmd_process(atkbd_t *dev); - -static void kbc_wait(atkbd_t *dev, uint8_t flags); - - /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -210,9 +126,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; -uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; - +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -653,27 +569,9 @@ static const scancode scancode_set3[512] = { }; -#define UISTR_LEN 256 -static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); -extern void ui_sb_bugui(char *__str); - - -static void -kbd_status(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsprintf(kbd_str, fmt, ap); - ui_sb_bugui(kbd_str); - va_end(ap); -} - - -// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -734,6 +632,9 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); + } else { + key_ctrl_queue_start = key_ctrl_queue_end = 0; + memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -741,6 +642,15 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + dev->status = (dev->status & 0x0f) | stat_hi; + if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -749,1054 +659,83 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else - fatal("Adding %02X to invalid channel %02X\n", val, channel); + } else { + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + } +} + + +static void +add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + kbd_log("ATkbc: Adding %02X to front...\n", val); + dev->wantirq = 0; + if (channel == 2) { + if (dev->mem[0] & 0x02) + picint(0x1000); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + dev->last_irq = 2; + } + dev->out = val; + if (channel == 2) + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; + else + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); return; } - - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } -static void -kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) -{ - dev->kbc_written[channel] = 1; - dev->kbc_data[channel] = val; -} - static void -kbd_send_to_host(atkbd_t *dev, uint8_t val) +add_data_kbd_direct(atkbd_t *dev, uint8_t val) { - kbc_send(dev, val, CHANNEL_KBD); -} + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); + uint8_t send; - -static void -kbd_chip_reset(atkbd_t *dev) -{ - kbc_queue_reset(1); - dev->kbc_written[1] = 0x00; - kbd_last_scan_code = 0x00; - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->kbd_phase = 0; - dev->kbd_in = 0; -} - - -static void -kbd_command(atkbd_t *dev) -{ - uint8_t val = dev->kbd_data; - - if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { - dev->kbd_phase++; - if (dev->kbd_phase == RESET_DELAY_TIME) { - kbd_send_to_host(dev, 0xaa); - dev->kbd_phase = 0; - dev->kbd_cmd = 0x00; - } - return; - } - - if (dev->kbd_phase == 2) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf2: - kbd_send_to_host(dev, 0x83); - break; - default: - fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } else if (dev->kbd_phase == 1) { - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xf0: - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - kbd_send_to_host(dev, keyboard_mode & 3); - break; - case 0xf2: - kbd_send_to_host(dev, 0xab); - dev->kbd_phase = 2; - break; - default: - fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - return; - } - - if (dev->kbd_in && (val < 0xed)) { - dev->kbd_in = 0; - dev->kbd_phase = 0; - - switch (dev->kbd_cmd) { - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set LEDs [%02x]\n", val); - kbd_send_to_host(dev, 0xfa); - break; - - case 0xf0: /* get/set scancode set */ - kbd_send_to_host(dev, 0xfa); - if (val == 0) - dev->kbd_phase = 1; - else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_send_to_host(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); - kbd_send_to_host(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - if (dev->kbd_phase == 0) - dev->kbd_cmd = 0x00; - } else { - /* No keyboard command in progress. */ - dev->kbd_in = 0; - dev->kbd_cmd = 0x00; - dev->kbd_phase = 0; - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - kbd_send_to_host(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - kbd_send_to_host(dev, 0xfe); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - kbd_send_to_host(dev, 0xfa); - - dev->kbd_in = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - kbd_send_to_host(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - kbd_send_to_host(dev, 0xfa); - dev->kbd_in = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", - val, keyboard_scan, dev->mem[0x20]); - kbd_send_to_host(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - kbd_send_to_host(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - kbd_send_to_host(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbd_chip_reset(dev); - kbd_send_to_host(dev, 0xfa); - dev->kbd_phase = 1; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - kbd_send_to_host(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) - dev->kbd_cmd = val; - } -} - - -static void -kbd_do_command(atkbd_t *dev) -{ - kbd_command(dev); - if (dev->kbd_written) - dev->kbd_poll_phase = KBD_CMD_PROCESS; - else if ((dev->kbd_phase == 0) && !dev->kbd_in) { - dev->kbd_in_cmd = 0; - if (dev->kbd_data != 0xf5) - keyboard_scan = 1; - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else { - keyboard_scan = 0; - dev->kbd_in_cmd = 1; - dev->kbd_poll_phase = KBD_CMD_PROCESS; - } -} - - -static void -kbd_nack(atkbd_t *dev) -{ - kbd_send_to_host(dev, 0xfe); - dev->kbd_poll_phase = KBD_MAIN_LOOP; -} - - -static void -kbd_main_loop(atkbd_t *dev) -{ - uint8_t scan = !dev->kbd_inhibit && keyboard_scan; - - if (dev->kbd_written) { - dev->kbd_written = 0; - kbd_cmd_process(dev); - } else if (scan && (key_queue_start != key_queue_end)) { - /* Scan here. */ - kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); - kbd_send_to_host(dev, key_queue[key_queue_start]); - key_queue_start = (key_queue_start + 1) & 0xf; - } -} - - -static void -kbd_cmd_process(atkbd_t *dev) -{ - uint8_t written = dev->kbd_written; - - /* We want data, nothing has been written yet, return. */ - if (dev->kbd_in && !dev->kbd_written) + if (dev->reset_delay) return; - dev->kbd_written = 0; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { - kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); - kbd_do_command(dev); - } else if (dev->kbd_data == 0xfe) { - kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); - kbd_send_to_host(dev, kbd_last_scan_code); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data == 0xee) { - kbd_log("ATkbd: Echo EE\n"); - kbd_send_to_host(dev, 0xee); - dev->kbd_poll_phase = KBD_MAIN_LOOP; - } else if (dev->kbd_data >= 0xed) { - kbd_log("ATkbd: Command %02X\n", dev->kbd_data); - if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { - kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); - keyboard_scan = 1; - dev->kbd_in_cmd = 0; - } - kbd_do_command(dev); - } else { - if (!keyboard_scan && dev->kbd_in_cmd) { - if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { - kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); - kbd_nack(dev); - } else { - kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); - kbd_do_command(dev); - } - } else { - kbd_log("ATkbd: Scanning or not in command, NACK\n"); - kbd_nack(dev); - } - } -} + if (translate) + send = nont_to_t[val]; + else + send = val; - -/* Keyboard processing */ -static void -kbd_process(atkbd_t *dev) -{ - /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ - if (dev->kbc_written[1] && dev->kbd_written) - dev->kbc_written[1] = 0; - - /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ - if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { - case KBD_MAIN_LOOP: - kbd_main_loop(dev); - break; - case KBD_CMD_PROCESS: - kbd_cmd_process(dev); - break; - } + add_data_kbd_queue(dev, 1, send); } static void -kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +add_data_kbd_raw(atkbd_t *dev, uint8_t val) { - uint8_t ch = (channel > 0) ? channel : 1; - uint8_t do_irq = (dev->mem[0x20] & ch); - int translate = (channel == 1) && (keyboard_mode & 0x60); - - if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) - return; - - stat_hi |= dev->inhibit; - - if (!dev->kbc_send_pending) { - dev->kbc_send_pending = 1; - dev->kbc_to_send = val; - dev->kbc_channel = channel; - dev->kbc_stat_hi = stat_hi; - return; - } - - if (translate) { - /* Allow for scan code translation. */ - if (val == 0xf0) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if ((sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - } - - dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; - if (do_irq) { - kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); - picint(dev->last_irq); - } - kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); - dev->ob = translate ? (nont_to_t[val] | sc_or) : val; - - dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); - if (ch == 2) - dev->status |= STAT_MFULL; - - if (translate && (sc_or == 0x80)) - sc_or = 0; -} - - -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - uint8_t old = dev->p2; - - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); - - if (!(dev->flags & KBC_FLAG_PS2)) - val |= ((dev->mem[0x20] << 4) & 0x10); - - dev->kbd_inhibit = (val & 0x40); - dev->mouse_inhibit = (val & 0x08); - - /* IRQ 12 */ - if ((old ^ val) & 0x20) { - if (val & 0x20) { - kbd_log("ATkbc: write_output(): IRQ 12\n"); - picint(1 << 12); - } else - picintc(1 << 12); - } - - /* IRQ 1 */ - if ((old ^ val) & 0x10) { - if (val & 0x10) { - kbd_log("ATkbc: write_output(): IRQ 1\n"); - picint(1 << 1); - } else - picintc(1 << 1); - } - - /* A20 enable change */ - if ((old ^ val) & 0x02) { - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - - /* Do this here to avoid an infinite reset loop. */ - dev->p2 = val; - - /* 0 holds the CPU in the RESET state, 1 releases it. To simplify this, - we just do everything on release. */ - if ((val & 0x01) && !(old & 0x01)) { - if (val & 0x01) { - /* Pin 0 selected. */ - pclog("write_output(): Pulse reset!\n"); - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - } - } -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) - val &= ~CCB_TRANSLATE; - - dev->mem[0x20] = val; - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { - keyboard_mode &= ~CCB_PCMODE; - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - if (!(dev->flags & KBC_FLAG_PS2)) { - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->p2); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_p2 = dev->p2 & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xef; - dev->mem[0x20] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0x20] &= 0xdf; - dev->mem[0x20] |= (enable ? 0x00 : 0x20); -} - - -static void -kbc_transmit(atkbd_t *dev, uint8_t val) -{ - kbc_send_to_ob(dev, val, 0, 0x00); -} - - -static void -kbc_command(atkbd_t *dev) -{ - uint8_t mask, val = dev->ib; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - int bad = 1; - - if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { - if (dev-> kbc_phase < 16) - kbc_transmit(dev, dev->mem[dev->kbc_phase]); - else if (dev-> kbc_phase == 16) - kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); - else if (dev-> kbc_phase == 17) - kbc_transmit(dev, dev->p2); - else if (dev-> kbc_phase == 18) - kbc_transmit(dev, dev->status); - - dev->kbc_phase++; - if (dev->kbc_phase == 19) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } - return; - } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { - val = ami_copr[dev->kbc_phase]; - kbc_transmit(dev, val); - if (val == 0x00) { - dev->kbc_phase = 0; - dev->kbc_cmd = 0x00; - } else - dev->kbc_phase++; - return; - } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { - /* load security */ - kbd_log("ATkbc: load security\n"); - dev->mem[0x50 + dev->kbc_in - 0x01] = val; - if ((dev->kbc_in == 0x80) && (val != 0x00)) { - /* Security string too long, set it to 0x00. */ - dev->mem[0x50] = 0x00; - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else if (val == 0x00) { - /* Security string finished. */ - dev->kbc_in = 0; - dev->kbc_cmd = 0; - } else /* Increase pointer and request another byte. */ - dev->kbc_in++; - return; - } - - /* If the written port is 64, go straight to the beginning of the command. */ - if (!(dev->status & STAT_CD) && dev->kbc_in) { - /* Write data to controller. */ - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (dev->kbc_cmd) { - case 0x60 ... 0x7f: - if (dev->kbc_cmd == 0x60) - write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; - break; - - case 0xc7: /* or input port with system data */ - dev->p1 |= val; - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("New AMIKey mode: %02X\n", val); - dev->ami_mode = val; - dev->flags &= ~KBC_FLAG_PS2; - if (val & 1) - dev->flags |= KBC_FLAG_PS2; - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->p2_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->p2 & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - // kbc_send_to_ob(dev, val, 1, 0x00); - /* Should be channel 1, but we send to 0 to avoid translation, - since bytes output using this command do *NOT* get translated. */ - kbc_send_to_ob(dev, val, 0, 0x00); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - kbc_send_to_ob(dev, val, 2, 0x00); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (dev->flags & KBC_FLAG_PS2) { - set_enable_mouse(dev, 1); - dev->mem[0x20] &= ~0x20; - if (mouse_write && !dev->kbc_written[2]) { - kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); - dev->mouse_data = val; - dev->mouse_written = 1; - dev->kbc_wait_for_response = 2; - } else - kbc_send_to_ob(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - -#ifdef ENABLE_KEYBOARD_AT_LOG - if (bad) - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); -#endif - } - } else { - /* Controller command. */ - kbd_log("ATkbc: Controller command: %02X\n", val); - dev->kbc_in = 0; - dev->kbc_phase = 0; - - switch (val) { - /* Read data from KBC memory. */ - case 0x20 ... 0x3f: - kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); - break; - - /* Write data to KBC memory. */ - case 0x60 ... 0x7f: - dev->kbc_in = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->kbd_in_cmd = dev->mouse_in_cmd = 0; - dev->status &= ~STAT_OFULL; - dev->last_irq = 0; - dev->kbc_phase = 0; - - /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ - if (dev->flags & KBC_FLAG_PS2) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - kbc_transmit(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - /* No error. */ - kbc_transmit(dev, 0x00); - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - kbc_transmit(dev, dev->mem[0x20]); - dev->kbc_phase = 1; - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xc7: /* or input port with system data */ - kbd_log("ATkbc: Phoenix - or input port with system data\n"); - dev->kbc_in = 1; - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - kbc_transmit(dev, dev->ami_mode); - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->kbc_in = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (!(dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x10)) - mask &= 0xbf; - kbc_transmit(dev, dev->p2 & mask); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->kbc_in = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - if (dev->flags & KBC_FLAG_PS2) - dev->kbc_in = 1; - else - kbc_transmit(dev, 0x00); /* NCR */ - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - kbc_transmit(dev, 0x00); - break; - - case 0xe1: case 0xea: - kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); - write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); - } - - /* If the command needs data, remember the command. */ - if (dev->kbc_in || (dev->kbc_phase > 0)) - dev->kbc_cmd = val; - } -} - - -static void -kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) -{ - dev->kbc_written[channel] = 0; - kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); - kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); -} - - -static void -kbc_main_loop_scan(atkbd_t *dev) -{ - uint8_t port_dis = dev->mem[0x20] & 0x30; - uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); - - if (!ps2) - port_dis |= 0x20; - - if (!(dev->status & STAT_OFULL)) { - if (port_dis & 0x20) { - if (!(port_dis & 0x10)) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); - /* Enable communication with keyboard. */ - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 1); - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX DIS, KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); - } -#endif - } else { - /* Enable communication with mouse. */ - dev->p2 &= 0xf7; - dev->mouse_inhibit = 0; - if (dev->mem[0x20] & 0x10) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD DIS\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); - kbc_wait(dev, 2); - } else { - /* Enable communication with keyboard. */ - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: AUX EN , KBD EN\n"); - // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); - dev->p2 &= 0xbf; - dev->kbd_inhibit = 0; - kbc_wait(dev, 3); - } - } - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); - } -#endif -} - - -static void -kbc_process_ib(atkbd_t *dev) -{ - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - } else { - dev->mem[0x20] &= ~0x10; - dev->kbd_data = dev->ib; - dev->kbd_written = 1; - dev->kbc_wait_for_response = 1; - } - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - if (!dev->kbc_wait_for_response) - kbc_main_loop_scan(dev); -} - - -static void -kbc_wait(atkbd_t *dev, uint8_t flags) -{ - if ((flags & 1) && dev->kbc_written[1]) { - /* Disable communication with mouse. */ - dev->p2 |= 0x08; - dev->mouse_inhibit = 1; - /* Send keyboard byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_KBD); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if ((flags & 2) && dev->kbc_written[2]) { - /* Disable communication with keyboard. */ - dev->p2 |= 0x40; - dev->kbd_inhibit = 1; - /* Send mouse byte to host. */ - kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } else if (dev->status & STAT_IFULL) { - /* Disable communication with keyboard and mouse. */ - dev->p2 |= 0x48; - dev->kbd_inhibit = dev->mouse_inhibit = 1; - kbc_process_ib(dev); - } else - dev->kbc_poll_phase = KBC_WAIT | flags; -} - - -/* Controller processing */ -static void -kbc_process(atkbd_t *dev) -{ - // kbd_log("ATkbc: kbc_process()\n"); - - /* If we're waiting for the response from the keyboard or mouse, do nothing - until the device has repsonded back. */ - if (dev->kbc_wait_for_response > 0) { - if (dev->kbc_written[dev->kbc_wait_for_response]) - dev->kbc_wait_for_response = 0; - else - return; - } - - if (dev->kbc_send_pending) { - kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", - dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); - dev->kbc_send_pending = 0; - } - - if (dev->kbc_poll_phase == KBC_RESET) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Reset loop()\n"); - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->kbc_in_cmd = 1; - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - - dev->kbc_poll_phase = KBC_MAIN_LOOP; - } - } - - return; - } - - if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: In a command\n"); - if (!dev->kbc_in && (dev->status & STAT_OFULL)) { - kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); - return; /* We do not want input and we're waiting for the host to read the data - we transmitted, but it has not done that yet, do nothing. */ - } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { - kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); - return; /* We want input and the host has not provided us with any yet, do nothing. */ - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbc: Normal condition\n"); -#endif - - if (dev->status & STAT_IFULL) { - dev->status &= ~STAT_IFULL; - - if (dev->status & STAT_CD) { - kbd_log("ATkbc: Resetting command\n"); - dev->kbc_phase = 0; - dev->kbc_in = 0; - } - } - - /* Process command. */ - kbc_command(dev); - - if ((dev->kbc_phase == 0) && !dev->kbc_in) - dev->kbc_in_cmd = 0; - else - return; - - if (!(dev->status & STAT_OFULL)) - kbc_main_loop_scan(dev); - /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ - } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { - case KBC_MAIN_LOOP: - // kbd_log("ATkbc: Main loop\n"); - if (dev->status & STAT_IFULL) { - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Main loop\n" - "ATkbc: IBF full, process\n"); - kbc_process_ib(dev); - } else - kbc_main_loop_scan(dev); - break; - case KBC_WAIT_FOR_KBD: - case KBC_WAIT_FOR_MOUSE: - case KBC_WAIT_FOR_BOTH: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); - kbc_wait(dev, dev->kbc_poll_phase & 3); - break; - default: - kbd_log("ATkbc: kbc_process()\n" - "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); - break; - } + add_data_kbd_queue(dev, 1, val); } @@ -1804,29 +743,105 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; +#ifdef ENABLE_KEYBOARD_AT_LOG + const uint8_t channels[4] = { 1, 2, 0, 0 }; +#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - /* We process all three devices at the same time, in an arbitrary order. */ + if (dev->out_new != -1 && !dev->last_irq) { + dev->wantirq = 0; + if (dev->out_new & 0x100) { + if (dev->mem[0] & 0x02) + picint(0x1000); + kbd_log("ATkbc: %02X coming from channel 2\n"); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; + dev->last_irq = 2; + } + } - /* Keyboard processing */ - kbd_process(dev); + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); + dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { + kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); + dev->out_new = mouse_queue[mouse_queue_start] | 0x100; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { + kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); + dev->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } - /* TODO: Mouse processing */ - // mouse_process(dev); + if (dev->reset_delay) { + dev->reset_delay--; + if (!dev->reset_delay) { + kbd_log("ATkbc: Sending AA on keyboard reset...\n"); + add_data_kbd_direct(dev, 0xaa); + } + } +} - /* Controller processing */ - kbc_process(dev); + +static void +add_data(atkbd_t *dev, uint8_t val) +{ + kbd_log("ATkbc: add to queue\n"); + + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + kbc_queue_add(dev, val, 0, 0x00); + + if (!(dev->out_new & 0x300)) { + dev->out_delayed = dev->out_new; + dev->out_new = -1; + } } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); int i; + uint8_t or = 0; + uint8_t send; - for (i = 0; i < len; i++) - add_data_kbd_queue(dev, 0, val[i]); + if (dev->reset_delay) + return; + + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + + add_data_kbd_queue(dev, 0, send); + } } @@ -1834,21 +849,56 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->kbd_in || (dev->kbd_phase > 0)) + if (dev->reset_delay) return; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && - (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) - t3100e_notify_set((val + 2) & 0x0f); + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && + (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0a); break; /* Up */ + case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ + } + + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1981,7 +1031,18 @@ add_data_kbd(uint16_t val) break; default: - add_data_kbd_queue(dev, 0, val); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); + if (translate) { + kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbd_log("F0 "); + kbd_log("%02X)\n", val); + } else + kbd_log("%02X\n", val); +#endif + + add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); break; } @@ -1990,13 +1051,124 @@ add_data_kbd(uint16_t val) } +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) + val |= ((dev->mem[0] << 4) & 0x10); + + if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->output_port = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); + + if ((val & 1) && (dev->status & STAT_OFULL)) + dev->wantirq = 1; + if (!(val & 1) && dev->wantirq) + dev->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + dev->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || + ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { + keyboard_mode &= ~CCB_PCMODE; + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->output_port); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_output_port = dev->output_port & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); + write_output(dev, dev->output_port & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); - write_output(dev, dev->p2 | dev->old_p2); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); + write_output(dev, dev->output_port | dev->old_output_port); +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xef; + dev->mem[0] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0] &= 0xdf; + dev->mem[0] |= (enable ? 0x00 : 0x20); } @@ -2005,72 +1177,49 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + switch (val) { case 0xa4: /* check if password installed */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: check if password installed\n"); - kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); - return 0; - } - break; - - case 0xa5: /* load security */ - if (dev->flags & KBC_FLAG_PS2) { - kbd_log("ATkbc: load security\n"); - dev->kbc_in = 1; + add_data(dev, 0xf1); return 0; } break; case 0xa7: /* disable mouse port */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: disable mouse port\n"); - // kbc_transmit(dev, 0); + set_enable_mouse(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: enable mouse port\n"); - // kbc_transmit(dev, 1); + set_enable_mouse(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if (dev->flags & KBC_FLAG_PS2) { - /* No error, this is testing the channel 2 interface. */ - kbc_transmit(dev, 0x00); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - kbc_transmit(dev, 0x00); + add_data(dev, 0x00); return 0; case 0xc0: /* read input port */ - /* IBM PS/1: - Bit 2 and 4 ignored (we return always 0), - Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". - Intel AMI: - Bit 2 ignored (we return always 1), - Bit 4 must be 1, - Bit 6 must be 1 or else error in SMM. - Acer: - Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), - Bit 4 must be 0, - Bit 6 ignored. - Packard Bell PB450: - Bit 2 must be 1. - P6RP4: - Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -2078,8 +1227,11 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc) | + (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -2091,34 +1243,39 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } else { - pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); - kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); - // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); else - kbc_transmit(dev, dev->p1 | fixed_bits); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if (dev->flags & KBC_FLAG_PS2) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -2133,170 +1290,38 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; - switch(dev->kbc_cmd) { - /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - if (dev->kbc_cmd == 0x40) + switch(dev->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) write_cmd(dev, val); - else - dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); - if (dev->secr_phase == 0) { - dev->mem_index = val; - dev->kbc_in = 1; - dev->secr_phase++; - } else if (dev->secr_phase == 1) { - if (dev->mem_index == 0x20) - write_cmd(dev, val); - else - dev->mem[dev->mem_index] = val; + kbd_log("ATkbc: AMI - set extended controller RAM\n"); + if (dev->secr_phase == 1) { + dev->mem_addr = val; + dev->want60 = 1; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; dev->secr_phase = 0; } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); - dev->mem_index = val; - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - dev->mem[index + dev->mem_index] = val; - } else if (dev->mem_index == 0x60) - write_cmd(dev, val); - else if (dev->mem_index == 0x42) - dev->status = val; - else if (dev->mem_index >= 0x40) - dev->mem[dev->mem_index - 0x40] = val; - else - dev->mem_int[dev->mem_index] = val; - return 0; - - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - dev->status = val; - break; - case 0x01: /* Password_ptr */ - dev->mem[0x1c] = val; - break; - case 0x02: /* Wakeup_Tsk_Reg */ - dev->mem[0x1e] = val; - break; - case 0x03: /* CCB */ - write_cmd(dev, val); - break; - case 0x04: /* Debounce_time */ - dev->mem[0x4d] = val; - break; - case 0x05: /* Pulse_Width */ - dev->mem[0x4e] = val; - break; - case 0x06: /* Pk_sel_byte */ - dev->mem[0x4c] = val; - break; - case 0x07: /* Func_Tsk_Reg */ - dev->mem[0x7e] = val; - break; - case 0x08: /* TypematicRate */ - dev->mem[0x80] = val; - break; - case 0x09: /* Led_Flag_Byte */ - dev->mem[0x81] = val; - break; - case 0x0a: /* Kbms_Command_St */ - dev->mem[0x87] = val; - break; - case 0x0b: /* Delay_Count_Byte */ - dev->mem[0x86] = val; - break; - case 0x0c: /* KBC_Flags */ - dev->mem[0x9b] = val; - break; - case 0x0d: /* SCODE_HK1 */ - dev->mem[0x50] = val; - break; - case 0x0e: /* SCODE_HK2 */ - dev->mem[0x51] = val; - break; - case 0x0f: /* SCODE_HK3 */ - dev->mem[0x52] = val; - break; - case 0x10: /* SCODE_HK4 */ - dev->mem[0x53] = val; - break; - case 0x11: /* SCODE_HK5 */ - dev->mem[0x54] = val; - break; - case 0x12: /* SCODE_HK6 */ - dev->mem[0x55] = val; - break; - case 0x13: /* TASK_HK1 */ - dev->mem[0x56] = val; - break; - case 0x14: /* TASK_HK2 */ - dev->mem[0x57] = val; - break; - case 0x15: /* TASK_HK3 */ - dev->mem[0x58] = val; - break; - case 0x16: /* TASK_HK4 */ - dev->mem[0x59] = val; - break; - case 0x17: /* TASK_HK5 */ - dev->mem[0x5a] = val; - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - dev->mem[0x5b] = val; - break; - case 0x19: /* Batt_Alarm_Reg1 */ - dev->mem[0x5c] = val; - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - dev->mem[0x5d] = val; - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - dev->mem[0x5e] = val; - break; - case 0x1c: /* Kbc_State1 */ - dev->mem[0x9d] = val; - break; - case 0x1d: /* Aux_Config */ - dev->mem[0x75] = val; - break; - case 0x1e: /* Kbc_State3 */ - dev->mem[0x73] = val; - break; - } - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); - dev->p1 = val; - return 0; - case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->ami_flags = val; return 0; } @@ -2308,50 +1333,62 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - uint16_t index = 0x00c0; switch (val) { - case 0x00 ... 0x1f: + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - kbc_transmit(dev, dev->mem[val + 0x20]); + add_data(dev, dev->mem[val]); return 0; - case 0x40 ... 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); - dev->kbc_in = 1; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; return 0; case 0xa0: /* copyright message */ - kbc_transmit(dev, ami_copr[0]); - dev->kbc_phase = 1; - return 0; + add_data(dev, 0x28); + add_data(dev, 0x00); + break; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - kbc_transmit(dev, 'H'); - // kbc_transmit(dev, 'Z'); + add_data(dev, 'H'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->p2 & 0xf3); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port & 0xf3); + add_data(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->p2 | 0x0c); - kbc_transmit(dev, 0x00); + write_output(dev, dev->output_port | 0x0c); + add_data(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -2359,7 +1396,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -2367,15 +1404,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read clock\n"); - kbc_transmit(dev, !!(dev->ami_stat & 1)); + add_data(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -2383,7 +1420,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -2391,237 +1428,68 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if (!(dev->flags & KBC_FLAG_PS2)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: AMI - read cache\n"); - kbc_transmit(dev, !!(dev->ami_stat & 2)); + add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->kbc_in = 1; + dev->want60 = 1; + dev->secr_phase = 1; return 0; - case 0xb0 ... 0xb3: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { - dev->p1 &= ~(1 << (val & 0x03)); - } - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb1)) + dev->input_port &= ~(1 << (val & 0x03)); + add_data(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 & ~(4 << (val & 0x01))); - kbc_transmit(dev, 0x00); + if (! PCI) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_data(dev, 0x00); return 0; -#if 0 - case 0xb8 ... 0xbb: -#else - case 0xb9: -#endif + case 0xb8: case 0xb9: case 0xba: case 0xbb: /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { - dev->p1 |= (1 << (val & 0x03)); - kbc_transmit(dev, 0x00); + if (!PCI || (val > 0xb9)) { + dev->input_port |= (1 << (val & 0x03)); + add_data(dev, 0x00); } return 0; - case 0xb8: - kbd_log("ATkbc: AMI MegaKey - memory index\n"); - dev->kbc_in = 1; - return 0; - - case 0xba: - kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); - if (dev->mem_index >= 0x80) { - switch (dev->mem[0x9b] & 0xc0) { - case 0x00: - index = 0x0080; - break; - case 0x40: case 0x80: - index = 0x0000; - break; - case 0xc0: - index = 0x0100; - break; - } - kbc_transmit(dev, dev->mem[index + dev->mem_index]); - } else if (dev->mem_index == 0x42) - kbc_transmit(dev, dev->status); - else if (dev->mem_index >= 0x40) - kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); - else - kbc_transmit(dev, dev->mem_int[dev->mem_index]); - return 0; - - case 0xbb: - kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - -#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (!(dev->flags & KBC_FLAG_PS2)) - write_output(dev, dev->p2 | (4 << (val & 0x01))); - kbc_transmit(dev, 0x00); - return 0; -#endif - - case 0xbc: - switch (dev->mem_index) { - case 0x00: /* STAT8042 */ - kbc_transmit(dev, dev->status); - break; - case 0x01: /* Password_ptr */ - kbc_transmit(dev, dev->mem[0x1c]); - break; - case 0x02: /* Wakeup_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x1e]); - break; - case 0x03: /* CCB */ - kbc_transmit(dev, dev->mem[0x20]); - break; - case 0x04: /* Debounce_time */ - kbc_transmit(dev, dev->mem[0x4d]); - break; - case 0x05: /* Pulse_Width */ - kbc_transmit(dev, dev->mem[0x4e]); - break; - case 0x06: /* Pk_sel_byte */ - kbc_transmit(dev, dev->mem[0x4c]); - break; - case 0x07: /* Func_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x7e]); - break; - case 0x08: /* TypematicRate */ - kbc_transmit(dev, dev->mem[0x80]); - break; - case 0x09: /* Led_Flag_Byte */ - kbc_transmit(dev, dev->mem[0x81]); - break; - case 0x0a: /* Kbms_Command_St */ - kbc_transmit(dev, dev->mem[0x87]); - break; - case 0x0b: /* Delay_Count_Byte */ - kbc_transmit(dev, dev->mem[0x86]); - break; - case 0x0c: /* KBC_Flags */ - kbc_transmit(dev, dev->mem[0x9b]); - break; - case 0x0d: /* SCODE_HK1 */ - kbc_transmit(dev, dev->mem[0x50]); - break; - case 0x0e: /* SCODE_HK2 */ - kbc_transmit(dev, dev->mem[0x51]); - break; - case 0x0f: /* SCODE_HK3 */ - kbc_transmit(dev, dev->mem[0x52]); - break; - case 0x10: /* SCODE_HK4 */ - kbc_transmit(dev, dev->mem[0x53]); - break; - case 0x11: /* SCODE_HK5 */ - kbc_transmit(dev, dev->mem[0x54]); - break; - case 0x12: /* SCODE_HK6 */ - kbc_transmit(dev, dev->mem[0x55]); - break; - case 0x13: /* TASK_HK1 */ - kbc_transmit(dev, dev->mem[0x56]); - break; - case 0x14: /* TASK_HK2 */ - kbc_transmit(dev, dev->mem[0x57]); - break; - case 0x15: /* TASK_HK3 */ - kbc_transmit(dev, dev->mem[0x58]); - break; - case 0x16: /* TASK_HK4 */ - kbc_transmit(dev, dev->mem[0x59]); - break; - case 0x17: /* TASK_HK5 */ - kbc_transmit(dev, dev->mem[0x5a]); - break; - /* The next 4 bytes have uncertain correspondences. */ - case 0x18: /* Batt_Poll_delay_Time */ - kbc_transmit(dev, dev->mem[0x5b]); - break; - case 0x19: /* Batt_Alarm_Reg1 */ - kbc_transmit(dev, dev->mem[0x5c]); - break; - case 0x1a: /* Batt_Alarm_Reg2 */ - kbc_transmit(dev, dev->mem[0x5d]); - break; - case 0x1b: /* Batt_Alarm_Tsk_Reg */ - kbc_transmit(dev, dev->mem[0x5e]); - break; - case 0x1c: /* Kbc_State1 */ - kbc_transmit(dev, dev->mem[0x9d]); - break; - case 0x1d: /* Aux_Config */ - kbc_transmit(dev, dev->mem[0x75]); - break; - case 0x1e: /* Kbc_State3 */ - kbc_transmit(dev, dev->mem[0x73]); - break; - default: - kbc_transmit(dev, 0x00); - break; - } - kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); + if (! PCI) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_data(dev, 0x00); return 0; - case 0xbd: - kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); - dev->kbc_in = 1; - return 0; - - case 0xc1: /* write input port */ - kbd_log("ATkbc: AMI MegaKey - write input port\n"); - dev->kbc_in = 1; - return 0; - - case 0xc4: - /* set KBC line P14 low */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); - dev->p1 &= 0xef; - kbc_transmit(dev, 0x00); - return 0; - case 0xc5: - /* set KBC line P15 low */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); - dev->p1 &= 0xdf; - kbc_transmit(dev, 0x00); - return 0; - - case 0xc8: case 0xc9: + case 0xc8: /* - * (un)block KBC lines P22/P23 + * unblock KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); - dev->p2_locked = (val & 1); + kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; - case 0xcc: - /* set KBC line P14 high */ - kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); - dev->p1 |= 0x10; - kbc_transmit(dev, 0x00); - return 0; - case 0xcd: - /* set KBC line P15 high */ - kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); - dev->p1 |= 0x20; - kbc_transmit(dev, 0x00); + case 0xc9: + /* + * block KBC lines P22/P23 + * (disallow command D1 from changing bits 2/3 of the port) + */ + kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); + dev->output_locked = 1; return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -2642,20 +1510,23 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0 ... 0xff: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -2670,7 +1541,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -2679,34 +1550,12 @@ write60_quadtel(void *priv, uint8_t val) return 1; } - static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { - /* This appears to be a clone of "Read input port", in which case, the bis would be: - 7: M290 (AT KBC): - Keyboard lock (1 = unlocked, 0 = locked); - M300 (PS/2 KBC): - Bus expansion board present (1 = present, 0 = not present); - 6: Usually: - Display (1 = MDA, 0 = CGA, but can have its polarity inverted); - 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); - 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); - 3: Fast Ram check (if inactive keyboard works erratically); - 2: Keyboard fuse present - This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; - 1: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Mouse data in; - 0: M290 (AT KBC): - Unused; - M300 (PS/2 KBC): - Key data in. - */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -2715,9 +1564,11 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); + add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); return 0; - } + } return write64_generic(dev, val); } @@ -2735,7 +1586,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; } @@ -2748,7 +1599,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->kbc_cmd) { + switch(dev->command) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -2791,30 +1642,29 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - kbc_transmit(dev, t3100e_config_get()); + add_data(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - kbc_transmit(dev, t3100e_mono_get()); + add_data(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->kbc_in = 1; + dev->want60 = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_FLAG_PS2; + dev->flags &= ~KBC_TYPE_MASK; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_FLAG_PS2; - } -#ifdef ENABLE_KEYBOARD_AT_LOG - else + dev->flags |= KBC_TYPE_PS2_NOREF; + } else { kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); -#endif + dev->flags |= KBC_TYPE_ISA; + } return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -2824,9 +1674,8 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - kbc_transmit(dev, 0x04); - else - kbc_transmit(dev, 0x00); + add_data(dev, 0x04); + else add_data(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -2839,8 +1688,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbc_transmit(dev, dev->p1); + dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_data(dev, dev->input_port); return 0; } @@ -2853,52 +1702,423 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; + int i = 0, bad = 1; + uint8_t mask, kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; + + kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); switch (port) { case 0x60: - dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); + dev->status &= ~STAT_CD; + if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; -#if 0 - if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { - dev->status &= ~STAT_IFULL; - write_output(dev, val); - dev->fast_a20_phase = 0; + switch (dev->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->output_port & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + add_to_kbc_queue_front(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (val == 0xbb) + break; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_mouse(dev, 1); + if (mouse_write) + mouse_write(val, mouse_p); + else + add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + + if (bad) { + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); + add_data_kbd(0xfe); + } + } + } else { + /* Write data to keyboard. */ + dev->mem[0] &= ~0x10; + + if (dev->key_wantdata) { + dev->key_wantdata = 0; + + /* + * Several system BIOSes and OS device drivers + * mess up with this, and repeat the command + * code many times. Fun! + */ + if (val == dev->key_command) { + /* Respond NAK and ignore it. */ + add_data_kbd(0xfe); + dev->key_command = 0x00; + break; + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd_direct(dev, 0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", val); + break; + + case 0xf0: /* get/set scancode set */ + add_data_kbd_direct(dev, 0xfa); + if (val == 0) { + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + add_data_kbd_direct(dev, keyboard_mode & 3); + } else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + add_data_kbd_direct(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); + add_data_kbd_direct(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + dev->key_command = 0x00; + } else { + /* No keyboard command in progress. */ + dev->key_command = 0x00; + + set_enable_kbd(dev, 1); + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + add_data_kbd_direct(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + add_data_kbd_direct(dev, 0xfe); + break; + + /* Sent by Pentium-era AMI BIOS'es.*/ + case 0x71: case 0x82: + kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + add_data_kbd_direct(dev, 0xfa); + + dev->key_wantdata = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + add_data_kbd_direct(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + add_data_kbd_direct(dev, 0xfa); + add_data_kbd_direct(dev, 0xab); + add_data_kbd_direct(dev, 0x83); + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + add_data_kbd_direct(dev, 0xfa); + dev->key_wantdata = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", + val, keyboard_scan, dev->mem[0]); + add_data_kbd_direct(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + add_data_kbd_direct(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + add_data_kbd_raw(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbc_queue_reset(1); + kbd_last_scan_code = 0x00; + add_data_kbd_direct(dev, 0xfa); + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->reset_delay = RESET_DELAY_TIME; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + add_data_kbd_direct(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = val; + } } -#endif break; - case 0x64: - dev->status |= (STAT_CD | STAT_IFULL); - dev->ib = val; - // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); -#if 0 - if (val == 0xd1) { - dev->status &= ~STAT_IFULL; - dev->fast_a20_phase = 1; - } else if (val == 0xfe) { - dev->status &= ~STAT_IFULL; - pulse_output(dev, 0x0e); - } else if ((val == 0xad) || (val == 0xae)) { - dev->status &= ~STAT_IFULL; - if (val & 0x01) - dev->mem[0x20] |= 0x10; - else - dev->mem[0x20] &= ~0x10; - } else if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); + case 0x61: + ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 1); + + if (kbc_ven == KBC_VEN_XI8088) + xi8088_turbo_set(!!(val & 0x04)); + break; + + case 0x64: + /* Controller command. */ + dev->want60 = 0; + dev->status |= STAT_CD; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + add_data(dev, dev->mem[val & 0x1f]); + break; + + /* Write data to KBC memory. */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + dev->want60 = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) + dev->status |= STAT_IFULL; + write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0x00; + dev->status &= ~STAT_OFULL; + dev->last_irq = dev->old_last_irq = 0; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + add_data(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + add_data(dev, 0x00); /*no error*/ + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + for (i = 0; i < 16; i++) + add_data(dev, dev->mem[i]); + add_data(dev, (dev->input_port & 0xf0) | 0x80); + add_data(dev, dev->output_port); + add_data(dev, dev->status); + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + add_data(dev, dev->ami_flags); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->want60 = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) + mask &= 0xbf; + add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->want60 = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + dev->want60 = 1; + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + add_data(dev, 0x00); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); } -#else - /* if (val == 0xa1) { - dev->status &= ~STAT_IFULL; - kbc_send_to_ob(dev, 'H', 0, 0x00); - } */ - // kbc_process(dev); -#endif + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = val; break; } } @@ -2909,20 +2129,83 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; - // if (dev->flags & KBC_FLAG_PS2) - // cycles -= ISA_CYCLES(8); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + cycles -= ISA_CYCLES(8); + + if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) + port = 0x61; switch (port) { case 0x60: - ret = dev->ob; + ret = dev->out; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + if (dev->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (kbc_ven == KBC_VEN_XI8088) { + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x62: + ret = 0xff; + if (kbc_ven == KBC_VEN_OLIVETTI) { + /* SWA on Olivetti M240 mainboard (off=1) */ + ret = 0x00; + if (ppi.pb & 0x8) { + /* Switches 4, 5 - floppy drives (number) */ + int i, fdd_count = 0; + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 2); + /* Switches 6, 7 - monitor type */ + if (video_is_mda()) + ret |= 0x3; + else if (video_is_cga()) + ret |= 0x2; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + } else { + /* bit 2 always on */ + ret |= 0x4; + /* Switch 8 - 8087 FPU. */ + if (hasfpu) + ret |= 0x02; + } + } + break; case 0x64: - ret = dev->status; + ret = (dev->status & 0xfb); + if (dev->mem[0] & STAT_SYSFLAG) + ret |= STAT_SYSFLAG; + /* Only clear the transmit timeout flag on non-PS/2 controllers, as on + PS/2 controller, it is the keyboard/mouse output source bit. */ + // dev->status &= ~STAT_RTIMEOUT; + if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && + (kbc_ven != KBC_VEN_IBM_MCA)) + dev->status &= ~STAT_TTIMEOUT; break; default: @@ -2930,57 +2213,48 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); + kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); return(ret); } +static void +kbd_refresh(void *priv) +{ + atkbd_t *dev = (atkbd_t *)priv; + + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); +} + + static void kbd_reset(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - - if (dev == NULL) - return; - - dev->status &= ~(STAT_IFULL | STAT_OFULL | STAT_CD); - dev->last_irq = 0; - picintc(1 << 1); - picintc(1 << 12); - dev->secr_phase = 0; - dev->kbd_in = 0; - dev->ob = 0xff; - - sc_or = 0; -} - - -static void -kbd_power_on(atkbd_t *dev) -{ int i; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_reset(dev); - + dev->first_write = 1; + // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - /* Write the value here first, so that we don't hit a pulse reset. */ - dev->p2 = 0xcf; + dev->mem[0] = 0x01; + dev->mem[0] |= CCB_TRANSLATE; + dev->wantirq = 0; write_output(dev, 0xcf); - dev->mem[0x20] = 0x01; - dev->mem[0x20] |= CCB_TRANSLATE; - dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); + dev->last_irq = dev->old_last_irq = 0; + dev->secr_phase = 0; + dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->p1 ^= 0x40; - if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) - dev->inhibit = ((dev->p1 & 0x80) >> 3); + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else - dev->inhibit = 0x10; - kbd_log("ATkbc: input port = %02x\n", dev->p1); + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbc: input port = %02x\n", dev->input_port); + + keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2988,16 +2262,18 @@ kbd_power_on(atkbd_t *dev) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->mem[0x31] = 0xfe; - - keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); - - for (i = 1; i <= 2; i++) + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) kbc_queue_reset(i); + kbd_last_scan_code = 0; + + sc_or = 0; memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); } @@ -3019,6 +2295,7 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); + timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -3042,14 +2319,17 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - dev->kbc_poll_phase = KBC_RESET; - kbd_send_to_host(dev, 0xaa); + kbd_reset(dev); - io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); - io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + timer_add(&dev->refresh_time, kbd_refresh, dev, 1); + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -3065,14 +2345,12 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: - /* The Olivetti controller is a special case - starts directly in the - main loop instead of the reset loop. */ - dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: + case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -3092,8 +2370,6 @@ kbd_init(const device_t *info) break; } - kbd_power_on(dev); - /* We need this, sadly. */ SavedKbd = dev; @@ -3121,6 +2397,16 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; +const device_t keyboard_at_samsung_device = { + "PC/AT Keyboard (Samsung)", + 0, + KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -3152,6 +2438,16 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + { NULL }, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -3164,7 +2460,7 @@ const device_t keyboard_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3174,7 +2470,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -3194,7 +2490,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3204,7 +2500,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -3234,7 +2530,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -3244,7 +2540,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -3254,7 +2550,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -3264,7 +2560,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -3274,7 +2570,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_ACER, + KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -3285,8 +2581,17 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - // mouse_write = func; - // mouse_p = priv; + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + + add_data_kbd_queue(dev, 0, val); } @@ -3299,30 +2604,10 @@ keyboard_at_adddata_mouse(uint8_t val) } -void -keyboard_at_adddata_mouse_direct(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - -void -keyboard_at_adddata_mouse_cmd(uint8_t val) -{ - // atkbd_t *dev = SavedKbd; - - return; -} - - void keyboard_at_mouse_reset(void) { - // atkbd_t *dev = SavedKbd; - - return; + kbc_queue_reset(2); } @@ -3333,22 +2618,13 @@ keyboard_at_mouse_pos(void) } -int -keyboard_at_fixed_channel(void) -{ - // atkbd_t *dev = SavedKbd; - - return 0x000; -} - - void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -3362,7 +2638,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0] & 0x20) ? 0x00 : 0x10); } @@ -3371,17 +2647,5 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); -} - - -void -keyboard_at_set_mode(int ps2) -{ - atkbd_t *dev = SavedKbd; - - if (ps2) - dev->flags |= KBC_FLAG_PS2; - else - dev->flags &= ~KBC_FLAG_PS2; + write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 649182ca5..a28a085ff 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -93,8 +93,6 @@ ps2_write(uint8_t val, void *priv) mouse_t *dev = (mouse_t *)priv; uint8_t temp; - pclog("ps2_write(%02X)\n", val); - if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; @@ -104,16 +102,16 @@ ps2_write(uint8_t val, void *priv) switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf3: /* set sample rate */ dev->sample_rate = val; - keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ + keyboard_at_adddata_mouse(0xfa); /* Command response */ break; default: - keyboard_at_adddata_mouse_cmd(0xfc); + keyboard_at_adddata_mouse(0xfc); } } else { dev->command = val; @@ -121,21 +119,21 @@ ps2_write(uint8_t val, void *priv) switch (dev->command) { case 0xe6: /* set scaling to 1:1 */ dev->flags &= ~FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe7: /* set scaling to 2:1 */ dev->flags |= FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe8: /* set mouse resolution */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xe9: /* status request */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); temp = (dev->flags & 0x30); if (mouse_buttons & 0x01) temp |= 0x01; @@ -143,13 +141,13 @@ ps2_write(uint8_t val, void *priv) temp |= 0x02; if (mouse_buttons & 0x04) temp |= 0x03; - keyboard_at_adddata_mouse_cmd(temp); - keyboard_at_adddata_mouse_cmd(dev->resolution); - keyboard_at_adddata_mouse_cmd(dev->sample_rate); + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(dev->resolution); + keyboard_at_adddata_mouse(dev->sample_rate); break; case 0xeb: /* Get mouse data */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); temp = 0; if (dev->x < 0) @@ -162,36 +160,36 @@ ps2_write(uint8_t val, void *priv) temp |= 2; if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI)) temp |= 4; - keyboard_at_adddata_mouse_cmd(temp); - keyboard_at_adddata_mouse_cmd(dev->x & 0xff); - keyboard_at_adddata_mouse_cmd(dev->y & 0xff); + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(dev->x & 0xff); + keyboard_at_adddata_mouse(dev->y & 0xff); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse_cmd(dev->z); + keyboard_at_adddata_mouse(dev->z); break; case 0xf2: /* read ID */ - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse_cmd(0x03); + keyboard_at_adddata_mouse(0x03); else - keyboard_at_adddata_mouse_cmd(0x00); + keyboard_at_adddata_mouse(0x00); break; case 0xf3: /* set command mode */ dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */ break; case 0xf4: /* enable */ dev->flags |= FLAG_ENABLED; mouse_scan = 1; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf5: /* disable */ dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); break; case 0xf6: /* set defaults */ @@ -201,15 +199,15 @@ mouse_reset: dev->flags &= 0x88; mouse_scan = 1; keyboard_at_mouse_reset(); - keyboard_at_adddata_mouse_cmd(0xfa); + keyboard_at_adddata_mouse(0xfa); if (dev->command == 0xff) { - keyboard_at_adddata_mouse_cmd(0xaa); - keyboard_at_adddata_mouse_cmd(0x00); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); } break; default: - keyboard_at_adddata_mouse_cmd(0xfe); + keyboard_at_adddata_mouse(0xfe); } } @@ -241,9 +239,6 @@ ps2_poll(int x, int y, int z, int b, void *priv) return(0xff); #endif - if ((keyboard_at_fixed_channel() & 0xf00) == 0x200) - return(0xff); - if (!mouse_scan) return(0xff); From bfb3c0c324bd3fbdf1cdc4c3183e14a679226809 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 13 Nov 2021 23:15:28 +0100 Subject: [PATCH 131/140] Fixed the intendation mess in cpu/x86seg.c, removed port 61h handling from keyboard/keyboard_at.c, and fixed a function with undeclared type in win/win.c. --- src/cpu/x86seg.c | 284 +++++++++++++++++++-------------------- src/device/keyboard_at.c | 100 +------------- src/win/win.c | 1 + 3 files changed, 148 insertions(+), 237 deletions(-) diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 8f5798ddb..bd1d1b864 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -942,173 +942,173 @@ void loadcscall(uint16_t seg) segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); } else /* On non-conforming segments, set RPL = CPL */ seg = (seg & 0xfffc) | CPL; - CS = seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if ((CPL == 3) && (oldcpl != 3)) - flushmmucache_cr3(); + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif #ifdef ENABLE_X86SEG_LOG - x86seg_log("Complete\n"); + x86seg_log("Complete\n"); #endif - cycles -= timing_call_pm; - } else { - type = segdat[2] & 0x0f00; - x86seg_log("Type %03X\n", type); - switch (type) { - case 0x0400: /* Call gate */ - case 0x0c00: /* 386 Call gate */ - x86seg_log("Callgate %08X\n", cpu_state.pc); - cgate32 = (type & 0x0800); - cgate16 = !cgate32; + cycles -= timing_call_pm; + } else { + type = segdat[2] & 0x0f00; + x86seg_log("Type %03X\n", type); + switch (type) { + case 0x0400: /* Call gate */ + case 0x0c00: /* 386 Call gate */ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32 = (type & 0x0800); + cgate16 = !cgate32; #ifndef USE_NEW_DYNAREC - oldcs = CS; + oldcs = CS; #endif - count = segdat[2] & 0x001f; - if (DPL < CPL) { - x86gpf("loadcscall(): ex DPL < CPL",seg & 0xfffc); - return; - } - if (DPL < (seg & 0x0003)) { - x86gpf("loadcscall(): ex DPL < RPL", seg & 0xfffc); - return; - } - if (!(segdat[2] & 0x8000)) { - x86np("Call gate not present", seg & 0xfffc); - return; - } - seg2 = segdat[1]; + count = segdat[2] & 0x001f; + if (DPL < CPL) { + x86gpf("loadcscall(): ex DPL < CPL",seg & 0xfffc); + return; + } + if (DPL < (seg & 0x0003)) { + x86gpf("loadcscall(): ex DPL < RPL", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Call gate not present", seg & 0xfffc); + return; + } + seg2 = segdat[1]; - x86seg_log("New address : %04X:%08X\n", seg2, newpc); + x86seg_log("New address : %04X:%08X\n", seg2, newpc); - if (!(seg2 & 0xfffc)) { - x86gpf("loadcscall(): ex selector is NULL", 0); - return; - } - addr = seg2 & 0xfff8; - dt = (seg2 & 0x0004) ? &ldt : &gdt; - if ((addr + 7) > dt->limit) { - x86gpf("loadcscall(): ex Selector > DT limit", seg2 & 0xfff8); - return; - } - addr += dt->base; - read_descriptor(addr, segdat, segdat32, 1); - if (cpu_state.abrt) - return; + if (!(seg2 & 0xfffc)) { + x86gpf("loadcscall(): ex selector is NULL", 0); + return; + } + addr = seg2 & 0xfff8; + dt = (seg2 & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadcscall(): ex Selector > DT limit", seg2 & 0xfff8); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n", seg2, segdat[0], segdat[1], segdat[2]); - if (DPL > CPL) { - x86gpf("loadcscall(): ex DPL > CPL", seg2 & 0xfffc); - return; - } - if (!(segdat[2] & 0x8000)) { - x86seg_log("Call gate CS not present %04X\n", seg2); - x86np("Call gate CS not present", seg2 & 0xfffc); - return; - } + if (DPL > CPL) { + x86gpf("loadcscall(): ex DPL > CPL", seg2 & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86seg_log("Call gate CS not present %04X\n", seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } - switch (segdat[2] & 0x1f00) { - case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ - if (DPL < CPL) { + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if (DPL < CPL) { #ifdef USE_NEW_DYNAREC - uint16_t oldcs = CS; + uint16_t oldcs = CS; #endif - oaddr = addr; - /* Load new stack */ - oldss = SS; - oldsp = oldsp2 = ESP; - cpl_override = 1; - if (tr.access & 8) { - addr = 4 + tr.base + (DPL << 3); - newss = readmemw(0, addr + 4); - if (cpu_16bitbus) { - newsp = readmemw(0, addr); - newsp |= (readmemw(0, addr + 2) << 16); - } else - newsp = readmeml(0, addr); - } else { - addr = 2 + tr.base + (DPL * 4); - newss = readmemw(0, addr + 2); + oaddr = addr; + /* Load new stack */ + oldss = SS; + oldsp = oldsp2 = ESP; + cpl_override = 1; + if (tr.access & 8) { + addr = 4 + tr.base + (DPL << 3); + newss = readmemw(0, addr + 4); + if (cpu_16bitbus) { newsp = readmemw(0, addr); - } - cpl_override = 0; - if (cpu_state.abrt) - return; - x86seg_log("New stack %04X:%08X\n", newss, newsp); - if (!(newss & 0xfffc)) { - x86ts(NULL, newss & 0xfffc); - return; - } - addr = newss & 0xfff8; - dt = (newss & 0x0004) ? &ldt : &gdt; - if ((addr + 7) > dt->limit) { - fatal("Bigger than DT limit %04X %08X %04X CSC SS\n", newss, addr, dt->limit); - x86ts(NULL, newss & ~3); - return; - } - addr += dt->base; - x86seg_log("Read stack seg\n"); - read_descriptor(addr, segdat2, segdat232, 1); - if (cpu_state.abrt) - return; - x86seg_log("Read stack seg done!\n"); - if (((newss & 0x0003) != DPL) || (DPL2 != DPL)) { - x86ts(NULL, newss & 0xfffc); - return; - } - if ((segdat2[2] & 0x1a00) != 0x1200) { - x86ts("Call gate loading SS unknown type", newss & 0xfffc); - return; - } - if (!(segdat2[2] & 0x8000)) { - x86ss("Call gate loading SS not present", newss & 0xfffc); - return; - } - if (!stack32) - oldsp &= 0xffff; - SS = newss; - set_stack32((segdat2[3] & 0x0040) ? 1 : 0); - if (stack32) - ESP = newsp; - else - SP = newsp; + newsp |= (readmemw(0, addr + 2) << 16); + } else + newsp = readmeml(0, addr); + } else { + addr = 2 + tr.base + (DPL * 4); + newss = readmemw(0, addr + 2); + newsp = readmemw(0, addr); + } + cpl_override = 0; + if (cpu_state.abrt) + return; + x86seg_log("New stack %04X:%08X\n", newss, newsp); + if (!(newss & 0xfffc)) { + x86ts(NULL, newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + fatal("Bigger than DT limit %04X %08X %04X CSC SS\n", newss, addr, dt->limit); + x86ts(NULL, newss & ~3); + return; + } + addr += dt->base; + x86seg_log("Read stack seg\n"); + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 0x0003) != DPL) || (DPL2 != DPL)) { + x86ts(NULL, newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + x86ts("Call gate loading SS unknown type", newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + x86ss("Call gate loading SS not present", newss & 0xfffc); + return; + } + if (!stack32) + oldsp &= 0xffff; + SS = newss; + set_stack32((segdat2[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); - x86seg_log("Set access 1\n"); - cpl_override = 1; - writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ - cpl_override = 0; + x86seg_log("Set access 1\n"); + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; - CS = seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if ((CPL == 3) && (oldcpl != 3)) - flushmmucache_cr3(); + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(segdat[3] & 0x0040); - cpu_state.pc = newpc; + set_use32(segdat[3] & 0x0040); + cpu_state.pc = newpc; - x86seg_log("Set access 2\n"); + x86seg_log("Set access 2\n"); - cpl_override = 1; - writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ - cpl_override = 0; + cpl_override = 1; + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; - x86seg_log("Type %04X\n", type); - if (type == 0x0c00) { - PUSHL(oldss); - PUSHL(oldsp2); - if (cpu_state.abrt) { - SS = oldss; - ESP = oldsp2; + x86seg_log("Type %04X\n", type); + if (type == 0x0c00) { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; #ifdef USE_NEW_DYNAREC - CS = oldcs; + CS = oldcs; #endif - return; + return; } if (count) { while (count--) { diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 81455f5a6..2969ca82d 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,8 +57,6 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - #define RESET_DELAY_TIME (100 * 10) /* 600ms */ #define CCB_UNUSED 0x80 @@ -98,8 +96,7 @@ typedef struct { uint8_t command, status, old_status, out, old_out, secr_phase, mem_addr, input_port, output_port, old_output_port, key_command, output_locked, ami_stat, want60, - wantirq, key_wantdata, refresh, first_write, - ami_flags, pad[7]; + wantirq, key_wantdata, ami_flags, first_write; uint8_t mem[0x100]; @@ -109,7 +106,7 @@ typedef struct { uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); @@ -1706,11 +1703,6 @@ kbd_write(uint16_t port, uint8_t val, void *priv) uint8_t mask, kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - - kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); - switch (port) { case 0x60: dev->status &= ~STAT_CD; @@ -1972,20 +1964,6 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } break; - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if (kbc_ven == KBC_VEN_XI8088) - xi8088_turbo_set(!!(val & 0x04)); - break; - case 0x64: /* Controller command. */ dev->want60 = 0; @@ -2135,9 +2113,6 @@ kbd_read(uint16_t port, void *priv) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) cycles -= ISA_CYCLES(8); - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - switch (port) { case 0x60: ret = dev->out; @@ -2146,56 +2121,6 @@ kbd_read(uint16_t port, void *priv) dev->last_irq = 0; break; - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if (kbc_ven == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) - ret |= 0x04; - else - ret &= ~0x04; - } - break; - - case 0x62: - ret = 0xff; - if (kbc_ven == KBC_VEN_OLIVETTI) { - /* SWA on Olivetti M240 mainboard (off=1) */ - ret = 0x00; - if (ppi.pb & 0x8) { - /* Switches 4, 5 - floppy drives (number) */ - int i, fdd_count = 0; - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } - if (!fdd_count) - ret |= 0x00; - else - ret |= ((fdd_count - 1) << 2); - /* Switches 6, 7 - monitor type */ - if (video_is_mda()) - ret |= 0x3; - else if (video_is_cga()) - ret |= 0x2; /* 0x10 would be 40x25 */ - else - ret |= 0x0; - } else { - /* bit 2 always on */ - ret |= 0x4; - /* Switch 8 - 8087 FPU. */ - if (hasfpu) - ret |= 0x02; - } - } - break; case 0x64: ret = (dev->status & 0xfb); if (dev->mem[0] & STAT_SYSFLAG) @@ -2219,16 +2144,6 @@ kbd_read(uint16_t port, void *priv) } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { @@ -2273,7 +2188,7 @@ kbd_reset(void *priv) set_scancode_map(dev); - dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; } @@ -2295,7 +2210,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2321,15 +2235,11 @@ kbd_init(const device_t *info) video_reset(gfxcard); kbd_reset(dev); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; diff --git a/src/win/win.c b/src/win/win.c index ee2fe4063..54aab11eb 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -139,6 +139,7 @@ win_log(const char *fmt, ...) #endif +void free_string(rc_str_t **str) { if (*str != NULL) { From 11431213eda6cc2a27c99b15162473a173f61c31 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 13 Nov 2021 23:25:07 +0100 Subject: [PATCH 132/140] Also reverted all the video changes. --- src/video/CMakeLists.txt | 4 +- src/video/vid_cl54xx.c | 22 --- src/video/vid_et3000.c | 308 -------------------------------------- src/video/vid_et4000.c | 162 ++++---------------- src/video/vid_et4000w32.c | 7 +- src/video/vid_oak_oti.c | 38 ++++- src/video/vid_s3.c | 32 +--- src/video/vid_svga.c | 152 +++---------------- src/video/vid_table.c | 2 - src/win/Makefile.mingw | 1 - 10 files changed, 92 insertions(+), 636 deletions(-) delete mode 100644 src/video/vid_et3000.c diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index edfab1864..c8cbdef62 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -20,8 +20,8 @@ add_library(vid OBJECT video.c vid_table.c vid_cga.c vid_cga_comp.c vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c - vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c - vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c + vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c + vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 21ddeca83..7ba2efb3c 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -1780,28 +1780,6 @@ gd54xx_recalctimings(svga_t *svga) } svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; - - pclog("svga->crtc[0x1a] = %02X\n", svga->crtc[0x1a]); - pclog("svga->crtc[0x1b] = %02X\n", svga->crtc[0x1b]); - pclog("svga->crtc[0x1c] = %02X\n", svga->crtc[0x1c]); - - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) - svga->htotal += ((svga->crtc[0x1c] >> 3) & 0x07); - - if (svga->crtc[0x1b] & ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5424) ? 0xa0 : 0x20)) { - /* Special blanking mode: the blank start and end become components of the window generator, - and the actual blanking comes from the display enable signal. */ - /* Start blanking at the first character clock after the last active one. */ - svga->hblankstart = svga->crtc[1] + 1; - svga->hblank_end_val = (svga->htotal + 6) & 0x3f; - /* In this mode, the dots per clock are always 8 or 16, never 9 or 18. */ - if (!svga->scrblank && svga->attr_palette_enable) - svga->dots_per_clock = (svga->seqregs[1] & 8) ? 16 : 8; - /* No overscan in this mode. */ - svga->hblank_overscan = 0; - /* Also make sure vertical blanking starts on display end. */ - svga->vblankstart = svga->dispend; - } } diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c deleted file mode 100644 index 70a383bfa..000000000 --- a/src/video/vid_et3000.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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 Tseng Labs ET3000. - * - * Authors: Miran Grca, - * - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/mca.h> -#include <86box/mem.h> -#include <86box/rom.h> -#include <86box/device.h> -#include <86box/timer.h> -#include <86box/video.h> -#include <86box/vid_svga.h> -#include <86box/vid_svga_render.h> - - -#define BIOS_ROM_PATH "roms/video/et3000/Tseng ET3000AX ISA VGA-VGA ULTRA.bin" - -typedef struct { - const char *name; - int type; - - svga_t svga; - - rom_t bios_rom; - - uint8_t banking; -} et3000_t; - - -static video_timings_t timing_et3000_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; - -static uint8_t et3000_in(uint16_t addr, void *priv); -static void et3000_out(uint16_t addr, uint8_t val, void *priv); - - -static uint8_t -et3000_in(uint16_t addr, void *priv) -{ - et3000_t *dev = (et3000_t *)priv; - svga_t *svga = &dev->svga; - - if (((addr & 0xfff0) == 0x3d0 || - (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; - - switch (addr) { - case 0x3cd: /*Banking*/ - return dev->banking; - - case 0x3d4: - return svga->crtcreg; - - case 0x3d5: - return svga->crtc[svga->crtcreg]; - } - - return svga_in(addr, svga); -} - -static void -et3000_out(uint16_t addr, uint8_t val, void *priv) -{ - et3000_t *dev = (et3000_t *)priv; - svga_t *svga = &dev->svga; - uint8_t old; - - if (((addr & 0xfff0) == 0x3d0 || - (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; - - switch (addr) { - case 0x3c0: - case 0x3c1: - if (svga->attrff && (svga->attraddr == 0x16)) { - svga->attrregs[0x16] = val; - svga->chain4 &= ~0x10; - if (svga->gdcreg[5] & 0x40) - svga->chain4 |= (svga->attrregs[0x16] & 0x10); - svga_recalctimings(svga); - } - break; - - case 0x3c5: - if (svga->seqaddr == 4) { - svga->seqregs[4] = val; - - svga->chain2_write = !(val & 4); - svga->chain4 = (svga->chain4 & ~8) | (val & 8); - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); - return; - } - break; - - case 0x3cf: - if ((svga->gdcaddr & 15) == 5) { - svga->chain4 &= ~0x10; - if (val & 0x40) - svga->chain4 |= (svga->attrregs[0x16] & 0x10); - } - break; - - case 0x3cd: /*Banking*/ - dev->banking = val; - if (!(svga->crtc[0x23] & 0x80) && !(svga->gdcreg[6] & 0x08)) { - switch ((val >> 6) & 3) { - case 0: /*128K segments*/ - svga->write_bank = (val & 7) << 17; - svga->read_bank = ((val >> 3) & 7) << 17; - break; - case 1: /*64K segments*/ - svga->write_bank = (val & 7) << 16; - svga->read_bank = ((val >> 3) & 7) << 16; - break; - } - } - return; - - case 0x3d4: - svga->crtcreg = val & 0x3f; - return; - - case 0x3d5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - - if (old != val) { - if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - break; - } - - svga_out(addr, val, svga); -} - - -static void -et3000_recalctimings(svga_t *svga) -{ - svga->ma_latch |= (svga->crtc[0x23] & 2) << 15; - if (svga->crtc[0x25] & 1) svga->vblankstart |= 0x400; - if (svga->crtc[0x25] & 2) svga->vtotal |= 0x400; - if (svga->crtc[0x25] & 4) svga->dispend |= 0x400; - if (svga->crtc[0x25] & 8) svga->vsyncstart |= 0x400; - if (svga->crtc[0x25] & 0x10) svga->split |= 0x400; - - svga->interlace = !!(svga->crtc[0x25] & 0x80); - - if (svga->attrregs[0x16] & 0x10) { - svga->ma_latch <<= (1 << 0); - svga->rowoffset <<= (1 << 0); - switch (svga->gdcreg[5] & 0x60) { - case 0x00: - svga->render = svga_render_4bpp_highres; - svga->hdisp *= 2; - break; - case 0x20: - svga->render = svga_render_2bpp_highres; - break; - case 0x40: case 0x60: - svga->render = svga_render_8bpp_highres; - break; - } - } - - /* pclog("HDISP = %i, HTOTAL = %i, ROWOFFSET = %i, INTERLACE = %i\n", - svga->hdisp, svga->htotal, svga->rowoffset, svga->interlace); */ - - switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x24] << 1) & 4)) { - case 0: - case 1: - break; - case 3: - svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; - break; - case 5: - svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; - break; - default: - svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; - break; - } -} - - -static void * -et3000_init(const device_t *info) -{ - const char *fn; - et3000_t *dev; - - dev = (et3000_t *)malloc(sizeof(et3000_t)); - memset(dev, 0x00, sizeof(et3000_t)); - dev->name = info->name; - dev->type = info->local; - fn = BIOS_ROM_PATH; - - switch(dev->type) { - case 0: /* ISA ET3000AX */ - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et3000_isa); - svga_init(info, &dev->svga, dev, device_get_config_int("memory") << 10, - et3000_recalctimings, et3000_in, et3000_out, - NULL, NULL); - io_sethandler(0x03c0, 32, - et3000_in,NULL,NULL, et3000_out,NULL,NULL, dev); - break; - } - - rom_init(&dev->bios_rom, (char *) fn, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - dev->svga.bpp = 8; - dev->svga.miscout = 1; - - return(dev); -} - - -static void -et3000_close(void *priv) -{ - et3000_t *dev = (et3000_t *)priv; - - svga_close(&dev->svga); - - free(dev); -} - - -static void -et3000_speed_changed(void *priv) -{ - et3000_t *dev = (et3000_t *)priv; - - svga_recalctimings(&dev->svga); -} - - -static void -et3000_force_redraw(void *priv) -{ - et3000_t *dev = (et3000_t *)priv; - - dev->svga.fullchange = changeframecount; -} - - -static int -et3000_available(void) -{ - return rom_present(BIOS_ROM_PATH); -} - -static const device_config_t et3000_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, "", { 0 }, - { - { - "256 KB", 256 - }, - { - "512 KB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 - } -}; - -const device_t et3000_isa_device = { - "Tseng Labs ET3000AX (ISA)", - DEVICE_ISA, - 0, - et3000_init, et3000_close, NULL, - { et3000_available }, - et3000_speed_changed, - et3000_force_redraw, - et3000_config -}; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index dd24a5b09..740be207e 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -55,7 +55,6 @@ #define BIOS_ROM_PATH "roms/video/et4000/et4000.bin" -#define TC6058AF_BIOS_ROM_PATH "roms/video/et4000/Tseng_Labs_VGA-4000_BIOS_V1.1.bin" #define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" #define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" #define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" @@ -110,14 +109,13 @@ et4000_in(uint16_t addr, void *priv) { et4000_t *dev = (et4000_t *)priv; svga_t *svga = &dev->svga; - uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3c2: - if (dev->type == 2) { + if (dev->type == 1) { if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) return 0; else @@ -134,9 +132,7 @@ et4000_in(uint16_t addr, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (dev->type >= 1) - return sc1502x_ramdac_in(addr, svga->ramdac, svga); - break; + return sc1502x_ramdac_in(addr, svga->ramdac, svga); case 0x3cd: /*Banking*/ return dev->banking; @@ -146,26 +142,6 @@ et4000_in(uint16_t addr, void *priv) case 0x3d5: return svga->crtc[svga->crtcreg]; - - case 0x3da: - svga->attrff = 0; - - if (svga->cgastat & 0x01) - svga->cgastat &= ~0x30; - else - svga->cgastat ^= 0x30; - - ret = svga->cgastat; - - if ((svga->fcr & 0x08) && svga->dispon) - ret |= 0x08; - - if (ret & 0x08) - ret &= 0x7f; - else - ret |= 0x80; - - return ret; } return svga_in(addr, svga); @@ -247,34 +223,12 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { - case 0x3c5: - if (svga->seqaddr == 4) { - svga->seqregs[4] = val; - - svga->chain2_write = !(val & 4); - svga->chain4 = (svga->chain4 & ~8) | (val & 8); - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); - return; - } else if (svga->seqaddr == 0x0e) { - svga->seqregs[0x0e] = val; - svga->chain4 &= ~0x02; - if (svga->gdcreg[5] & 0x40) - svga->chain4 |= (svga->seqregs[0x0e] & 0x02); - svga_recalctimings(svga); - return; - } - break; - case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: - if (dev->type >= 1) { - sc1502x_ramdac_out(addr, val, svga->ramdac, svga); - return; - } - break; + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; case 0x3cd: /*Banking*/ if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { @@ -285,11 +239,7 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) return; case 0x3cf: - if ((svga->gdcaddr & 15) == 5) { - svga->chain4 &= ~0x02; - if (val & 0x40) - svga->chain4 |= (svga->seqregs[0x0e] & 0x02); - } else if ((svga->gdcaddr & 15) == 6) { + if ((svga->gdcaddr & 15) == 6) { if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { svga->write_bank = (dev->banking & 0x0f) * 0x10000; svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; @@ -470,8 +420,7 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) break; case 1: case 2: - if ((et4000->kasan_cfg_index - 0xF0) <= 16) - et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; io_removehandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); et4000->kasan_access_addr = (et4000->kasan_cfg_regs[2] << 8) | et4000->kasan_cfg_regs[1]; io_sethandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); @@ -514,10 +463,8 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) case 3: case 4: case 5: - if (et4000->kasan_cfg_regs[0] & 1) { - if ((addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)) <= 4) - et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; - } + if (et4000->kasan_cfg_regs[0] & 1) + et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; break; case 6: if ((et4000->kasan_cfg_regs[0] & 1) && (et4000->kasan_font_data[3] & !(val & 0x80)) && (et4000->get_korean_font_base & 0x7F) >= 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) { @@ -601,13 +548,13 @@ et4000_recalctimings(svga_t *svga) et4000_t *dev = (et4000_t *)svga->p; svga->ma_latch |= (svga->crtc[0x33] & 3) << 16; - if (svga->crtc[0x35] & 1) svga->vblankstart |= 0x400; - if (svga->crtc[0x35] & 2) svga->vtotal |= 0x400; - if (svga->crtc[0x35] & 4) svga->dispend |= 0x400; - if (svga->crtc[0x35] & 8) svga->vsyncstart |= 0x400; - if (svga->crtc[0x35] & 0x10) svga->split |= 0x400; + if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; if (!svga->rowoffset) svga->rowoffset = 0x100; - if (svga->crtc[0x3f] & 1) svga->htotal |= 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) { @@ -636,7 +583,7 @@ et4000_recalctimings(svga_t *svga) break; } - if (dev->type == 3 || dev->type == 4 || dev->type == 5) { + if (dev->type == 2 || dev->type == 3 || dev->type == 4) { if ((svga->render == svga_render_text_80) && ((svga->crtc[0x37] & 0x0A) == 0x0A)) { if (dev->port_32cb_val & 0x80) { svga->ma_latch -= 2; @@ -647,19 +594,6 @@ et4000_recalctimings(svga_t *svga) } } } - - if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { - svga->ma_latch <<= (1 << 0); - svga->rowoffset <<= (1 << 0); - svga->render = svga_render_8bpp_highres; - } - - if (dev->type == 0) { - if (svga->render == svga_render_8bpp_lowres) - svga->render = svga_render_8bpp_tseng_lowres; - else if (svga->render == svga_render_8bpp_highres) - svga->render = svga_render_8bpp_tseng_highres; - } } static void @@ -673,7 +607,6 @@ et4000_kasan_recalctimings(svga_t *svga) svga->ma_latch -= 3; svga->ca_adj = (et4000->kasan_cfg_regs[0] >> 6) - 3; svga->ksc5601_sbyte_mask = (et4000->kasan_cfg_regs[0] & 4) << 5; - /* TODO: Are we sure this doesn't use Attribute register 16h bit 6 (two-byte character code enable)? */ if((et4000->kasan_cfg_regs[0] & 0x23) == 0x20 && (et4000->kasan_cfg_regs[4] & 0x80) && ((svga->crtc[0x37] & 0x0B) == 0x0A)) svga->render = svga_render_text_80_ksc5601; } @@ -722,8 +655,7 @@ et4000_init(const device_t *info) fn = BIOS_ROM_PATH; switch(dev->type) { - case 0: /* ISA ET4000AX (TC6058AF) */ - case 1: /* ISA ET4000AX */ + case 0: /* ISA ET4000AX */ dev->vram_size = device_get_config_int("memory") << 10; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); svga_init(info, &dev->svga, dev, dev->vram_size, @@ -731,11 +663,9 @@ et4000_init(const device_t *info) NULL, NULL); io_sethandler(0x03c0, 32, et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); - if (dev->type == 0) - fn = TC6058AF_BIOS_ROM_PATH; break; - case 2: /* MCA ET4000AX */ + case 1: /* MCA ET4000AX */ dev->vram_size = 1024 << 10; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_mca); svga_init(info, &dev->svga, dev, dev->vram_size, @@ -748,8 +678,8 @@ et4000_init(const device_t *info) mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, NULL, dev); break; - case 3: /* Korean ET4000 */ - case 4: /* Trigem 286M ET4000 */ + case 2: /* Korean ET4000 */ + case 3: /* Trigem 286M ET4000 */ dev->vram_size = device_get_config_int("memory") << 10; dev->port_22cb_val = 0x60; dev->port_32cb_val = 0; @@ -773,7 +703,7 @@ et4000_init(const device_t *info) loadfont(KOREAN_FONT_ROM_PATH, 6); fn = KOREAN_BIOS_ROM_PATH; break; - case 5: /* Kasan ET4000 */ + case 4: /* Kasan ET4000 */ dev->vram_size = device_get_config_int("memory") << 10; dev->svga.ksc5601_sbyte_mask = 0; dev->svga.ksc5601_udc_area_msb[0] = 0xC9; @@ -809,8 +739,7 @@ et4000_init(const device_t *info) } - if (dev->type >= 1) - dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + dev->svga.ramdac = device_add(&sc1502x_ramdac_device); dev->vram_mask = dev->vram_size - 1; @@ -854,13 +783,6 @@ et4000_force_redraw(void *priv) } -static int -et4000_tc6058af_available(void) -{ - return rom_present(TC6058AF_BIOS_ROM_PATH); -} - - static int et4000_available(void) { @@ -882,27 +804,6 @@ et4000_kasan_available(void) rom_present(KASAN_FONT_ROM_PATH); } -static const device_config_t et4000_tc6058af_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1024, "", { 0 }, - { - { - "256 KB", 256 - }, - { - "512 KB", 512 - }, - { - "" - } - } - }, - { - "", "", -1 - } -}; - static const device_config_t et4000_config[] = { { @@ -927,21 +828,10 @@ static const device_config_t et4000_config[] = } }; -const device_t et4000_tc6058af_isa_device = { - "Tseng Labs ET4000AX (TC6058AF) (ISA)", - DEVICE_ISA, - 0, - et4000_init, et4000_close, NULL, - { et4000_tc6058af_available }, - et4000_speed_changed, - et4000_force_redraw, - et4000_tc6058af_config -}; - const device_t et4000_isa_device = { "Tseng Labs ET4000AX (ISA)", DEVICE_ISA, - 1, + 0, et4000_init, et4000_close, NULL, { et4000_available }, et4000_speed_changed, @@ -952,7 +842,7 @@ const device_t et4000_isa_device = { const device_t et4000_mca_device = { "Tseng Labs ET4000AX (MCA)", DEVICE_MCA, - 2, + 1, et4000_init, et4000_close, NULL, { et4000_available }, et4000_speed_changed, @@ -963,7 +853,7 @@ const device_t et4000_mca_device = { const device_t et4000k_isa_device = { "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", DEVICE_ISA, - 3, + 2, et4000_init, et4000_close, NULL, { et4000k_available }, et4000_speed_changed, @@ -974,7 +864,7 @@ const device_t et4000k_isa_device = { const device_t et4000k_tg286_isa_device = { "Trigem Korean VGA (Trigem 286M)", DEVICE_ISA, - 4, + 3, et4000_init, et4000_close, NULL, { et4000k_available }, et4000_speed_changed, @@ -985,7 +875,7 @@ const device_t et4000k_tg286_isa_device = { const device_t et4000_kasan_isa_device = { "Kasan Hangulmadang-16 VGA (Tseng Labs ET4000AX Korean)", DEVICE_ISA, - 5, + 4, et4000_init, et4000_close, NULL, { et4000_kasan_available }, et4000_speed_changed, diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index f4384b459..65dced875 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -397,7 +397,6 @@ et4000w32p_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); -#if 0 if (svga->adv_flags & FLAG_NOSKEW) { /* On the Cardex ET4000/W32p-based cards, adjust text mode clocks by 1. */ if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ @@ -414,10 +413,10 @@ et4000w32p_recalctimings(svga_t *svga) svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; else svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; - } + } else if ((svga->gdcreg[5] & 0x40) == 0) + svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; } } -#endif if (et4000->type == ET4000W32) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { @@ -464,10 +463,8 @@ et4000w32p_recalctimings(svga_t *svga) else svga->render = svga_render_text_80; } else { -#if 0 if (svga->adv_flags & FLAG_NOSKEW) svga->ma_latch--; -#endif switch (svga->gdcreg[5] & 0x60) { case 0x00: diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 31e49794a..941359987 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -31,7 +31,9 @@ #include <86box/vid_svga_render.h> #define BIOS_037C_PATH "roms/video/oti/bios.bin" -#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/oti067.bin" +#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/oti067.bin" +#define BIOS_067_M300_08_PATH "roms/machines/olivetti_m300_08/EVC_BIOS.ROM" +#define BIOS_067_M300_15_PATH "roms/machines/olivetti_m300_15/EVC_BIOS.ROM" #define BIOS_077_PATH "roms/video/oti/oti077.vbi" @@ -39,6 +41,7 @@ enum { OTI_037C, OTI_067 = 2, OTI_067_AMA932J, + OTI_067_M300 = 4, OTI_077 = 5 }; @@ -394,6 +397,16 @@ oti_init(const device_t *info) io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); break; + case OTI_067_M300: + if (rom_present(BIOS_067_M300_15_PATH)) + romfn = BIOS_067_M300_15_PATH; + else + romfn = BIOS_067_M300_08_PATH; + oti->vram_size = device_get_config_int("memory"); + oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */ + io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); + break; + case OTI_067: case OTI_077: romfn = BIOS_077_PATH; @@ -463,20 +476,27 @@ oti037c_available(void) return(rom_present(BIOS_037C_PATH)); } - static int oti067_ama932j_available(void) { return(rom_present(BIOS_067_AMA932J_PATH)); } - static int oti067_077_available(void) { return(rom_present(BIOS_077_PATH)); } +static int +oti067_m300_available(void) +{ + if (rom_present(BIOS_067_M300_15_PATH)) + return(rom_present(BIOS_067_M300_15_PATH)); + else + return(rom_present(BIOS_067_M300_08_PATH)); +} + static const device_config_t oti067_config[] = { @@ -569,6 +589,18 @@ const device_t oti067_device = oti067_config }; +const device_t oti067_m300_device = +{ + "Oak OTI-067 (Olivetti M300-08/15)", + DEVICE_ISA, + 4, + oti_init, oti_close, NULL, + { oti067_m300_available }, + oti_speed_changed, + oti_force_redraw, + oti067_config +}; + const device_t oti067_ama932j_device = { "Oak OTI-067 (AMA-932J)", diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index f64b30fd3..7dff04e4a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -2801,8 +2801,6 @@ static void s3_recalctimings(svga_t *svga) s3_t *s3 = (s3_t *)svga->p; int clk_sel = (svga->miscout >> 2) & 3; - svga->hdisp = svga->hdisp_old; - if (!svga->scrblank && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { if (svga->crtc[0x3a] & 0x10) { /*256+ color register*/ @@ -2812,12 +2810,13 @@ static void s3_recalctimings(svga_t *svga) } svga->ma_latch |= (s3->ma_ext << 16); - if (s3->chip >= S3_86C928) { + svga->hdisp = svga->hdisp_old; + if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * svga->dots_per_clock; + svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; if (svga->crtc[0x5e] & 0x02) svga->dispend |= 0x400; @@ -2826,7 +2825,7 @@ static void s3_recalctimings(svga_t *svga) if (svga->crtc[0x5e] & 0x40) svga->split |= 0x400; if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; - } else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; + } if (!svga->rowoffset) svga->rowoffset = 256; if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { @@ -3066,28 +3065,6 @@ static void s3_recalctimings(svga_t *svga) } } } - - if (s3->chip >= S3_86C801) { - if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); - } - - if (svga->crtc[0x5d] & 0x04) - svga->hblankstart += 0x100; - if (s3->chip >= S3_VISION964) { - /* NOTE: The S3 Trio64V+ datasheet says this is bit 7, but then where is bit 6? - The datasheets for the pre-Trio64V+ cards say +64, which implies bit 6, - and, contrary to VGADOC, it also exists on Trio32, Trio64, Vision868, - and Vision968. */ - // pclog("svga->crtc[0x5d] = %02X\n", svga->crtc[0x5d]); - if (svga->crtc[0x5d] & 0x08) - svga->hblank_ext = 0x40; - svga->hblank_end_len = 0x00000040; - } - } - - svga->hblank_overscan = !(svga->crtc[0x33] & 0x20); } static void s3_trio64v_recalctimings(svga_t *svga) @@ -8138,3 +8115,4 @@ const device_t s3_trio64v2_dx_onboard_pci_device = s3_force_redraw, s3_standard_config }; + diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 8ec5c978d..b1d446829 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -20,13 +20,11 @@ * Copyright 2016-2019 Miran Grca. */ #include -#include #include #include -#include #include +#include #include -#define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/device.h> @@ -55,27 +53,6 @@ uint8_t svga_rotate[8][256]; static svga_t *svga_pri; -// #define ENABLE_SVGA_LOG 1 -#ifdef ENABLE_SVGA_LOG -int svga_do_log = ENABLE_SVGA_LOG; - - -static void -svga_log(const char *fmt, ...) -{ - va_list ap; - - if (svga_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define svga_log(fmt, ...) -#endif - - svga_t *svga_get_pri() { @@ -199,7 +176,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) break; case 4: svga->chain2_write = !(val & 4); - svga->chain4 = (svga->chain4 & ~8) | (val & 8); + svga->chain4 = val & 8; svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); break; @@ -260,7 +237,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) break; case 6: if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { - switch (val & 0xc) { + switch (val&0xC) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; @@ -291,9 +268,6 @@ svga_out(uint16_t addr, uint8_t val, void *p) ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); break; - case 0x3da: - svga->fcr = val; - break; } } @@ -361,9 +335,6 @@ svga_in(uint16_t addr, void *p) if (svga->adv_flags & FLAG_RAMDAC_SHIFT) ret >>= 2; break; - case 0x3ca: - ret = svga->fcr; - break; case 0x3cc: ret = svga->miscout; break; @@ -397,11 +368,7 @@ svga_in(uint16_t addr, void *p) svga->cgastat &= ~0x30; else svga->cgastat ^= 0x30; - ret = svga->cgastat; - - if ((svga->fcr & 0x08) && svga->dispon) - ret |= 0x08; break; } @@ -433,10 +400,6 @@ void svga_recalctimings(svga_t *svga) { double crtcconst, _dispontime, _dispofftime, disptime; -#ifdef ENABLE_SVGA_LOG - int vsyncend, vblankend; - int hdispstart, hdispend, hsyncstart, hsyncend; -#endif svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; @@ -474,9 +437,12 @@ svga_recalctimings(svga_t *svga) svga->vblankstart |= 0x200; svga->vblankstart++; - svga->hdisp = svga->crtc[1] - ((svga->crtc[3] & 0x60) >> 5); + svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); svga->hdisp++; + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + svga->rowoffset = svga->crtc[0x13]; svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; @@ -493,19 +459,20 @@ svga_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; if (!svga->scrblank && svga->attr_palette_enable) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - if (svga->seqregs[1] & 8) - svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; - else - svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ + if (svga->seqregs[1] & 8) /*40 column*/ { svga->render = svga_render_text_40; - else + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + /* Character clock is off by 1 now in 40-line modes, on all cards. */ + svga->ma_latch--; + svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; + } else { svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } svga->hdisp_old = svga->hdisp; } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; svga->hdisp_old = svga->hdisp; switch (svga->gdcreg[5] & 0x60) { @@ -567,7 +534,7 @@ svga_recalctimings(svga_t *svga) } svga->linedbl = svga->crtc[9] & 0x80; - svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; + svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; if (enable_overscan) { overscan_y = (svga->rowcount + 1) << 1; @@ -584,41 +551,9 @@ svga_recalctimings(svga_t *svga) } else overscan_x = 16; - svga->htotal = svga->crtc[0]; - svga->hblankstart = svga->crtc[4] + 1; - svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00); - // pclog("htotal = %i, hblankstart = %i, hblank_end_val = %02X\n", svga->htotal, svga->hblankstart, svga->hblank_end_val); - svga->hblank_end_len = 0x00000040; - svga->hblank_overscan = 1; - - if (!svga->scrblank && svga->attr_palette_enable) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - if (svga->seqregs[1] & 8) - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); - else - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); - } else - svga->dots_per_clock = 1; - - /* Do svga->recalctimings_ex() here so that the above five variables can be - updated by said function. */ if (svga->recalctimings_ex) svga->recalctimings_ex(svga); - svga->htotal += 6; /*+6 is required for Tyrian*/ - svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; - if (svga->hblankend <= svga->hblankstart) - svga->hblankend += svga->hblank_end_len; - svga->hblankend += svga->hblank_ext; - - svga->hblank_sub = 0; - if (svga->hblankend > svga->htotal) { - svga->hblankend &= (svga->hblank_end_len - 1); - svga->hblank_sub = svga->hblankend + svga->hblank_overscan; - - svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); - } - svga->y_add = (overscan_y >> 1) - (svga->crtc[8] & 0x1f); svga->x_add = (overscan_x >> 1); @@ -627,44 +562,6 @@ svga_recalctimings(svga_t *svga) crtcconst = svga->clock * svga->char_width; -#ifdef ENABLE_SVGA_LOG - vsyncend = (svga->vsyncstart & 0xfffffff0) | (svga->crtc[0x11] & 0x0f); - if (vsyncend <= svga->vsyncstart) - vsyncend += 0x00000010; - vblankend = (svga->vblankstart & 0xffffff80) | (svga->crtc[0x16] & 0x7f); - if (vblankend <= svga->vblankstart) - vblankend += 0x00000080; - - hdispstart = ((svga->crtc[3] >> 5) & 3); - hdispend = svga->crtc[1] + 1; - hsyncstart = svga->crtc[4] + ((svga->crtc[5] >> 5) & 3) + 1; - hsyncend = (hsyncstart & 0xffffffe0) | (svga->crtc[5] & 0x1f); - if (hsyncend <= hsyncstart) - hsyncend += 0x00000020; -#endif - - svga_log("Last scanline in the vertical period: %i\n" - "First scanline after the last of active display: %i\n" - "First scanline with vertical retrace asserted: %i\n" - "First scanline after the last with vertical retrace asserted: %i\n" - "First scanline of blanking: %i\n" - "First scanline after the last of blanking: %i\n" - "\n" - "Last character in the horizontal period: %i\n" - "First character of active display: %i\n" - "First character after the last of active display: %i\n" - "First character with horizontal retrace asserted: %i\n" - "First character after the last with horizontal retrace asserted: %i\n" - "First character of blanking: %i\n" - "First character after the last of blanking: %i\n" - "\n" - "\n", - svga->vtotal, svga->dispend, svga->vsyncstart, vsyncend, - svga->vblankstart, vblankend, - svga->htotal, hdispstart, hdispend, hsyncstart, hsyncend, - svga->hblankstart, svga->hblankend - ); - disptime = svga->htotal; _dispontime = svga->hdisp_time; @@ -750,8 +647,6 @@ svga_poll(void *p) uint32_t x, blink_delay; int wx, wy; int ret, old_ma; - // int lines_num = (svga->vtotal > svga->vsyncstart) ? svga->vtotal : svga->vsyncstart; - // int lines_num = svga->vsyncstart + 3 + 19; if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { @@ -830,7 +725,7 @@ svga_poll(void *p) svga->displine++; if (svga->interlace) svga->displine++; - if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15))) + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) svga->cgastat &= ~8; svga->vslines++; if (svga->displine > 1500) @@ -882,12 +777,11 @@ svga_poll(void *p) if (ret) { if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; + svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); else - svga->ma = svga->maback = ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; + svga->ma = svga->maback = ((svga->crtc[5] & 0x60) >> 5); svga->ma = (svga->ma << 2); svga->maback = (svga->maback << 2); - svga->sc = 0; if (svga->attrregs[0x10] & 0x20) { svga->scrollcache = 0; @@ -952,9 +846,9 @@ svga_poll(void *p) svga->vslines = 0; if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); else - svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; + svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); svga->ca = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + ((svga->crtc[0xb] & 0x60) >> 5) + svga->ca_adj; svga->ma = (svga->ma << 2); @@ -964,7 +858,6 @@ svga_poll(void *p) if (svga->vsync_callback) svga->vsync_callback(svga); } - // if (svga->vc == lines_num) { if (svga->vc == svga->vtotal) { svga->vc = 0; svga->sc = 0; @@ -1084,7 +977,6 @@ svga_init(const device_t *info, svga_t *svga, void *p, int memsize, svga->ramdac_type = RAMDAC_6BIT; svga->map8 = svga->pallook; - svga->hblank_overscan = 1; /* Do at least 1 character of overscan after horizontal blanking. */ return 0; } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index e5cd12f9a..32865df01 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -112,8 +112,6 @@ video_cards[] = { { "tvga9000b", &tvga9000b_device }, { "tgkorvga", &et4000k_isa_device }, { "et2000", &et2000_device }, - { "et3000ax", &et3000_isa_device }, - { "et4000ax_tc6058af", &et4000_tc6058af_isa_device }, { "et4000ax", &et4000_isa_device }, { "et4000w32", &et4000w32_device }, { "et4000w32i", &et4000w32i_isa_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 068562028..bdc3d1246 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -744,7 +744,6 @@ VIDOBJ := video.o \ vid_bt48x_ramdac.o \ vid_av9194.o vid_icd2061.o vid_ics2494.o vid_ics2595.o \ vid_cl54xx.o \ - vid_et3000.o \ vid_et4000.o vid_sc1148x_ramdac.o \ vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ From 3e70c7e98a2cceed896cdde62bab59651290664b Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 13 Nov 2021 17:33:43 -0500 Subject: [PATCH 133/140] Trivial fixes and cleanups for serial & parallel --- src/config.c | 10 +++++----- src/device/serial.c | 16 ++-------------- src/include/86box/config.h | 4 ++-- src/include/86box/serial.h | 4 +++- src/machine/m_pcjr.c | 2 +- src/machine/m_xt_zenith.c | 2 +- 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/config.c b/src/config.c index 0bd8dbfe3..872ed41a2 100644 --- a/src/config.c +++ b/src/config.c @@ -1042,12 +1042,12 @@ load_ports(void) char temp[512]; int c, d; - for (c = 0; c < 4; c++) { + for (c = 0; c < SERIAL_MAX; c++) { sprintf(temp, "serial%d_enabled", c + 1); serial_enabled[c] = !!config_get_int(cat, temp, (c >= 2) ? 0 : 1); } - for (c = 0; c < 3; c++) { + for (c = 0; c < PARALLEL_MAX; c++) { sprintf(temp, "lpt%d_enabled", c + 1); lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); @@ -1059,7 +1059,7 @@ load_ports(void) /* Legacy config compatibility. */ d = config_get_int(cat, "lpt_enabled", 2); if (d < 2) { - for (c = 0; c < 3; c++) + for (c = 0; c < PARALLEL_MAX; c++) lpt_ports[c].enabled = d; } config_delete_var(cat, "lpt_enabled"); @@ -2512,7 +2512,7 @@ save_ports(void) char temp[512]; int c, d; - for (c = 0; c < 4; c++) { + for (c = 0; c < SERIAL_MAX; c++) { sprintf(temp, "serial%d_enabled", c + 1); if (((c < 2) && serial_enabled[c]) || ((c >= 2) && !serial_enabled[c])) config_delete_var(cat, temp); @@ -2520,7 +2520,7 @@ save_ports(void) config_set_int(cat, temp, serial_enabled[c]); } - for (c = 0; c < 3; c++) { + for (c = 0; c < PARALLEL_MAX; c++) { sprintf(temp, "lpt%d_enabled", c + 1); d = (c == 0) ? 1 : 0; if (lpt_ports[c].enabled == d) diff --git a/src/device/serial.c b/src/device/serial.c index 3de0c6826..15527fad4 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -717,20 +717,8 @@ serial_set_next_inst(int ni) void serial_standalone_init(void) { - if (next_inst == 0) { - device_add_inst(&i8250_device, 1); - device_add_inst(&i8250_device, 2); - device_add_inst(&i8250_device, 3); - device_add_inst(&i8250_device, 4); - } else if (next_inst == 1) { - device_add_inst(&i8250_device, 2); - device_add_inst(&i8250_device, 3); - device_add_inst(&i8250_device, 4); - } else if (next_inst == 2) { - device_add_inst(&i8250_device, 3); - device_add_inst(&i8250_device, 4); - } else - device_add_inst(&i8250_device, 4); + for ( ; next_inst < 4; ) + device_add_inst(&i8250_device, next_inst + 1); }; diff --git a/src/include/86box/config.h b/src/include/86box/config.h index 549306daa..b630d0c80 100644 --- a/src/include/86box/config.h +++ b/src/include/86box/config.h @@ -110,9 +110,9 @@ typedef struct { /* Ports category */ char parallel_devices[3][32]; /* LPT device names */ #ifdef USE_SERIAL_DEVICES - char serial_devices[2][32]; /* Serial device names */ + char serial_devices[4][32]; /* Serial device names */ #endif - int serial_enabled[2], /* Serial ports 1 and 2 enabled */ + int serial_enabled[4], /* Serial ports 1 and 2 enabled */ parallel_enabled[3]; /* LPT1, LPT2, LPT3 enabled */ /* Other peripherals category */ diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index 0b6b99aa5..f580f9f9f 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -27,6 +27,8 @@ #define SERIAL_NS16450 2 #define SERIAL_NS16550 3 +#define SERIAL_FIFO_SIZE 16 + /* Default settings for the standard ports. */ #define SERIAL1_ADDR 0x03f8 #define SERIAL1_IRQ 4 @@ -54,7 +56,7 @@ typedef struct serial_s uint8_t rcvr_fifo_pos, xmit_fifo_pos, pad0, pad1, - rcvr_fifo[16], xmit_fifo[16]; + rcvr_fifo[SERIAL_FIFO_SIZE], xmit_fifo[SERIAL_FIFO_SIZE]; pc_timer_t transmit_timer, timeout_timer; double clock_src, transmit_period; diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 35ddfe6da..482c26ed6 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -867,7 +867,7 @@ machine_pcjr_init(const machine_t *model) device_add(&fdc_pcjr_device); device_add(&i8250_pcjr_device); - serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + serial_set_next_inst(MAX_SERIAL); /* So that serial_standalone_init() won't do anything. */ return ret; } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index 1ca553227..791ebdcd1 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -154,7 +154,7 @@ machine_xt_z184_init(const machine_t *model) lpt2_remove(); lpt1_init(0x278); device_add(&i8250_device); - serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + serial_set_next_inst(MAX_SERIAL); /* So that serial_standalone_init() won't do anything. */ device_add(&cga_device); From bf3767bc4a08c9404daf65bc69a2e4f4634033d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 23:51:03 +0100 Subject: [PATCH 134/140] Make more descriptive help for --lang --- src/86box.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index 16c4ab4ce..1f38b2e98 100644 --- a/src/86box.c +++ b/src/86box.c @@ -434,7 +434,7 @@ usage: printf("-E or --nographic - forces the old behavior\n"); #endif printf("-F or --fullscreen - start in fullscreen mode\n"); - printf("-G or --lang langid - start the application with the specified language\n"); + printf("-G or --lang langid - start with specified language (e.g. en-US, or system)\n"); #ifdef _WIN32 printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); #endif From dfa795b26745ff1512e25403089cae0f3df80aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 23:51:29 +0100 Subject: [PATCH 135/140] Add reverse conversion from string to LCID --- src/include/86box/plat.h | 1 + src/win/win.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 148b396c3..ca116a684 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -123,6 +123,7 @@ extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); extern void plat_vid_reload_options(void); extern uint32_t plat_language_code(char* langcode); +extern void plat_language_code_r(uint32_t lcid, char* outbuf, int len); /* Resource management. */ extern void set_language(uint32_t id); diff --git a/src/win/win.c b/src/win/win.c index 4c8e7ac27..80708a5ca 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -1221,6 +1221,22 @@ plat_language_code(char* langcode) return lcid; } +/* Converts back the language code to LCID */ +void +plat_language_code_r(uint32_t lcid, char* outbuf, int len) +{ + if (lcid == 0xFFFF) + { + strcpy(outbuf, "system"); + return; + } + + wchar_t buffer[LOCALE_NAME_MAX_LENGTH + 1]; + LCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0); + + c16stombs(outbuf, buffer, len); +} + void take_screenshot(void) { From 0ba4718fb7c0d4b8902640ff1714c34156079db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 23:52:49 +0100 Subject: [PATCH 136/140] Save config language entry as string instead of hex16 And remove some unnecessary stuff. --- src/config.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/config.c b/src/config.c index 499624f50..bb6427aaa 100644 --- a/src/config.c +++ b/src/config.c @@ -567,7 +567,11 @@ load_general(void) confirm_exit = config_get_int(cat, "confirm_exit", 1); confirm_save = config_get_int(cat, "confirm_save", 1); - lang_id = config_get_hex16(cat, "language", DEFAULT_LANGUAGE); + p = config_get_string(cat, "language", NULL); + if (p != NULL) + { + lang_id = plat_language_code(p); + } #if USE_DISCORD enable_discord = !!config_get_int(cat, "enable_discord", 0); @@ -1995,9 +1999,7 @@ config_load(void) cpu_f = (cpu_family_t *) &cpu_families[0]; cpu = 0; -#ifdef USE_LANGUAGE - plat_langid = 0x0409; -#endif + kbd_req_capture = 0; hide_status_bar = 0; scale = 1; @@ -2207,7 +2209,11 @@ save_general(void) if (lang_id == DEFAULT_LANGUAGE) config_delete_var(cat, "language"); else - config_set_hex16(cat, "language", lang_id); + { + char buffer[512] = {0}; + plat_language_code_r(lang_id, buffer, 511); + config_set_string(cat, "language", buffer); + } #if USE_DISCORD if (enable_discord) From b321679bde26aed423c24ed1cd83411b78ae4f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laci=20b=C3=A1?= Date: Sat, 13 Nov 2021 23:56:35 +0100 Subject: [PATCH 137/140] Final cleanup --- src/86box.c | 3 --- src/config.c | 2 -- src/win/win.c | 2 -- src/win/win_lang.c | 8 -------- 4 files changed, 15 deletions(-) diff --git a/src/86box.c b/src/86box.c index 1f38b2e98..763d41cd3 100644 --- a/src/86box.c +++ b/src/86box.c @@ -707,17 +707,14 @@ usage: config_load(); /* Load the desired language */ - pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); if (lang_init) lang_id = lang_init; - pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); lang_init = lang_id; lang_id = 0; if (lang_init) set_language(lang_init); - pclog("lang_init %u, lang_id: %u\n", lang_init, lang_id); /* All good! */ return(1); } diff --git a/src/config.c b/src/config.c index bb6427aaa..fa6b69d1d 100644 --- a/src/config.c +++ b/src/config.c @@ -2939,8 +2939,6 @@ save_other_removable_devices(void) void config_save(void) { - pclog("config_save"); - save_general(); /* General */ save_machine(); /* Machine */ save_video(); /* Video */ diff --git a/src/win/win.c b/src/win/win.c index 80708a5ca..a6845424c 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -245,7 +245,6 @@ size_t c16stombs(char dst[], const uint16_t src[], int len) int has_language_changed(uint32_t id) { - pclog("has_language_changed? lang_id:%u == id:%u?\n", lang_id, id); return (lang_id != id); } @@ -254,7 +253,6 @@ has_language_changed(uint32_t id) void set_language(uint32_t id) { - pclog("set_language %u, lang_id %u\n", id, lang_id); if (id == 0xFFFF) { set_language(lang_sys); diff --git a/src/win/win_lang.c b/src/win/win_lang.c index 805856b6d..29f5dfe9b 100644 --- a/src/win/win_lang.c +++ b/src/win/win_lang.c @@ -50,7 +50,6 @@ EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLan SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)dispname); SendMessage((HWND)lParam, CB_SETITEMDATA, c, (LPARAM)wIDLanguage); - pclog("widl: %u, langid: %u, c: %u\n", wIDLanguage, lang_id, c); if (wIDLanguage == lang_id) enum_helper = c; c++; @@ -73,10 +72,8 @@ progsett_fill_languages(HWND hdlg) //if no one is selected, then it was 0xFFFF or unsupported language, in either case go with index enum_helper=0 //also start enum index from c=1 EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); - pclog("enum_helper is %d\n", enum_helper); SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); - pclog("win_fill_languages\n"); } /* This returns 1 if any variable has changed, 0 if not. */ @@ -109,8 +106,6 @@ progsett_settings_save(void) { /* Language */ set_language(temp_language); - - pclog("done"); /* Update title bar */ update_mouse_msg(); @@ -136,7 +131,6 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) hwndProgSett = hdlg; /* Language */ temp_language = lang_id; - pclog("temp_language is %u\n", lang_id); progsett_fill_languages(hdlg); break; @@ -157,7 +151,6 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG); int index = SendMessage(combo, CB_GETCURSEL, 0, 0); temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); - pclog("combobox changed -> temp_language = %u", temp_language); } break; @@ -166,7 +159,6 @@ ProgSettDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) int index = progsett_indexof(combo, DEFAULT_LANGUAGE); SendMessage(combo, CB_SETCURSEL, index, 0); temp_language = DEFAULT_LANGUAGE; - pclog("combobox changed -> temp_language = %u", temp_language); break; } default: From 41dccb5f6b48952f4c98f69500fae36f795a4d62 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 13 Nov 2021 18:02:56 -0500 Subject: [PATCH 138/140] EGA also supported 32K lines 194-205 appear to cover the memory window setting. --- src/video/vid_ega.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 61cf87ee0..1e66743ec 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1168,6 +1168,9 @@ static const device_config_t ega_config[] = { "memory", "Memory size", CONFIG_SELECTION, "", 256, "", { 0 }, { + { + "32 kB", 32 + }, { "64 kB", 64 }, From 1f5322959ab7bba708f2f3dd4a50bd09230b939e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 14 Nov 2021 00:12:49 +0100 Subject: [PATCH 139/140] Declared MAX_SERIAL. --- src/include/86box/serial.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index f580f9f9f..576c0c12e 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -39,6 +39,8 @@ #define SERIAL4_ADDR 0x02e8 #define SERIAL4_IRQ 3 +#define MAX_SERIAL 4 + struct serial_device_s; struct serial_s; From e24da32acf3007966e1076fe3d1c7216e395bf09 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 14 Nov 2021 00:16:09 +0100 Subject: [PATCH 140/140] Moved a code block behind an #ifdef. --- src/86box.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/86box.c b/src/86box.c index 00fc3222c..5efedc238 100644 --- a/src/86box.c +++ b/src/86box.c @@ -749,6 +749,7 @@ pc_init_modules(void) wchar_t temp[512]; char tempc[512]; +#ifdef PRINT_MISSING_MACHINES_AND_VIDEO_CARDS c = m = 0; while (machine_get_internal_name_ex(c) != NULL) { m = machine_available(c); @@ -768,6 +769,7 @@ pc_init_modules(void) pclog("Missing video card: %s\n", tempc); c++; } +#endif pc_log("Scanning for ROM images:\n"); c = m = 0;