Ported PCI clean-ups from VARCem.

This commit is contained in:
OBattler
2018-10-21 20:27:57 +02:00
parent 480666673e
commit 416bd769c4
2 changed files with 702 additions and 661 deletions

587
src/pci.c
View File

@@ -1,3 +1,23 @@
/*
* 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 the PCI bus.
*
* Version: @(#)pci.c 1.0.0 2018/10/21
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2008-2018 Sarah Walker.
*/
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -16,39 +36,40 @@
#include "keyboard.h" #include "keyboard.h"
static uint64_t pci_irq_hold[16]; typedef struct {
typedef struct
{
uint8_t id, type; uint8_t id, type;
uint8_t irq_routing[4]; uint8_t irq_routing[4];
void (*write) (int func, int addr, uint8_t val, void *priv);
uint8_t (*read) (int func, int addr, void *priv); void *priv;
void * priv; void (*write)(int func, int addr, uint8_t val, void *priv);
uint8_t (*read)(int func, int addr, void *priv);
} pci_card_t; } pci_card_t;
static pci_card_t pci_cards[32]; typedef struct {
static uint8_t last_pci_card = 0;
static uint8_t pci_card_to_slot_mapping[32];
static uint8_t elcr[2] = { 0, 0 };
static uint8_t pci_irqs[4];
typedef struct
{
uint8_t enabled; uint8_t enabled;
uint8_t irq_line; uint8_t irq_line;
} pci_mirq_t; } pci_mirq_t;
int pci_burst_time,
pci_nonburst_time;
static pci_card_t pci_cards[32];
static uint8_t last_pci_card = 0;
static uint8_t pci_card_to_slot_mapping[32];
static uint8_t elcr[2] = { 0, 0 };
static uint8_t pci_irqs[4];
static uint64_t pci_irq_hold[16];
static pci_mirq_t pci_mirqs[2]; static pci_mirq_t pci_mirqs[2];
static int pci_index,
static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; pci_func,
int pci_burst_time, pci_nonburst_time; pci_card,
pci_bus,
pci_enable,
pci_key;
static int trc_reg = 0; static int trc_reg = 0;
#ifdef ENABLE_PCI_LOG #ifdef ENABLE_PCI_LOG
int pci_do_log = ENABLE_PCI_LOG; int pci_do_log = ENABLE_PCI_LOG;
@@ -69,7 +90,8 @@ pci_log(const char *fmt, ...)
#endif #endif
static void pci_cf8_write(uint16_t port, uint32_t val, void *p) static void
pci_cf8_write(uint16_t port, uint32_t val, void *priv)
{ {
pci_index = val & 0xff; pci_index = val & 0xff;
pci_func = (val >> 8) & 7; pci_func = (val >> 8) & 7;
@@ -78,29 +100,30 @@ static void pci_cf8_write(uint16_t port, uint32_t val, void *p)
pci_enable = (val >> 31) & 1; pci_enable = (val >> 31) & 1;
} }
static uint32_t pci_cf8_read(uint16_t port, void *p)
static uint32_t
pci_cf8_read(uint16_t port, void *priv)
{ {
return pci_index | (pci_func << 8) | (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); return pci_index | (pci_func << 8) |
(pci_card << 11) | (pci_bus << 16) | (pci_enable << 31);
} }
static void pci_write(uint16_t port, uint8_t val, void *priv)
static void
pci_write(uint16_t port, uint8_t val, void *priv)
{ {
uint8_t slot = 0; uint8_t slot = 0;
switch (port) switch (port) {
{
case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
if (!pci_enable) if (! pci_enable)
return; return;
if (!pci_bus) if (! pci_bus) {
{
slot = pci_card_to_slot_mapping[pci_card]; slot = pci_card_to_slot_mapping[pci_card];
if (slot != 0xFF) if (slot != 0xff) {
{ if (pci_cards[slot].write) {
if (pci_cards[slot].write) pci_log("Reading PCI card on slot %02X (pci_cards[%i])...\n", pci_card, slot);
{
/* pci_log("Reading PCI card on slot %02X (pci_cards[%i])...\n", pci_card, slot); */
pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv);
} }
} }
@@ -110,23 +133,21 @@ static void pci_write(uint16_t port, uint8_t val, void *priv)
} }
} }
static uint8_t pci_read(uint16_t port, void *priv)
static uint8_t
pci_read(uint16_t port, void *priv)
{ {
uint8_t slot = 0; uint8_t slot = 0;
switch (port) switch (port) {
{
case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
if (!pci_enable) if (! pci_enable)
return 0xff; return 0xff;
if (!pci_bus) if (! pci_bus) {
{
slot = pci_card_to_slot_mapping[pci_card]; slot = pci_card_to_slot_mapping[pci_card];
if (slot != 0xFF) if (slot != 0xff) {
{ if (pci_cards[slot].read) {
if (pci_cards[slot].read)
{
return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv);
} }
} }
@@ -134,102 +155,145 @@ static uint8_t pci_read(uint16_t port, void *priv)
return 0xff; return 0xff;
} }
return 0xff; return 0xff;
} }
static void elcr_write(uint16_t port, uint8_t val, void *priv)
static void
elcr_write(uint16_t port, uint8_t val, void *priv)
{ {
/* pci_log("ELCR%i: WRITE %02X\n", port & 1, val); */ pci_log("ELCR%i: WRITE %02X\n", port & 1, val);
if (port & 1) if (port & 1)
val &= 0xDE; val &= 0xde;
else else
val &= 0xF8; val &= 0xf8;
elcr[port & 1] = val; elcr[port & 1] = val;
pci_log("ELCR %i: %c %c %c %c %c %c %c %c\n", port & 1, (val & 1) ? 'L' : 'E', (val & 2) ? 'L' : 'E', (val & 4) ? 'L' : 'E', (val & 8) ? 'L' : 'E', (val & 0x10) ? 'L' : 'E', (val & 0x20) ? 'L' : 'E', (val & 0x40) ? 'L' : 'E', (val & 0x80) ? 'L' : 'E'); pci_log("ELCR %i: %c %c %c %c %c %c %c %c\n",
port & 1,
(val & 1) ? 'L' : 'E',
(val & 2) ? 'L' : 'E',
(val & 4) ? 'L' : 'E',
(val & 8) ? 'L' : 'E',
(val & 0x10) ? 'L' : 'E',
(val & 0x20) ? 'L' : 'E',
(val & 0x40) ? 'L' : 'E',
(val & 0x80) ? 'L' : 'E');
} }
static uint8_t elcr_read(uint16_t port, void *priv)
static uint8_t
elcr_read(uint16_t port, void *priv)
{ {
/* pci_log("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); */ pci_log("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]);
return elcr[port & 1]; return elcr[port & 1];
} }
static void elcr_reset(void)
static void
elcr_reset(void)
{ {
pic_reset(); pic_reset();
elcr[0] = elcr[1] = 0x00;
elcr[0] = 0x00;
elcr[1] = 0x00;
} }
static void pci_type2_write(uint16_t port, uint8_t val, void *priv); static void pci_type2_write(uint16_t port, uint8_t val, void *priv);
static uint8_t pci_type2_read(uint16_t port, void *priv); static uint8_t pci_type2_read(uint16_t port, void *priv);
static void pci_type2_write(uint16_t port, uint8_t val, void *priv)
static void
pci_type2_write(uint16_t port, uint8_t val, void *priv)
{ {
uint8_t slot = 0; uint8_t slot = 0;
if (port == 0xcf8) { if (port == 0xcf8) {
pci_func = (val >> 1) & 7; pci_func = (val >> 1) & 7;
if (!pci_key && (val & 0xf0)) if (!pci_key && (val & 0xf0))
io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); io_sethandler(0xc000, 0x1000,
pci_type2_read, NULL, NULL,
pci_type2_write, NULL, NULL, priv);
else else
io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); io_removehandler(0xc000, 0x1000,
pci_type2_read, NULL, NULL,
pci_type2_write, NULL, NULL, priv);
pci_key = val & 0xf0; pci_key = val & 0xf0;
} else if (port == 0xcfa) } else if (port == 0xcfa) {
pci_bus = val; pci_bus = val;
else { } else {
pci_card = (port >> 8) & 0xf; pci_card = (port >> 8) & 0xf;
pci_index = port & 0xff; pci_index = port & 0xff;
if (!pci_bus) { if (! pci_bus) {
slot = pci_card_to_slot_mapping[pci_card]; slot = pci_card_to_slot_mapping[pci_card];
if (slot != 0xFF) { if (slot != 0xff) {
if (pci_cards[slot].write) if (pci_cards[slot].write) {
pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv);
} }
} }
} }
}
} }
static uint8_t pci_type2_read(uint16_t port, void *priv)
static uint8_t
pci_type2_read(uint16_t port, void *priv)
{ {
uint8_t slot = 0; uint8_t slot = 0;
if (port == 0xcf8) if (port == 0xcf8)
return pci_key | (pci_func << 1); return pci_key | (pci_func << 1);
else if (port == 0xcfa)
if (port == 0xcfa)
return pci_bus; return pci_bus;
pci_card = (port >> 8) & 0xf; pci_card = (port >> 8) & 0xf;
pci_index = port & 0xff; pci_index = port & 0xff;
if (!pci_bus) { if (! pci_bus) {
slot = pci_card_to_slot_mapping[pci_card]; slot = pci_card_to_slot_mapping[pci_card];
if (slot != 0xFF) { if (slot != 0xff) {
if (pci_cards[slot].read) if (pci_cards[slot].read) {
return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv);
} }
} }
}
return 0xff; return 0xff;
} }
void pci_set_irq_routing(int pci_int, int irq)
void
pci_set_irq_routing(int pci_int, int irq)
{ {
pci_irqs[pci_int - 1] = irq; pci_irqs[pci_int - 1] = irq;
} }
void pci_enable_mirq(int mirq)
void
pci_enable_mirq(int mirq)
{ {
pci_mirqs[mirq].enabled = 1; pci_mirqs[mirq].enabled = 1;
} }
void pci_set_mirq_routing(int mirq, int irq)
void
pci_set_mirq_routing(int mirq, int irq)
{ {
pci_mirqs[mirq].irq_line = irq; pci_mirqs[mirq].irq_line = irq;
} }
int pci_irq_is_level(int irq)
int
pci_irq_is_level(int irq)
{ {
int real_irq = irq & 7; int real_irq = irq & 7;
@@ -238,11 +302,13 @@ int pci_irq_is_level(int irq)
if (irq > 7) if (irq > 7)
return !!(elcr[1] & (1 << real_irq)); return !!(elcr[1] & (1 << real_irq));
else
return !!(elcr[0] & (1 << real_irq)); return !!(elcr[0] & (1 << real_irq));
} }
uint8_t pci_use_mirq(uint8_t mirq)
uint8_t
pci_use_mirq(uint8_t mirq)
{ {
if (!PCI || !pci_mirqs[0].enabled) if (!PCI || !pci_mirqs[0].enabled)
return 0; return 0;
@@ -253,68 +319,56 @@ uint8_t pci_use_mirq(uint8_t mirq)
return 1; return 1;
} }
#define pci_mirq_log pci_log
void pci_set_mirq(uint8_t mirq) void
pci_set_mirq(uint8_t mirq)
{ {
uint8_t irq_line = 0; uint8_t irq_line = 0;
uint8_t level = 0; uint8_t level = 0;
if (!pci_mirqs[mirq].enabled) if (! pci_mirqs[mirq].enabled) {
{ pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq);
pci_mirq_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq);
return; return;
} }
if (pci_mirqs[mirq].irq_line > 0x0F) if (pci_mirqs[mirq].irq_line > 0x0f) {
{ pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq);
pci_mirq_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq);
return; return;
} }
else
{
irq_line = pci_mirqs[mirq].irq_line; irq_line = pci_mirqs[mirq].irq_line;
pci_mirq_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); pci_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line);
}
if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) if (pci_irq_is_level(irq_line) &&
{ (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) {
/* IRQ already held, do nothing. */ /* IRQ already held, do nothing. */
pci_mirq_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); pci_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq);
return; return;
} }
else pci_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq);
{
pci_mirq_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq);
}
level = pci_irq_is_level(irq_line); level = pci_irq_is_level(irq_line);
if (!level || !pci_irq_hold[irq_line]) {
if (!level || !pci_irq_hold[irq_line]) pci_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not ");
{
pci_mirq_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not ");
/* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */
picintlevel(1 << irq_line); picintlevel(1 << irq_line);
} } else if (level && pci_irq_hold[irq_line]) {
else if (level && pci_irq_hold[irq_line]) pci_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq);
{
pci_mirq_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq);
} }
/* If the IRQ is level-triggered, mark that this MIRQ is holding it. */ /* If the IRQ is level-triggered, mark that this MIRQ is holding it. */
if (level) if (level) {
{ pci_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq);
pci_mirq_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq); pci_irq_hold[irq_line] |= (1ULL << (0x1E + mirq));
pci_irq_hold[irq_line] |= (1 << (0x1E + mirq));
}
else
{
pci_mirq_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq);
} }
pci_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq);
} }
void pci_set_irq(uint8_t card, uint8_t pci_int)
void
pci_set_irq(uint8_t card, uint8_t pci_int)
{ {
uint8_t slot = 0; uint8_t slot = 0;
uint8_t irq_routing = 0; uint8_t irq_routing = 0;
@@ -322,147 +376,113 @@ void pci_set_irq(uint8_t card, uint8_t pci_int)
uint8_t irq_line = 0; uint8_t irq_line = 0;
uint8_t level = 0; uint8_t level = 0;
if (!last_pci_card) if (! last_pci_card) {
{
pci_log("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int);
return; return;
} }
else
{
pci_log("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); 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];
if (slot == 0xff) {
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); pci_log("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int);
return; return;
} }
else
{
pci_log("pci_set_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); pci_log("pci_set_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot);
}
if (!pci_cards[slot].irq_routing[pci_int_index]) if (! pci_cards[slot].irq_routing[pci_int_index]) {
{
pci_log("pci_set_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int);
return; return;
} }
else
{
irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3;
pci_log("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); pci_log("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing);
}
if (pci_irqs[irq_routing] > 0x0F) if (pci_irqs[irq_routing] > 0x0f) {
{
pci_log("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int);
return; return;
} }
else
{
irq_line = pci_irqs[irq_routing]; irq_line = pci_irqs[irq_routing];
pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); 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] & (1 << card))) if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << card))) {
{
/* IRQ already held, do nothing. */ /* IRQ already held, do nothing. */
pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int);
return; return;
} }
else
{
pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int);
}
level = pci_irq_is_level(irq_line); level = pci_irq_is_level(irq_line);
if (!level || !pci_irq_hold[irq_line]) {
if (!level || !pci_irq_hold[irq_line])
{
pci_log("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); pci_log("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not ");
/* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */
picintlevel(1 << irq_line); picintlevel(1 << irq_line);
} } else if (level && pci_irq_hold[irq_line]) {
else if (level && pci_irq_hold[irq_line])
{
pci_log("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int);
} }
/* If the IRQ is level-triggered, mark that this card is holding it. */ /* If the IRQ is level-triggered, mark that this card is holding it. */
if (pci_irq_is_level(irq_line)) if (pci_irq_is_level(irq_line)) {
{
pci_log("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int);
pci_irq_hold[irq_line] |= (1 << card); pci_irq_hold[irq_line] |= (1ULL << card);
} } else {
else
{
pci_log("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); pci_log("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int);
} }
} }
void pci_clear_mirq(uint8_t mirq)
void
pci_clear_mirq(uint8_t mirq)
{ {
uint8_t irq_line = 0; uint8_t irq_line = 0;
uint8_t level = 0; uint8_t level = 0;
if (mirq > 1) if (mirq > 1) {
{ pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq);
pci_mirq_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq);
return; return;
} }
if (!pci_mirqs[mirq].enabled) if (! pci_mirqs[mirq].enabled) {
{ pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq);
pci_mirq_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq);
return; return;
} }
if (pci_mirqs[mirq].irq_line > 0x0F) if (pci_mirqs[mirq].irq_line > 0x0f) {
{ pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq);
pci_mirq_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq);
return; return;
} }
else
{
irq_line = pci_mirqs[mirq].irq_line; irq_line = pci_mirqs[mirq].irq_line;
pci_mirq_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); pci_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line);
}
if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) if (pci_irq_is_level(irq_line) &&
{ !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) {
/* IRQ not held, do nothing. */ /* IRQ not held, do nothing. */
pci_mirq_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); pci_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq);
return; return;
} }
level = pci_irq_is_level(irq_line); level = pci_irq_is_level(irq_line);
if (level) {
if (level) pci_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq);
{
pci_mirq_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq);
pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq));
if (!pci_irq_hold[irq_line]) if (! pci_irq_hold[irq_line]) {
{ pci_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq);
pci_mirq_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);
} }
else } else {
{ pci_log("pci_clear_mirq(%02X): Clearing edge-triggered interrupt\n", mirq);
pci_mirq_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq);
}
}
else
{
pci_mirq_log("pci_clear_mirq(%02X): Clearing edge-triggered interrupt\n", mirq);
picintc(1 << irq_line); picintc(1 << irq_line);
} }
} }
void pci_clear_irq(uint8_t card, uint8_t pci_int)
void
pci_clear_irq(uint8_t card, uint8_t pci_int)
{ {
uint8_t slot = 0; uint8_t slot = 0;
uint8_t irq_routing = 0; uint8_t irq_routing = 0;
@@ -470,89 +490,67 @@ void pci_clear_irq(uint8_t card, uint8_t pci_int)
uint8_t irq_line = 0; uint8_t irq_line = 0;
uint8_t level = 0; uint8_t level = 0;
if (!last_pci_card) if (! last_pci_card) {
{
pci_log("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int);
return; return;
} }
else
{
pci_log("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); 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];
if (slot == 0xff) {
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); pci_log("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int);
return; return;
} }
else
{
pci_log("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); pci_log("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot);
}
if (!pci_cards[slot].irq_routing[pci_int_index]) if (! pci_cards[slot].irq_routing[pci_int_index]) {
{
pci_log("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int);
return; return;
} }
else
{
irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3;
pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing);
}
if (pci_irqs[irq_routing] > 0x0F) if (pci_irqs[irq_routing] > 0x0f) {
{
pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int);
return; return;
} }
else
{
irq_line = pci_irqs[irq_routing]; irq_line = pci_irqs[irq_routing];
pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line);
}
if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << card))) if (pci_irq_is_level(irq_line) &&
{ !(pci_irq_hold[irq_line] & (1ULL << card))) {
/* IRQ not held, do nothing. */ /* IRQ not held, do nothing. */
pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int);
return; return;
} }
level = pci_irq_is_level(irq_line); level = pci_irq_is_level(irq_line);
if (level) {
if (level)
{
pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); 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 << card);
if (!pci_irq_hold[irq_line]) 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); 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 {
else
{
pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int);
} }
} } else {
else
{
pci_log("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); pci_log("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int);
picintc(1 << irq_line); picintc(1 << irq_line);
} }
} }
void pci_reset(void)
{
int i = 0;
for (i = 0; i < 16; i++) void
{ pci_reset(void)
if (pci_irq_hold[i]) {
{ int i;
for (i = 0; i < 16; i++) {
if (pci_irq_hold[i]) {
pci_irq_hold[i] = 0; pci_irq_hold[i] = 0;
picintc(1 << i); picintc(1 << i);
@@ -562,22 +560,20 @@ void pci_reset(void)
elcr_reset(); elcr_reset();
} }
static void pci_slots_clear(void)
static void
pci_slots_clear(void)
{ {
uint8_t i = 0; uint8_t i, j;
uint8_t j = 0;
last_pci_card = 0; last_pci_card = 0;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++) {
{
pci_cards[i].id = 0xFF; pci_cards[i].id = 0xFF;
pci_cards[i].type = 0xFF; pci_cards[i].type = 0xFF;
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{
pci_cards[i].irq_routing[j] = 0; pci_cards[i].irq_routing[j] = 0;
}
pci_cards[i].read = NULL; pci_cards[i].read = NULL;
pci_cards[i].write = NULL; pci_cards[i].write = NULL;
@@ -587,42 +583,53 @@ static void pci_slots_clear(void)
} }
} }
static uint8_t trc_read(uint16_t port, void *priv)
static uint8_t
trc_read(uint16_t port, void *priv)
{ {
return trc_reg & 0xfb; return trc_reg & 0xfb;
} }
static void trc_reset(uint8_t val)
static void
trc_reset(uint8_t val)
{ {
if (val & 2) if (val & 2) {
{
device_reset_all_pci(); device_reset_all_pci();
port_92_reset(); port_92_reset();
pci_reset(); pci_reset();
} }
resetx86(); resetx86();
} }
static void trc_write(uint16_t port, uint8_t val, void *priv)
static void
trc_write(uint16_t port, uint8_t val, void *priv)
{ {
/* pci_log("TRC Write: %02X\n", val); */ pci_log("TRC Write: %02X\n", val);
if (!(trc_reg & 4) && (val & 4)) if (!(trc_reg & 4) && (val & 4))
{
trc_reset(val); trc_reset(val);
}
trc_reg = val & 0xfd; trc_reg = val & 0xfd;
} }
void trc_init(void)
void
trc_init(void)
{ {
trc_reg = 0; trc_reg = 0;
io_sethandler(0x0cf9, 0x0001, trc_read, NULL, NULL, trc_write, NULL, NULL, NULL); io_sethandler(0x0cf9, 0x0001,
trc_read, NULL, NULL, trc_write, NULL, NULL, NULL);
} }
void pci_init(int type)
void
pci_init(int type)
{ {
int c; int c;
@@ -634,85 +641,89 @@ void pci_init(int type)
trc_init(); trc_init();
io_sethandler(0x04d0, 0x0002, elcr_read, NULL, NULL, elcr_write, NULL, NULL, NULL); io_sethandler(0x04d0, 0x0002,
elcr_read,NULL,NULL, elcr_write,NULL,NULL, NULL);
if (type == PCI_CONFIG_TYPE_1) if (type == PCI_CONFIG_TYPE_1) {
{ io_sethandler(0x0cf8, 1,
io_sethandler(0x0cf8, 0x0001, NULL, NULL, pci_cf8_read, NULL, NULL, pci_cf8_write, NULL); NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL);
io_sethandler(0x0cfc, 0x0004, pci_read, NULL, NULL, pci_write, NULL, NULL, NULL); io_sethandler(0x0cfc, 4,
} pci_read,NULL,NULL, pci_write,NULL,NULL, NULL);
else } else {
{ io_sethandler(0x0cf8, 1,
io_sethandler(0x0cf8, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL);
io_sethandler(0x0cfa, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); io_sethandler(0x0cfa, 1,
pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL);
} }
for (c = 0; c < 4; c++) for (c = 0; c < 4; c++)
{
pci_irqs[c] = PCI_IRQ_DISABLED; pci_irqs[c] = PCI_IRQ_DISABLED;
}
for (c = 0; c < 2; c++) for (c = 0; c < 2; c++) {
{
pci_mirqs[c].enabled = 0; pci_mirqs[c].enabled = 0;
pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; pci_mirqs[c].irq_line = PCI_IRQ_DISABLED;
} }
} }
void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd)
void
pci_register_slot(int card, int type, int inta, int intb, int intc, int intd)
{ {
pci_cards[last_pci_card].id = card; pci_card_t *dev = &pci_cards[last_pci_card];
pci_cards[last_pci_card].type = type;
pci_cards[last_pci_card].irq_routing[0] = inta; dev->id = card;
pci_cards[last_pci_card].irq_routing[1] = intb; dev->type = type;
pci_cards[last_pci_card].irq_routing[2] = intc; dev->irq_routing[0] = inta;
pci_cards[last_pci_card].irq_routing[3] = intd; dev->irq_routing[1] = intb;
pci_cards[last_pci_card].read = NULL; dev->irq_routing[2] = intc;
pci_cards[last_pci_card].write = NULL; dev->irq_routing[3] = intd;
pci_cards[last_pci_card].priv = NULL; dev->read = NULL;
dev->write = NULL;
dev->priv = NULL;
pci_card_to_slot_mapping[card] = last_pci_card; pci_card_to_slot_mapping[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].id = %02X\n", last_pci_card, card);
last_pci_card++; last_pci_card++;
} }
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)
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)
{ {
uint8_t i = 0; pci_card_t *dev;
uint8_t i;
if (add_type < PCI_ADD_NORMAL) if (add_type < PCI_ADD_NORMAL)
{
pci_log("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); pci_log("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type);
}
if (!PCI) 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" : "SPECIFIC")); 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" : "SPECIFIC"));
return 0xFF; return 0xff;
} }
if (!last_pci_card) 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" : "SPECIFIC")); 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" : "SPECIFIC"));
return 0xFF; return 0xff;
} }
for (i = 0; i < last_pci_card; i++) for (i = 0; i < last_pci_card; i++) {
{ dev = &pci_cards[i];
if (!pci_cards[i].read && !pci_cards[i].write)
{ if (!dev->read && !dev->write) {
if (((pci_cards[i].type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || if (((dev->type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) ||
((pci_cards[i].type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || ((dev->type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) ||
((pci_cards[i].id == add_type) && (add_type < PCI_ADD_NORMAL))) ((dev->id == add_type) && (add_type < PCI_ADD_NORMAL))) {
{ dev->read = read;
pci_cards[i].read = read; dev->write = write;
pci_cards[i].write = write; dev->priv = priv;
pci_cards[i].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" : "SPECIFIC"));
pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, pci_cards[i].id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); return dev->id;
return pci_cards[i].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" : "SPECIFIC")); 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" : "SPECIFIC"));
return 0xFF;
return 0xff;
} }

View File

@@ -1,22 +1,26 @@
void pci_set_irq_routing(int pci_int, int irq); /*
* 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 PCI handler module.
*
* Version: @(#)pci.h 1.0.0 2018/10/21
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2008-2018 Sarah Walker.
*/
#ifndef EMU_PCI_H
# define EMU_PCI_H
void pci_enable_mirq(int mirq);
void pci_set_mirq_routing(int mirq, int irq);
uint8_t pci_use_mirq(uint8_t mirq);
int pci_irq_is_level(int irq);
void pci_set_mirq(uint8_t mirq);
void pci_set_irq(uint8_t card, uint8_t pci_int);
void pci_clear_mirq(uint8_t mirq);
void pci_clear_irq(uint8_t card, uint8_t pci_int);
void pci_reset(void);
void pci_init(int type);
void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd);
void pci_close(void);
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);
#define PCI_REG_COMMAND 0x04 #define PCI_REG_COMMAND 0x04
@@ -36,8 +40,7 @@ uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void
#define PCI_IRQ_DISABLED -1 #define PCI_IRQ_DISABLED -1
enum enum {
{
PCI_CARD_NORMAL = 0, PCI_CARD_NORMAL = 0,
PCI_CARD_ONBOARD, PCI_CARD_ONBOARD,
PCI_CARD_SPECIAL PCI_CARD_SPECIAL
@@ -47,11 +50,38 @@ enum
#define PCI_ADD_NORMAL 0x80 #define PCI_ADD_NORMAL 0x80
#define PCI_ADD_VIDEO 0x81 #define PCI_ADD_VIDEO 0x81
extern int pci_burst_time, pci_nonburst_time;
typedef union { typedef union {
uint32_t addr; uint32_t addr;
uint8_t addr_regs[4]; uint8_t addr_regs[4];
} bar_t; } bar_t;
extern int pci_burst_time,
pci_nonburst_time;
extern void pci_set_irq_routing(int pci_int, int irq);
extern void pci_enable_mirq(int mirq);
extern void pci_set_mirq_routing(int mirq, int irq);
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);
extern void pci_set_irq(uint8_t card, uint8_t pci_int);
extern void pci_clear_mirq(uint8_t mirq);
extern void pci_clear_irq(uint8_t 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_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 void trc_init(void); extern void trc_init(void);
#endif /*EMU_PCI_H*/