From 7ebe8f50184949ab1d7fa5fd317787b4f53ceae8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 10 Jul 2020 04:23:10 +0200 Subject: [PATCH] Vastly improved the STPC PCI IDE controller emulation. --- src/chipset/stpc.c | 119 ++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 81262b993..4e6b4cb9c 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -67,10 +67,10 @@ typedef struct stpc_t uint8_t pci_conf[4][256]; usb_t *usb; int ide_slot; + sff8038i_t *bm[2]; } stpc_t; -#define ENABLE_STPC_LOG 1 #ifdef ENABLE_STPC_LOG int stpc_do_log = ENABLE_STPC_LOG; @@ -261,30 +261,6 @@ stpc_nb_read(int func, int addr, void *priv) } -void -stpc_ide_irq(int channel, void *priv) -{ - stpc_t *dev = (stpc_t *) priv; - - uint8_t status = (channel >> 4); - channel &= 0x01; - dev->pci_conf[2][0x48] &= ~(1 << channel); - - if (status) { - dev->pci_conf[2][0x48] |= (1 << channel); - if (dev->pci_conf[2][0x09] & (1 << (channel << 1))) - pci_set_irq(dev->ide_slot, PCI_INTA); - else - picint(1 << (14 + channel)); - } else { - if (dev->pci_conf[2][0x09] & (1 << (channel << 1))) - pci_clear_irq(dev->ide_slot, PCI_INTA); - else - picintc(1 << (14 + channel)); - } -} - - static void stpc_ide_handlers(stpc_t *dev, int bus) { @@ -338,6 +314,16 @@ stpc_ide_handlers(stpc_t *dev, int bus) } +static void +stpc_ide_bm_handlers(stpc_t *dev) +{ + uint16_t base = (dev->pci_conf[2][0x20] & 0xf0) | (dev->pci_conf[2][0x21] << 8); + + sff_bus_master_handler(dev->bm[0], (dev->pci_conf[2][0x04] & 1), base); + sff_bus_master_handler(dev->bm[1], (dev->pci_conf[2][0x04] & 1), base + 8); +} + + static void stpc_ide_write(int func, int addr, uint8_t val, void *priv) { @@ -349,26 +335,22 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) return; switch (addr) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x06: case 0x07: case 0x08: case 0x0a: - case 0x0b: case 0x0e: - case 0x30: case 0x31: case 0x32: case 0x33: /* unknown registers written to by Windows 2000 */ - return; - case 0x04: - val &= 0x41; - dev->pci_conf[2][addr] = val; + dev->pci_conf[2][addr] = (dev->pci_conf[2][addr] & 0xbe) | (val & 0x41); stpc_ide_handlers(dev, 0x03); + stpc_ide_bm_handlers(dev); break; case 0x05: - val &= 0x01; + dev->pci_conf[2][addr] = (val & 0x01); + break; + + case 0x07: + dev->pci_conf[2][addr] &= ~(val & 0x70); break; case 0x09: - val &= 0x05; - val |= 0x8a; - dev->pci_conf[2][addr] = val; + dev->pci_conf[2][addr] = (dev->pci_conf[2][addr] & 0x8a) | (val & 0x05); stpc_ide_handlers(dev, 0x03); break; @@ -376,7 +358,6 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[2][addr] = (val & 0xf8) | 1; stpc_ide_handlers(dev, 0x01); break; - case 0x11: dev->pci_conf[2][addr] = val; stpc_ide_handlers(dev, 0x01); @@ -386,7 +367,6 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[2][addr] = (val & 0xfc) | 1; stpc_ide_handlers(dev, 0x01); break; - case 0x15: dev->pci_conf[2][addr] = val; stpc_ide_handlers(dev, 0x01); @@ -396,7 +376,6 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[2][addr] = (val & 0xf8) | 1; stpc_ide_handlers(dev, 0x02); break; - case 0x19: dev->pci_conf[2][addr] = val; stpc_ide_handlers(dev, 0x02); @@ -406,24 +385,38 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) dev->pci_conf[2][addr] = (val & 0xfc) | 1; stpc_ide_handlers(dev, 0x02); break; - case 0x1d: dev->pci_conf[2][addr] = val; stpc_ide_handlers(dev, 0x02); break; - case 0x48: - val &= 0x8f; - if (val & 0x01) - val &= 0xfe; - if (val & 0x02) - val &= 0xfd; + case 0x20: + dev->pci_conf[2][0x20] = (val & 0xf0) | 1; + stpc_ide_bm_handlers(dev); + break; + case 0x21: + dev->pci_conf[2][0x21] = val; + stpc_ide_bm_handlers(dev); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: dev->pci_conf[2][addr] = val; + break; + + case 0x48: + dev->pci_conf[2][addr] = (val & 0x8c) & ~(val & 0x03); stpc_ide_handlers(dev, 0x03); + if (val & 0x02) { + sff_bus_master_set_irq(0x01, dev->bm[0]); + sff_bus_master_set_irq(0x01, dev->bm[1]); + } + if (val & 0x01) { + sff_bus_master_set_irq(0x00, dev->bm[0]); + sff_bus_master_set_irq(0x00, dev->bm[1]); + } break; } - - dev->pci_conf[2][addr] = val; } @@ -435,8 +428,14 @@ stpc_ide_read(int func, int addr, void *priv) if (func > 0) ret = 0xff; - else + else { ret = dev->pci_conf[2][addr]; + if (addr == 0x48) { + ret &= 0xfc; + ret |= (!!(dev->bm[0]->status & 0x04)); + ret |= ((!!(dev->bm[1]->status & 0x04)) << 1); + } + } stpc_log("STPC: ide_read(%d, %02X) = %02X\n", func, addr, ret); return ret; @@ -680,9 +679,6 @@ stpc_reset(void *priv) stpc_reg_read, NULL, NULL, stpc_reg_write, NULL, NULL, dev); io_sethandler(0x22, 2, stpc_reg_read, NULL, NULL, stpc_reg_write, NULL, NULL, dev); - - stpc_ide_irq(0x00, dev); - stpc_ide_irq(0x01, dev); } @@ -768,14 +764,6 @@ stpc_setup(stpc_t *dev) dev->pci_conf[2][0x46] = 0x60; dev->pci_conf[2][0x47] = 0x97; - ide_set_bus_master(0, NULL, stpc_ide_irq, dev); - ide_set_bus_master(1, NULL, stpc_ide_irq, dev); - - /* Initial datasheets indicated DMA support, but this was - later scrubbed. Assume DMA is broken in real hardware. */ - ide_board_set_force_ata3(0, 1); - ide_board_set_force_ata3(1, 1); - /* USB */ if (dev->usb) { dev->pci_conf[3][0x00] = 0x4a; @@ -831,6 +819,15 @@ stpc_init(const device_t *info) pci_add_card(0x0E, stpc_usb_read, stpc_usb_write, dev); } + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[0], 1, 0); + + sff_set_irq_mode(dev->bm[1], 0, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + stpc_setup(dev); stpc_reset(dev);