diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 32025b1b7..863234137 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -24,8 +24,8 @@ #include <86box/mem.h> #include <86box/io.h> #include <86box/rom.h> -#include <86box/pci.h> #include <86box/device.h> +#include <86box/pci.h> #include <86box/keyboard.h> #include <86box/chipset.h> #include <86box/spd.h> @@ -52,7 +52,7 @@ enum typedef struct { - uint8_t pm2_cntrl, max_func, + uint8_t pm2_cntrl, smram_locked, max_drb, drb_unit, drb_default; uint8_t regs[2][256], regs_locked[2][256]; @@ -277,7 +277,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) uint8_t *regs_l = (uint8_t *) dev->regs_locked[func]; int i; - if (func > dev->max_func) + if (func) return; if ((addr >= 0x10) && (addr < 0x4f)) @@ -447,7 +447,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x51] |= 0x10; /* Virtual PC 2007 BIOS requires a reserved bus speed bit to be set */ break; case INTEL_440GX: - regs[0x51] = (regs[0x50] & 0x88) | (val & 0x08); + regs[0x51] = (regs[0x50] & 0x88) | (val & 0x08); /*regs[0x51] = (regs[0x50] & 0x88) | (val & 0x77);*/ break; } @@ -1258,7 +1258,7 @@ i4x0_read(int func, int addr, void *priv) uint8_t ret = 0xff; uint8_t *regs = (uint8_t *) dev->regs[func]; - if (func > dev->max_func) + if (func) ret = 0xff; else { ret = regs[addr]; @@ -1298,8 +1298,7 @@ i4x0_reset(void *priv) } if ((dev->type == INTEL_440LX) || (dev->type == INTEL_440BX) || (dev->type == INTEL_440ZX)) { - for (i = 0; i <= dev->max_func; i++) - memset(dev->regs_locked[i], 0x00, 256 * sizeof(uint8_t)); + memset(dev->regs_locked[0], 0x00, 256 * sizeof(uint8_t)); } } @@ -1492,8 +1491,6 @@ static void dev->drb_default = 0x02; break; case INTEL_440LX: - dev->max_func = 1; - regs[0x02] = 0x80; regs[0x03] = 0x71; /* 82443LX */ regs[0x06] = 0x90; regs[0x10] = 0x08; @@ -1517,8 +1514,6 @@ static void dev->drb_default = 0x01; break; case INTEL_440EX: - dev->max_func = 1; - regs[0x02] = 0x80; regs[0x03] = 0x71; /* 82443EX. Same Vendor ID as 440LX */ regs[0x06] = 0x90; regs[0x10] = 0x08; @@ -1543,7 +1538,6 @@ static void break; case INTEL_440BX: case INTEL_440ZX: regs[0x7a] = (info->local >> 8) & 0xff; - dev->max_func = (regs[0x7a] & 0x02) ? 0 : 1; regs[0x02] = (regs[0x7a] & 0x02) ? 0x92 : 0x90; regs[0x03] = 0x71; /* 82443BX */ regs[0x06] = (regs[0x7a] & 0x02) ? 0x00 : 0x10; @@ -1574,7 +1568,6 @@ static void break; case INTEL_440GX: regs[0x7a] = (info->local >> 8) & 0xff; - dev->max_func = (regs[0x7a] & 0x02) ? 0 : 1; regs[0x02] = (regs[0x7a] & 0x02) ? 0xa2 : 0xa0; regs[0x03] = 0x71; /* 82443GX */ regs[0x06] = (regs[0x7a] & 0x02) ? 0x00 : 0x10; @@ -1617,42 +1610,13 @@ static void i4x0_write(regs[0x5f], 0x5f, 0x00, dev); i4x0_write(regs[0x72], 0x72, 0x00, dev); - if (((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX)) && (dev->max_func == 1)) { - regs = (uint8_t *) dev->regs[1]; - - regs[0x00] = 0x86; regs[0x01] = 0x80; /* Intel */ - regs[0x02] = 0x81; regs[0x03] = 0x71; /* 82443LX */ - regs[0x06] = 0xa0; regs[0x07] = 0x02; - regs[0x0a] = 0x04; regs[0x0b] = 0x06; - regs[0x0e] = 0x01; - regs[0x1c] = 0xf0; - regs[0x1e] = 0xa0; regs[0x1f] = 0x02; - regs[0x20] = 0xf0; regs[0x21] = 0xff; - regs[0x24] = 0xf0; regs[0x25] = 0xff; - } - - if (((dev->type == INTEL_440BX) || (dev->type == INTEL_440GX) || (dev->type == INTEL_440ZX)) && (dev->max_func == 1)) { - regs = (uint8_t *) dev->regs[1]; - - regs[0x00] = 0x86; regs[0x01] = 0x80; /* Intel */ - if(dev->type != INTEL_440GX) { - regs[0x02] = 0x91; regs[0x03] = 0x71; /* 82443BX */ - } else { - regs[0x02] = 0xa1; regs[0x03] = 0x71; /* 82443GX (They seem to share the same deal*/ - } - regs[0x06] = 0x20; regs[0x07] = 0x02; - regs[0x08] = 0x02; - regs[0x0a] = 0x04; regs[0x0b] = 0x06; - regs[0x0e] = 0x01; - regs[0x1c] = 0xf0; - regs[0x1e] = 0xa0; regs[0x1f] = 0x02; - regs[0x20] = 0xf0; regs[0x21] = 0xff; - regs[0x24] = 0xf0; regs[0x25] = 0xff; - regs[0x3e] = 0x80; - } - pci_add_card(PCI_ADD_NORTHBRIDGE, i4x0_read, i4x0_write, dev); + if ((dev->type >= INTEL_440BX) && !(regs[0x7a] & 0x02)) + device_add((dev->type == INTEL_440GX) ? &i440gx_agp_device : &i440bx_agp_device); + else if (dev->type >= INTEL_440LX) + device_add(&i440lx_agp_device); + return dev; } diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c new file mode 100644 index 000000000..367e36834 --- /dev/null +++ b/src/device/pci_bridge.c @@ -0,0 +1,325 @@ +/* + * 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 PCI-PCI and host-AGP bridges. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/machine.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/pci.h> + + +#define PCI_BRIDGE_DEC_21150 0x10110022 +#define AGP_BRIDGE_INTEL_440LX 0x80867181 +#define AGP_BRIDGE_INTEL_440BX 0x80867191 +#define AGP_BRIDGE_INTEL_440GX 0x808671a1 +#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_INTEL_440LX) + + +typedef struct +{ + uint32_t local; + uint8_t type; + + uint8_t regs[256]; + uint8_t bus_index; + int slot; +} pci_bridge_t; + + +#ifdef ENABLE_PCI_BRIDGE_LOG +int pci_bridge_do_log = ENABLE_PCI_BRIDGE_LOG; + + +static void +pci_bridge_log(const char *fmt, ...) +{ + va_list ap; + + if (pci_bridge_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pci_bridge_log(fmt, ...) +#endif + + +static void +pci_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + pci_bridge_log("PCI Bridge %d: write(%d, %02X, %02X)\n", dev->bus_index, func, addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x06: case 0x07: case 0x08: case 0x09: + case 0x0a: case 0x0b: case 0x0e: case 0x1e: + case 0x1f: case 0x34: case 0x3d: case 0x67: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + return; + + case 0x04: + val &= 0x67; + break; + + case 0x05: + val &= 0x03; + break; + + case 0x19: + /* Set our bus number. */ + pci_bridge_log("PCI Bridge %d: switching from bus %02X to %02X\n", dev->bus_index, dev->regs[addr], val); + if (dev->regs[addr]) + pci_bus_number_to_index_mapping[dev->regs[addr]] = 0xff; + if (val) + pci_bus_number_to_index_mapping[val] = dev->bus_index; + break; + + case 0x1c: case 0x1d: case 0x20: case 0x22: + case 0x24: case 0x26: + val &= 0xf0; + break; + + case 0x3e: + val &= 0xef; + break; + + case 0x3f: + val &= 0x0f; + break; + + case 0x40: + val &= 0x32; + break; + + case 0x41: + val &= 0x07; + break; + + case 0x43: + val &= 0x03; + break; + + case 0x64: + val &= 0x7e; + break; + + case 0x69: + val &= 0x3f; + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +pci_bridge_read(int func, int addr, void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + uint8_t ret; + + if (func > 0) + ret = 0xff; + else + ret = dev->regs[addr]; + + pci_bridge_log("PCI Bridge %d: read(%d, %02X) = %02X\n", dev->bus_index, func, addr, ret); + return ret; +} + + +static void +pci_bridge_reset(void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + pci_bridge_log("PCI Bridge %d: reset()\n", dev->bus_index); + + /* IDs */ + dev->regs[0x00] = dev->local >> 16; + dev->regs[0x01] = dev->local >> 24; + dev->regs[0x02] = dev->local; + dev->regs[0x03] = dev->local >> 8; + + switch (dev->local) { + case PCI_BRIDGE_DEC_21150: + dev->regs[0x06] = 0x80; + dev->regs[0x07] = 0x02; + break; + + case AGP_BRIDGE_INTEL_440LX: + dev->regs[0x06] = 0xa0; + dev->regs[0x07] = 0x02; + dev->regs[0x08] = 0x03; + break; + + case AGP_BRIDGE_INTEL_440BX: + case AGP_BRIDGE_INTEL_440GX: + dev->regs[0x06] = 0x20; + dev->regs[0x07] = dev->regs[0x08] = 0x02; + break; + } + + dev->regs[0x0a] = 0x04; /* PCI-PCI bridge */ + dev->regs[0x0b] = 0x06; /* bridge device */ + + dev->regs[0x0e] = 0x01; + + /* IO BARs */ + if (AGP_BRIDGE(dev->local)) { + dev->regs[0x1c] = 0xf0; + } else { + dev->regs[0x1c] = dev->regs[0x1d] = 0x01; + } + + dev->regs[0x1e] = AGP_BRIDGE(dev->local) ? 0xa0 : 0x80; + dev->regs[0x1f] = 0x02; + + /* prefetchable memory limits */ + if (AGP_BRIDGE(dev->local)) { + dev->regs[0x20] = dev->regs[0x24] = 0xf0; + dev->regs[0x21] = dev->regs[0x25] = 0xff; + } else { + dev->regs[0x24] = dev->regs[0x26] = 0x01; + } + + if (dev->local == AGP_BRIDGE_INTEL_440LX) + dev->regs[0x3e] = 0x80; + + if (dev->local == PCI_BRIDGE_DEC_21150) { + dev->regs[0x34] = 0xdc; + dev->regs[0x43] = 0x02; + dev->regs[0xdc] = dev->regs[0xde] = 0x01; + } +} + + +static void * +pci_bridge_init(const device_t *info) +{ + uint8_t interrupts[4], interrupt_count, interrupt_mask, slot_count, i; + + pci_bridge_t *dev = (pci_bridge_t *) malloc(sizeof(pci_bridge_t)); + memset(dev, 0, sizeof(pci_bridge_t)); + + dev->local = info->local; + dev->bus_index = last_pci_bus++; + pci_bridge_log("PCI Bridge %d: init()\n", dev->bus_index); + + pci_bridge_reset(dev); + + dev->slot = pci_add_card(AGP_BRIDGE(dev->local) ? 0x01 : 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); + 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) + slot_count = 9; /* 9 bus masters */ + else + slot_count = 1; /* AGP bridges always have 1 slot */ + + for (i = 0; i < slot_count; i++) { + /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ + pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); + pci_register_bus_slot(dev->bus_index, i, /*AGP_BRIDGE(dev->local) ? PCI_CARD_SPECIAL : */PCI_CARD_NORMAL, + interrupts[i & interrupt_mask], + interrupts[(i + 1) & interrupt_mask], + interrupts[(i + 2) & interrupt_mask], + interrupts[(i + 3) & interrupt_mask]); + } + + return dev; +} + + +/* PCI bridges */ +const device_t dec21150_device = +{ + "DEC 21150 PCI Bridge", + DEVICE_PCI, + PCI_BRIDGE_DEC_21150, + pci_bridge_init, + NULL, + pci_bridge_reset, + NULL, + NULL, + NULL, + NULL +}; + +/* AGP bridges */ +const device_t i440lx_agp_device = +{ + "Intel 82443LX AGP Bridge", + DEVICE_PCI, + AGP_BRIDGE_INTEL_440LX, + pci_bridge_init, + NULL, + pci_bridge_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t i440bx_agp_device = +{ + "Intel 82443BX AGP Bridge", + DEVICE_PCI, + AGP_BRIDGE_INTEL_440BX, + pci_bridge_init, + NULL, + pci_bridge_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t i440gx_agp_device = +{ + "Intel 82443GX AGP Bridge", + DEVICE_PCI, + AGP_BRIDGE_INTEL_440GX, + pci_bridge_init, + NULL, + pci_bridge_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index a36eae830..131471cb0 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -64,7 +64,8 @@ enum { PCI_ADD_VIDEO, PCI_ADD_SCSI, PCI_ADD_SOUND, - PCI_ADD_IDE + PCI_ADD_IDE, + PCI_ADD_BRIDGE }; typedef union { @@ -75,6 +76,8 @@ typedef union { extern int pci_burst_time, pci_nonburst_time; +extern uint8_t last_pci_bus; +extern uint8_t pci_bus_number_to_index_mapping[256]; extern void pci_set_irq_routing(int pci_int, int irq); @@ -88,16 +91,19 @@ extern uint8_t pci_use_mirq(uint8_t mirq); extern int pci_irq_is_level(int irq); extern void pci_set_mirq(uint8_t mirq, int level); -extern void pci_set_irq(uint8_t card, uint8_t pci_int); +extern void pci_set_irq(int card, uint8_t pci_int); extern void pci_clear_mirq(uint8_t mirq, int level); -extern void pci_clear_irq(uint8_t card, uint8_t pci_int); +extern void pci_clear_irq(int card, uint8_t pci_int); +extern uint8_t pci_get_int(int card, uint8_t pci_int); extern void pci_reset(void); extern void pci_init(int type); extern void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd); +extern void pci_register_bus_slot(int bus, int card, int type, + int inta, int intb, int intc, int intd); extern void pci_close(void); -extern uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +extern int pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); extern void trc_init(void); @@ -110,4 +116,13 @@ extern void elcr_write(uint16_t port, uint8_t val, void *priv); extern uint8_t elcr_read(uint16_t port, void *priv); +#ifdef EMU_DEVICE_H +extern const device_t dec21150_device; + +extern const device_t i440lx_agp_device; +extern const device_t i440bx_agp_device; +extern const device_t i440gx_agp_device; +#endif + + #endif /*EMU_PCI_H*/ diff --git a/src/pci.c b/src/pci.c index 6001406cd..19207c525 100644 --- a/src/pci.c +++ b/src/pci.c @@ -37,7 +37,7 @@ typedef struct { - uint8_t id, type; + uint8_t bus, id, type; uint8_t irq_routing[4]; void *priv; @@ -53,10 +53,12 @@ typedef struct { int pci_burst_time, pci_nonburst_time; +uint8_t last_pci_bus = 1; +uint8_t pci_bus_number_to_index_mapping[256]; static pci_card_t pci_cards[32]; -static uint8_t pci_pmc = 0, last_pci_card = 0; -static uint8_t pci_card_to_slot_mapping[32]; +static uint8_t pci_pmc = 0, last_pci_card = 0, last_normal_pci_card = 0; +static uint8_t pci_card_to_slot_mapping[256][32]; static uint8_t elcr[2] = { 0, 0 }; static uint8_t pci_irqs[4], pci_irq_level[4]; static uint64_t pci_irq_hold[16]; @@ -121,7 +123,7 @@ pci_write(uint16_t port, uint8_t val, void *priv) uint8_t slot = 0; if (in_smm) - pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); switch (port) { case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: @@ -129,24 +131,22 @@ pci_write(uint16_t port, uint8_t val, void *priv) return; pci_log("Writing %02X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index); - if (! pci_bus) { - slot = pci_card_to_slot_mapping[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); - pci_cards[slot].write(pci_func, pci_index | (port & 3), val, 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); -#endif + 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); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); } #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); + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #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); +#endif + break; } } @@ -166,25 +166,23 @@ pci_read(uint16_t port, void *priv) if (! pci_enable) return 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[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); -#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); -#endif - } + 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); #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); + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #endif } - - pci_log("Reading %02X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index); +#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); +#endif } + pci_log("Reading %02X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index); + return ret; } @@ -285,21 +283,19 @@ pci_type2_write(uint16_t port, uint8_t val, void *priv) pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].write) - pci_cards[slot].write(pci_func, pci_index | (port & 3), val, 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); -#endif - } + 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_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); #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); + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #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); +#endif } } @@ -319,21 +315,19 @@ pci_type2_read(uint16_t port, void *priv) pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].read) - return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); -#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); -#endif - } + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) + return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); #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); + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #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); +#endif return 0xff; } @@ -450,7 +444,7 @@ pci_set_mirq(uint8_t mirq, int level) void -pci_set_irq(uint8_t card, uint8_t pci_int) +pci_set_irq(int card, uint8_t pci_int) { uint8_t slot = 0; uint8_t irq_routing = 0; @@ -464,7 +458,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } pci_log("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = pci_card_to_slot_mapping[(card >> 5) & 0xff][card & 31]; if (slot == 0xff) { pci_log("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); return; @@ -492,7 +486,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } else pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << card))) { + if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << slot))) { /* IRQ already held, do nothing. */ pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); return; @@ -514,7 +508,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) /* If the IRQ is level-triggered, mark that this card is holding it. */ if (level) { pci_log("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] |= (1ULL << card); + pci_irq_hold[irq_line] |= (1ULL << slot); } else { pci_log("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); } @@ -556,7 +550,7 @@ pci_clear_mirq(uint8_t mirq, int level) if (! pci_irq_hold[irq_line]) { pci_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq); - picintc(1 << irq_line); + picintc(1 << irq_line); } else { pci_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq); } @@ -568,7 +562,7 @@ pci_clear_mirq(uint8_t mirq, int level) void -pci_clear_irq(uint8_t card, uint8_t pci_int) +pci_clear_irq(int card, uint8_t pci_int) { uint8_t slot = 0; uint8_t irq_routing = 0; @@ -582,7 +576,7 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) } pci_log("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = pci_card_to_slot_mapping[(card >> 5) & 0xff][card & 31]; if (slot == 0xff) { pci_log("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); return; @@ -611,7 +605,7 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (level && !(pci_irq_hold[irq_line] & (1ULL << card))) { + if (level && !(pci_irq_hold[irq_line] & (1ULL << slot))) { /* IRQ not held, do nothing. */ pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); return; @@ -619,11 +613,11 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) if (level) { pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] &= ~(1 << card); + pci_irq_hold[irq_line] &= ~(1 << slot); if (! pci_irq_hold[irq_line]) { pci_log("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); - picintc(1 << irq_line); + picintc(1 << irq_line); } else { pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); } @@ -634,6 +628,17 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) } +uint8_t +pci_get_int(int card, uint8_t pci_int) +{ + uint8_t slot = pci_card_to_slot_mapping[(card >> 5) & 0xff][card & 31]; + if (slot == 0xff) + return 0xff; + + return pci_cards[slot].irq_routing[pci_int - PCI_INTA]; +} + + void pci_elcr_set_enabled(int enabled) { @@ -704,7 +709,7 @@ pci_slots_clear(void) { uint8_t i, j; - last_pci_card = 0; + last_pci_card = last_normal_pci_card = 0; for (i = 0; i < 32; i++) { pci_cards[i].id = 0xFF; @@ -716,9 +721,16 @@ pci_slots_clear(void) pci_cards[i].read = NULL; pci_cards[i].write = NULL; pci_cards[i].priv = NULL; - - pci_card_to_slot_mapping[i] = 0xFF; } + + i = 0; + do { + for (j = 0; j < 32; j++) + pci_card_to_slot_mapping[i][j] = 0xFF; + pci_bus_number_to_index_mapping[i] = 0xFF; + } while (i++ < 0xff); + + pci_bus_number_to_index_mapping[0] = 0; /* always map bus 0 to index 0 */ } @@ -858,9 +870,17 @@ pci_init(int type) void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) +{ + pci_register_bus_slot(0, card, type, inta, intb, intc, intd); +} + + +void +pci_register_bus_slot(int bus, int card, int type, int inta, int intb, int intc, int intd) { pci_card_t *dev = &pci_cards[last_pci_card]; + dev->bus = bus; dev->id = card; dev->type = type; dev->irq_routing[0] = inta; @@ -870,15 +890,17 @@ pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) dev->read = NULL; dev->write = NULL; dev->priv = NULL; - pci_card_to_slot_mapping[card] = last_pci_card; + pci_card_to_slot_mapping[bus][card] = last_pci_card; - pci_log("pci_register_slot(): pci_cards[%i].id = %02X\n", last_pci_card, card); + pci_log("pci_register_slot(): pci_cards[%i].bus = %02X; .id = %02X\n", last_pci_card, bus, card); + if (type == PCI_CARD_NORMAL) + last_normal_pci_card = last_pci_card; last_pci_card++; } -uint8_t +int pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) { pci_card_t *dev; @@ -889,12 +911,12 @@ pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), if (! PCI) { pci_log("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return 0xff; + return 0xffff; } if (! last_pci_card) { pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return 0xff; + return 0xffff; } for (i = 0; i < last_pci_card; i++) { @@ -908,17 +930,25 @@ pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), ((dev->type == PCI_CARD_IDE) && (add_type == PCI_ADD_IDE)) || ((dev->type == PCI_CARD_NORTHBRIDGE) && (add_type == PCI_ADD_NORTHBRIDGE)) || ((dev->type == PCI_CARD_SOUTHBRIDGE) && (add_type == PCI_ADD_SOUTHBRIDGE)) || - ((dev->id == add_type) && (add_type < PCI_ADD_NORTHBRIDGE))) { + ((dev->bus == 0) && (dev->id == add_type) && (add_type < PCI_ADD_NORTHBRIDGE))) { + /* Add DEC 21150 PCI bridge if this is the last available NORMAL slot and + the machine supports IRQ steering (the bridge code requires steering). */ + if (!(pci_type & PCI_NO_IRQ_STEERING) && (dev->type == PCI_CARD_NORMAL) && (add_type != PCI_ADD_BRIDGE) && (i == last_normal_pci_card)) { + pci_log("pci_add_card(): Reached last NORMAL slot, adding bridge to pci_cards[%i]\n", i); + device_add_inst(&dec21150_device, last_pci_bus); + continue; + } + dev->read = read; dev->write = write; dev->priv = priv; - pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return dev->id; + pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (bus %02X slot %02X) [%s]\n", i, dev->bus, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); + return (dev->bus << 5) | dev->id; } } } pci_log("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return 0xff; + return 0xffff; } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index c1b717d31..af761ea69 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -660,7 +660,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 -DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o serial.o vpc2007.o \ +DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o vpc2007.o \ smbus.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \