VIA southbridge overhaul, day 1

This commit is contained in:
RichardG867
2020-10-09 23:07:56 -03:00
parent 2534660784
commit 8f1f3bdc08
7 changed files with 773 additions and 1449 deletions

737
src/chipset/via_pipc.c Normal file
View File

@@ -0,0 +1,737 @@
/*
* 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.
*
* Emulation of the VIA PIPC southbridges.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Melissa Goad, <mszoopers@protonmail.com>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2020 Melissa Goad.
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/cdrom.h>
#include "cpu.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/apm.h>
#include <86box/keyboard.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/acpi.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/port_92.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/usb.h>
#include <86box/zip.h>
#include <86box/machine.h>
#include <86box/smbus_piix4.h>
#include <86box/chipset.h>
#define VIA_PIPC_586A 0x05862000
#define VIA_PIPC_586B 0x05864700
#define VIA_PIPC_596B 0x05961200
#define VIA_PIPC_686A 0x06861400
#define VIA_PIPC_686B 0x06864000
#define VIA_PIPC_586(x) (((x) >> 16) == 0x0586)
typedef struct
{
uint32_t local;
uint8_t max_func;
uint8_t pci_isa_regs[256];
uint8_t ide_regs[256];
uint8_t usb_regs[2][256];
uint8_t power_regs[256];
sff8038i_t *bm[2];
nvr_t *nvr;
int nvr_enabled, slot;
smbus_piix4_t *smbus;
usb_t *usb[2];
acpi_t *acpi;
} pipc_t;
//#define ENABLE_PIPC_LOG 1
#ifdef ENABLE_PIPC_LOG
int pipc_do_log = ENABLE_PIPC_LOG;
static void
pipc_log(const char *fmt, ...)
{
va_list ap;
if (pipc_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define pipc_log(fmt, ...)
#endif
static void
pipc_reset_hard(void *priv)
{
int i;
pipc_log("PIPC: reset_hard()\n");
pipc_t *dev = (pipc_t *) priv;
uint16_t old_base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8);
sff_bus_master_reset(dev->bm[0], old_base);
sff_bus_master_reset(dev->bm[1], old_base + 8);
memset(dev->pci_isa_regs, 0, 256);
memset(dev->ide_regs, 0, 256);
memset(dev->usb_regs, 0, 512);
memset(dev->power_regs, 0, 256);
dev->pci_isa_regs[0x00] = 0x06; dev->pci_isa_regs[0x01] = 0x11;
dev->pci_isa_regs[0x02] = dev->local >> 16;
dev->pci_isa_regs[0x03] = dev->local >> 24;
dev->pci_isa_regs[0x04] = (dev->local <= VIA_PIPC_586B) ? 0x0f : 0x87;
dev->pci_isa_regs[0x07] = 0x02;
dev->pci_isa_regs[0x08] = dev->local >> 8;
dev->pci_isa_regs[0x0a] = 0x01;
dev->pci_isa_regs[0x0b] = 0x06;
dev->pci_isa_regs[0x0e] = 0x80;
dev->pci_isa_regs[0x48] = 0x01;
dev->pci_isa_regs[0x4a] = 0x04;
dev->pci_isa_regs[0x4f] = 0x03;
dev->pci_isa_regs[0x50] = (dev->local >= VIA_PIPC_686A) ? 0x2d : 0x24;
dev->pci_isa_regs[0x59] = 0x04;
if (dev->local >= VIA_PIPC_686A)
dev->pci_isa_regs[0x5a] = dev->pci_isa_regs[0x5f] = 0x04;
dma_e = 0x00;
for (i = 0; i < 8; i++) {
dma[i].ab &= 0xffff000f;
dma[i].ac &= 0xffff000f;
}
pic_set_shadow(0);
/* IDE registers */
dev->max_func++;
dev->ide_regs[0x00] = 0x06; dev->ide_regs[0x01] = 0x11;
dev->ide_regs[0x02] = 0x71; dev->ide_regs[0x03] = 0x05;
dev->ide_regs[0x04] = 0x80;
dev->ide_regs[0x06] = (dev->local == VIA_PIPC_686A) ? 0x90 : 0x80; dev->ide_regs[0x07] = 0x02;
dev->ide_regs[0x08] = 0x06;
dev->ide_regs[0x09] = 0x85;
dev->ide_regs[0x0a] = 0x01;
dev->ide_regs[0x0b] = 0x01;
dev->ide_regs[0x10] = 0xf1; dev->ide_regs[0x11] = 0x01;
dev->ide_regs[0x14] = 0xf5; dev->ide_regs[0x15] = 0x03;
dev->ide_regs[0x18] = 0x71; dev->ide_regs[0x19] = 0x01;
dev->ide_regs[0x1c] = 0x75; dev->ide_regs[0x1d] = 0x03;
dev->ide_regs[0x20] = 0x01; dev->ide_regs[0x21] = 0xcc;
if (dev->local >= VIA_PIPC_686A)
dev->ide_regs[0x34] = 0xc0;
dev->ide_regs[0x3c] = 0x0e;
if (dev->local < VIA_PIPC_686A)
dev->ide_regs[0x40] = 0x08;
dev->ide_regs[0x41] = 0x02;
dev->ide_regs[0x42] = 0x09;
dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a;
dev->ide_regs[0x44] = 0x68;
dev->ide_regs[0x46] = 0xc0;
dev->ide_regs[0x48] = 0xa8; dev->ide_regs[0x49] = 0xa8;
dev->ide_regs[0x4a] = 0xa8; dev->ide_regs[0x4b] = 0xa8;
dev->ide_regs[0x4c] = 0xff;
dev->ide_regs[0x4e] = 0xff;
dev->ide_regs[0x4f] = 0xff;
dev->ide_regs[0x50] = 0x03; dev->ide_regs[0x51] = 0x03;
dev->ide_regs[0x52] = 0x03; dev->ide_regs[0x53] = 0x03;
if (dev->local >= VIA_PIPC_596B)
dev->ide_regs[0x54] = 0x06;
dev->ide_regs[0x61] = 0x02;
dev->ide_regs[0x69] = 0x02;
if (dev->local >= VIA_PIPC_686A) {
dev->ide_regs[0xc0] = 0x01;
dev->ide_regs[0xc2] = 0x02;
}
for (uint8_t i = 0; i <= (dev->local >= VIA_PIPC_686A); i++) {
dev->max_func++;
dev->usb_regs[i][0x00] = 0x06; dev->usb_regs[i][0x01] = 0x11;
dev->usb_regs[i][0x02] = 0x38; dev->usb_regs[i][0x03] = 0x30;
dev->usb_regs[i][0x04] = 0x00; dev->usb_regs[i][0x05] = 0x00;
dev->usb_regs[i][0x06] = 0x00; dev->usb_regs[i][0x07] = 0x02;
if (dev->local >= VIA_PIPC_686A)
dev->usb_regs[i][0x08] = 0x16;
else if (dev->local >= VIA_PIPC_596B)
dev->usb_regs[i][0x08] = 0x08;
else
dev->usb_regs[i][0x08] = 0x02;
dev->usb_regs[i][0x0a] = 0x03;
dev->usb_regs[i][0x0b] = 0x0c;
dev->usb_regs[i][0x0d] = 0x16;
dev->usb_regs[i][0x20] = 0x01;
dev->usb_regs[i][0x21] = 0x03;
dev->usb_regs[i][0x3d] = 0x04;
dev->usb_regs[i][0x60] = 0x10;
if (dev->local >= VIA_PIPC_686A) {
dev->usb_regs[i][0x80] = 0x01;
dev->usb_regs[i][0x82] = 0x02;
}
dev->usb_regs[i][0xc1] = 0x20;
}
if (dev->local >= VIA_PIPC_586B) {
dev->max_func++;
dev->power_regs[0x00] = 0x06; dev->power_regs[0x01] = 0x11;
if (dev->local <= VIA_PIPC_586B)
dev->power_regs[0x02] = 0x40;
else if (dev->local <= VIA_PIPC_596B)
dev->power_regs[0x02] = 0x50;
else
dev->power_regs[0x02] = 0x57;
dev->power_regs[0x03] = 0x30;
dev->power_regs[0x04] = 0x00; dev->power_regs[0x05] = 0x00;
dev->power_regs[0x06] = (dev->local == VIA_PIPC_686B) ? 0x90 : 0x80; dev->power_regs[0x07] = 0x02;
if (dev->local >= VIA_PIPC_686A)
dev->power_regs[0x08] = 0x40;
else if (dev->local >= VIA_PIPC_596B)
dev->power_regs[0x08] = 0x20;
else
dev->power_regs[0x08] = 0x10;
dev->power_regs[0x48] = 0x01;
if (dev->local >= VIA_PIPC_596B)
dev->power_regs[0x90] = 0x01;
}
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);
pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED);
ide_pri_disable();
ide_sec_disable();
}
static void
pipc_ide_handlers(pipc_t *dev)
{
uint16_t main, side;
ide_pri_disable();
ide_sec_disable();
if (dev->ide_regs[0x09] & 0x01) {
main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8);
side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2;
} else {
main = 0x1f0;
side = 0x3f6;
}
ide_set_base(0, main);
ide_set_side(0, side);
if (dev->ide_regs[0x09] & 0x04) {
main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8);
side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2;
} else {
main = 0x170;
side = 0x376;
}
ide_set_base(1, main);
ide_set_side(1, side);
if (dev->ide_regs[0x04] & PCI_COMMAND_IO) {
if (dev->ide_regs[0x40] & 0x02)
ide_pri_enable();
if (dev->ide_regs[0x40] & 0x01)
ide_sec_enable();
}
}
static void
pipc_ide_irqs(pipc_t *dev)
{
int irq_mode[2] = { 0, 0 };
if (dev->ide_regs[0x09] & 0x01)
irq_mode[0] = (dev->ide_regs[0x3d] & 0x01);
if (dev->ide_regs[0x09] & 0x04)
irq_mode[1] = (dev->ide_regs[0x3d] & 0x01);
sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]);
sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]);
}
static void
pipc_bus_master_handlers(pipc_t *dev)
{
uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8);
sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base);
sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8);
}
static uint8_t
pipc_read(int func, int addr, void *priv)
{
pipc_t *dev = (pipc_t *) priv;
uint8_t ret = 0xff;
int c;
uint8_t pm_func = (dev->local >= VIA_PIPC_686A) ? 4 : 3;
if (func > dev->max_func)
return ret;
else if (func == 0) { /* PCI-ISA bridge */
if ((addr >= 0x60) && (addr <= 0x6f)) {
c = (addr & 0x0e) >> 1;
if (addr & 0x01)
ret = (dma[c].ab & 0x0000ff00) >> 8;
else {
ret = (dma[c].ab & 0x000000f0);
ret |= (!!(dma_e & (1 << c)) << 3);
}
} else
ret = dev->pci_isa_regs[addr];
}
else if (func == 1) /* IDE */
ret = dev->ide_regs[addr];
else if (func < pm_func) /* USB */
ret = dev->usb_regs[func - 2][addr];
else if (func == pm_func) /* Power */
ret = dev->power_regs[addr];
pipc_log("PIPC: read(%d, %02X) = %02X\n", func, addr, ret);
return ret;
}
static void
nvr_update_io_mapping(pipc_t *dev)
{
if (dev->nvr_enabled)
nvr_at_handler(0, 0x0074, dev->nvr);
if ((dev->pci_isa_regs[0x5b] & 0x02) && (dev->pci_isa_regs[0x48] & 0x08))
nvr_at_handler(1, 0x0074, dev->nvr);
}
static void
usb_update_io_mapping(pipc_t *dev, int func)
{
uhci_update_io_mapping(dev->usb[func - 2], dev->usb_regs[func - 2][0x20] & ~0x1f, dev->usb_regs[func - 2][0x21], dev->usb_regs[func - 2][PCI_REG_COMMAND] & PCI_COMMAND_IO);
}
static void
pipc_write(int func, int addr, uint8_t val, void *priv)
{
pipc_t *dev = (pipc_t *) priv;
int c;
uint8_t pm_func = (dev->local >= VIA_PIPC_686A) ? 4 : 3;
if (func > dev->max_func)
return;
pipc_log("PIPC: write(%d, %02X, %02X)\n", func, addr, val);
if (func == 0) { /* PCI-ISA bridge */
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) || (addr == 0x49) || (addr == 0x4b) ||
(addr == 0x53) || ((addr >= 0x5d) && (addr < 0x5f)) || ((addr >= 0x71) && (addr < 0x74)) || (addr >= 0x90))
return;
if ((dev->local <= VIA_PIPC_586B) && (addr >= 0x74))
return;
if ((dev->local <= VIA_PIPC_596B) && ((addr == 0x51) || (addr == 0x52) || (addr == 0x5f) || (addr == 0x85) ||
(addr == 0x86) || ((addr >= 0x8a) && (addr < 0x90))))
return;
switch (addr) {
case 0x04:
dev->pci_isa_regs[0x04] = (val & 8) | 7;
break;
case 0x07:
dev->pci_isa_regs[0x07] &= ~(val & 0xb0);
break;
case 0x47:
if ((val & 0x81) == 0x81) {
/* Trigger TRC reset. */
outb(0xcf9, 0x00);
outb(0xcf9, 0xff);
return;
}
pic_set_shadow(!!(val & 0x10));
pci_elcr_set_enabled(!!(val & 0x20));
dev->pci_isa_regs[0x47] = val & 0xfe;
break;
case 0x48:
dev->pci_isa_regs[0x48] = val;
nvr_update_io_mapping(dev);
break;
case 0x54:
pci_set_irq_level(PCI_INTA, !(val & 8));
pci_set_irq_level(PCI_INTB, !(val & 4));
pci_set_irq_level(PCI_INTC, !(val & 2));
pci_set_irq_level(PCI_INTD, !(val & 1));
break;
case 0x55:
pci_set_irq_routing((dev->local >= VIA_PIPC_596B) ? PCI_INTA : PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
if (dev->local < VIA_PIPC_686A)
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x55] = val;
break;
case 0x56:
pci_set_irq_routing((dev->local >= VIA_PIPC_596B) ? PCI_INTC : PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x56] = val;
break;
case 0x57:
pci_set_irq_routing((dev->local >= VIA_PIPC_596B) ? PCI_INTD : PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
if (dev->local < VIA_PIPC_686A)
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x57] = val;
break;
case 0x58:
if (dev->local < VIA_PIPC_686A)
pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x58] = val;
break;
case 0x5b:
dev->pci_isa_regs[0x5b] = val;
nvr_update_io_mapping(dev);
break;
case 0x60: case 0x62: case 0x64: case 0x66:
case 0x6a: case 0x6c: case 0x6e:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0);
dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0);
if (val & 0x08)
dma_e |= (1 << c);
else
dma_e &= ~(1 << c);
break;
case 0x61: case 0x63: case 0x65: case 0x67:
case 0x6b: case 0x6d: case 0x6f:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8);
dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8);
break;
case 0x70: case 0x71: case 0x72: case 0x73:
dev->pci_isa_regs[(addr - 0x44)] = val;
break;
case 0x74:
dev->pci_isa_regs[addr] = val;
break;
case 0x80: case 0x86: case 0x87:
dev->pci_isa_regs[addr] &= ~(val);
break;
default:
dev->pci_isa_regs[addr] = val;
break;
}
} else if (func == 1) { /* IDE */
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) ||
((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) ||
((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) ||
((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x55) && (addr < 0x60)) ||
((addr >= 0x62) && (addr < 0x68)) || ((addr >= 0x6a) && (addr < 0x70)) ||
(addr == 0x72) || (addr == 0x73) || (addr == 0x76) || (addr == 0x77) ||
(addr == 0x7a) || (addr == 0x7b) || (addr == 0x7e) || (addr == 0x7f) ||
((addr >= 0x84) && (addr < 0x88)) || (addr >= 0x8c))
return;
if ((dev->local <= VIA_PIPC_586B) && ((addr == 0x54) || (addr >= 0x70)))
return;
switch (addr) {
case 0x04:
dev->ide_regs[0x04] = val & 0x85;
pipc_ide_handlers(dev);
pipc_bus_master_handlers(dev);
break;
case 0x07:
dev->ide_regs[0x07] &= ~(val & 0xf1);
break;
case 0x09:
dev->ide_regs[0x09] = (val & 0x05) | 0x8a;
pipc_ide_handlers(dev);
pipc_ide_irqs(dev);
break;
case 0x10:
dev->ide_regs[0x10] = (val & 0xf8) | 1;
pipc_ide_handlers(dev);
break;
case 0x11:
dev->ide_regs[0x11] = val;
pipc_ide_handlers(dev);
break;
case 0x14:
dev->ide_regs[0x14] = (val & 0xfc) | 1;
pipc_ide_handlers(dev);
break;
case 0x15:
dev->ide_regs[0x15] = val;
pipc_ide_handlers(dev);
break;
case 0x18:
dev->ide_regs[0x18] = (val & 0xf8) | 1;
pipc_ide_handlers(dev);
break;
case 0x19:
dev->ide_regs[0x19] = val;
pipc_ide_handlers(dev);
break;
case 0x1c:
dev->ide_regs[0x1c] = (val & 0xfc) | 1;
pipc_ide_handlers(dev);
break;
case 0x1d:
dev->ide_regs[0x1d] = val;
pipc_ide_handlers(dev);
break;
case 0x20:
dev->ide_regs[0x20] = (val & 0xf0) | 1;
pipc_bus_master_handlers(dev);
break;
case 0x21:
dev->ide_regs[0x21] = val;
pipc_bus_master_handlers(dev);
break;
case 0x3d:
dev->ide_regs[0x3d] = val & 0x01;
pipc_ide_irqs(dev);
break;
case 0x40:
dev->ide_regs[0x40] = val;
pipc_ide_handlers(dev);
break;
case 0x70: case 0x71: case 0x74: case 0x75: case 0x78: case 0x79: case 0x7c: case 0x7d: case 0x80: case 0x81: case 0x82: case 0x83: case 0x88: case 0x89: case 0x8a: case 0x8b:
pclog("them ide registers... %02X %02X\n", addr, val);
break;
default:
dev->ide_regs[addr] = val;
break;
}
} else if (func < pm_func) { /* USB */
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) ||
((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) ||
((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2))
return;
switch (addr) {
case 0x04:
dev->usb_regs[func - 2][0x04] = val & 0x97;
usb_update_io_mapping(dev, func);
break;
case 0x07:
dev->usb_regs[func - 2][0x07] &= ~(val & 0x78);
break;
case 0x20:
dev->usb_regs[func - 2][0x20] = (val & ~0x1f) | 1;
usb_update_io_mapping(dev, func);
break;
case 0x21:
dev->usb_regs[func - 2][0x21] = val;
usb_update_io_mapping(dev, func);
break;
default:
dev->usb_regs[func - 2][addr] = val;
break;
}
} else if (func == pm_func) { /* Power */
/* Read-only addresses */
if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) ||
(addr == 0x4e) || (addr == 0x4f) || (addr == 0x56) || (addr == 0x57) || ((addr >= 0x5c) && (addr < 0x61)) ||
((addr >= 0x64) && (addr < 0x70)) || (addr == 0x72) || (addr == 0x73) || ((addr >= 0x75) && (addr < 0x90)) ||
((addr >= 0x92) && (addr < 0xd2)) || (addr >= 0xd7))
return;
if ((dev->local <= VIA_PIPC_586B) && ((addr == 0x4c) || (addr == 0x4d) || (addr >= 0x54)))
return;
if ((dev->local <= VIA_PIPC_596B) && ((addr >= 0x64) && (addr < 0x90)))
return;
switch (addr) {
case 0x41: case 0x49:
dev->power_regs[addr] = val;
acpi_update_io_mapping(dev->acpi, dev->power_regs[0x49] << 8, dev->power_regs[0x41] & 0x80);
break;
case 0x61: case 0x62: case 0x63:
dev->power_regs[(addr - 0x58)] = val;
break;
case 0x90: case 0x91:
dev->power_regs[addr] = val;
smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), dev->power_regs[0xd2] & 0x01);
break;
default:
dev->power_regs[addr] = val;
break;
}
}
}
static void *
pipc_init(const device_t *info)
{
pipc_t *dev = (pipc_t *) malloc(sizeof(pipc_t));
memset(dev, 0, sizeof(pipc_t));
pipc_log("PIPC: init()\n");
dev->local = info->local;
dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, pipc_read, pipc_write, dev);
dev->bm[0] = device_add_inst(&sff8038i_device, 1);
sff_set_slot(dev->bm[0], dev->slot);
sff_set_irq_mode(dev->bm[0], 0, 0);
sff_set_irq_mode(dev->bm[0], 1, 0);
sff_set_irq_pin(dev->bm[0], PCI_INTA);
dev->bm[1] = device_add_inst(&sff8038i_device, 2);
sff_set_slot(dev->bm[1], dev->slot);
sff_set_irq_mode(dev->bm[1], 0, 0);
sff_set_irq_mode(dev->bm[1], 1, 0);
sff_set_irq_pin(dev->bm[1], PCI_INTA);
dev->nvr = device_add(&via_nvr_device);
dev->smbus = device_add(&piix4_smbus_device);
dev->acpi = device_add(&acpi_via_device);
dev->usb[0] = device_add_inst(&usb_device, 1);
if (dev->local >= VIA_PIPC_686A)
dev->usb[1] = device_add_inst(&usb_device, 2);
pipc_reset_hard(dev);
device_add(&port_92_pci_device);
dma_alias_set();
pci_enable_mirq(0);
pci_enable_mirq(1);
pci_enable_mirq(2);
return dev;
}
static void
pipc_close(void *p)
{
pipc_t *pipc = (pipc_t *) p;
pipc_log("PIPC: close()\n");
free(pipc);
}
const device_t via_vt82c586b_device =
{
"VIA VT82C586B",
DEVICE_PCI,
VIA_PIPC_586B,
pipc_init,
pipc_close,
NULL,
NULL,
NULL,
NULL,
NULL
};
const device_t via_vt82c596b_device =
{
"VIA VT82C596B",
DEVICE_PCI,
VIA_PIPC_596B,
pipc_init,
pipc_close,
NULL,
NULL,
NULL,
NULL,
NULL
};

View File

@@ -1,659 +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.
*
* Emulation of the VIA Apollo MVP3 southbridge
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Melissa Goad, <mszoopers@protonmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2020 Melissa Goad.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/cdrom.h>
#include "cpu.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/apm.h>
#include <86box/keyboard.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/port_92.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/zip.h>
#include <86box/machine.h>
#include <86box/chipset.h>
#define ACPI_TIMER_FREQ 3579545
#define ACPI_IO_ENABLE (1 << 7)
#define ACPI_TIMER_32BIT (1 << 3)
typedef struct
{
uint8_t pci_isa_regs[256];
uint8_t ide_regs[256];
uint8_t usb_regs[256];
uint8_t power_regs[256];
sff8038i_t * bm[2];
nvr_t * nvr;
int nvr_enabled, slot;
struct
{
uint16_t io_base;
} usb;
struct
{
uint16_t io_base;
} power;
} via_vt82c586b_t;
static void
via_vt82c586b_reset_hard(void *priv)
{
int i;
via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *) priv;
uint16_t old_base = (via_vt82c586b->ide_regs[0x20] & 0xf0) | (via_vt82c586b->ide_regs[0x21] << 8);
sff_bus_master_reset(via_vt82c586b->bm[0], old_base);
sff_bus_master_reset(via_vt82c586b->bm[1], old_base + 8);
memset(via_vt82c586b->pci_isa_regs, 0, 256);
memset(via_vt82c586b->ide_regs, 0, 256);
memset(via_vt82c586b->usb_regs, 0, 256);
memset(via_vt82c586b->power_regs, 0, 256);
via_vt82c586b->pci_isa_regs[0x00] = 0x06; via_vt82c586b->pci_isa_regs[0x01] = 0x11; /*VIA*/
via_vt82c586b->pci_isa_regs[0x02] = 0x86; via_vt82c586b->pci_isa_regs[0x03] = 0x05; /*VT82C586B*/
via_vt82c586b->pci_isa_regs[0x04] = 0x0f;
via_vt82c586b->pci_isa_regs[0x07] = 0x02;
via_vt82c586b->pci_isa_regs[0x0a] = 0x01;
via_vt82c586b->pci_isa_regs[0x0b] = 0x06;
via_vt82c586b->pci_isa_regs[0x0e] = 0x80;
via_vt82c586b->pci_isa_regs[0x48] = 0x01;
via_vt82c586b->pci_isa_regs[0x4a] = 0x04;
via_vt82c586b->pci_isa_regs[0x4f] = 0x03;
via_vt82c586b->pci_isa_regs[0x50] = 0x24;
via_vt82c586b->pci_isa_regs[0x59] = 0x04;
dma_e = 0x00;
for (i = 0; i < 8; i++) {
dma[i].ab &= 0xffff000f;
dma[i].ac &= 0xffff000f;
}
pic_set_shadow(0);
/* IDE registers */
via_vt82c586b->ide_regs[0x00] = 0x06; via_vt82c586b->ide_regs[0x01] = 0x11; /*VIA*/
via_vt82c586b->ide_regs[0x02] = 0x71; via_vt82c586b->ide_regs[0x03] = 0x05; /*VT82C586B*/
via_vt82c586b->ide_regs[0x04] = 0x80;
via_vt82c586b->ide_regs[0x06] = 0x80; via_vt82c586b->ide_regs[0x07] = 0x02;
via_vt82c586b->ide_regs[0x09] = 0x85;
via_vt82c586b->ide_regs[0x0a] = 0x01;
via_vt82c586b->ide_regs[0x0b] = 0x01;
via_vt82c586b->ide_regs[0x10] = 0xf1; via_vt82c586b->ide_regs[0x11] = 0x01;
via_vt82c586b->ide_regs[0x14] = 0xf5; via_vt82c586b->ide_regs[0x15] = 0x03;
via_vt82c586b->ide_regs[0x18] = 0x71; via_vt82c586b->ide_regs[0x19] = 0x01;
via_vt82c586b->ide_regs[0x1c] = 0x75; via_vt82c586b->ide_regs[0x1d] = 0x03;
via_vt82c586b->ide_regs[0x20] = 0x01; via_vt82c586b->ide_regs[0x21] = 0xcc;
via_vt82c586b->ide_regs[0x3c] = 0x0e;
via_vt82c586b->ide_regs[0x40] = 0x08;
via_vt82c586b->ide_regs[0x41] = 0x02;
via_vt82c586b->ide_regs[0x42] = 0x09;
via_vt82c586b->ide_regs[0x43] = 0x3a;
via_vt82c586b->ide_regs[0x44] = 0x68;
via_vt82c586b->ide_regs[0x46] = 0xc0;
via_vt82c586b->ide_regs[0x48] = 0xa8; via_vt82c586b->ide_regs[0x49] = 0xa8;
via_vt82c586b->ide_regs[0x4a] = 0xa8; via_vt82c586b->ide_regs[0x4b] = 0xa8;
via_vt82c586b->ide_regs[0x4c] = 0xff;
via_vt82c586b->ide_regs[0x4e] = 0xff;
via_vt82c586b->ide_regs[0x4f] = 0xff;
via_vt82c586b->ide_regs[0x50] = 0x03; via_vt82c586b->ide_regs[0x51] = 0x03;
via_vt82c586b->ide_regs[0x52] = 0x03; via_vt82c586b->ide_regs[0x53] = 0x03;
via_vt82c586b->ide_regs[0x61] = 0x02;
via_vt82c586b->ide_regs[0x69] = 0x02;
via_vt82c586b->usb_regs[0x00] = 0x06; via_vt82c586b->usb_regs[0x01] = 0x11; /*VIA*/
via_vt82c586b->usb_regs[0x02] = 0x38; via_vt82c586b->usb_regs[0x03] = 0x30;
via_vt82c586b->usb_regs[0x04] = 0x00; via_vt82c586b->usb_regs[0x05] = 0x00;
via_vt82c586b->usb_regs[0x06] = 0x00; via_vt82c586b->usb_regs[0x07] = 0x02;
via_vt82c586b->usb_regs[0x0a] = 0x03;
via_vt82c586b->usb_regs[0x0b] = 0x0c;
via_vt82c586b->usb_regs[0x0d] = 0x16;
via_vt82c586b->usb_regs[0x20] = 0x01;
via_vt82c586b->usb_regs[0x21] = 0x03;
via_vt82c586b->usb_regs[0x3d] = 0x04;
via_vt82c586b->usb_regs[0x60] = 0x10;
via_vt82c586b->usb_regs[0xc1] = 0x20;
via_vt82c586b->power_regs[0x00] = 0x06; via_vt82c586b->power_regs[0x01] = 0x11; /*VIA*/
via_vt82c586b->power_regs[0x02] = 0x40; via_vt82c586b->power_regs[0x03] = 0x30;
via_vt82c586b->power_regs[0x04] = 0x00; via_vt82c586b->power_regs[0x05] = 0x00;
via_vt82c586b->power_regs[0x06] = 0x80; via_vt82c586b->power_regs[0x07] = 0x02;
via_vt82c586b->power_regs[0x08] = 0x10; /*Production version (3041)*/
via_vt82c586b->power_regs[0x48] = 0x01;
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);
pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED);
ide_pri_disable();
ide_sec_disable();
}
static void
via_vt82c586b_ide_handlers(via_vt82c586b_t *dev)
{
uint16_t main, side;
ide_pri_disable();
ide_sec_disable();
if (dev->ide_regs[0x09] & 0x01) {
main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8);
side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2;
} else {
main = 0x1f0;
side = 0x3f6;
}
ide_set_base(0, main);
ide_set_side(0, side);
if (dev->ide_regs[0x09] & 0x04) {
main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8);
side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2;
} else {
main = 0x170;
side = 0x376;
}
ide_set_base(1, main);
ide_set_side(1, side);
if (dev->ide_regs[0x04] & PCI_COMMAND_IO) {
if (dev->ide_regs[0x40] & 0x02)
ide_pri_enable();
if (dev->ide_regs[0x40] & 0x01)
ide_sec_enable();
}
}
static void
via_vt82c586b_ide_irqs(via_vt82c586b_t *dev)
{
int irq_mode[2] = { 0, 0 };
if (dev->ide_regs[0x09] & 0x01)
irq_mode[0] = (dev->ide_regs[0x3d] & 0x01);
if (dev->ide_regs[0x09] & 0x04)
irq_mode[1] = (dev->ide_regs[0x3d] & 0x01);
sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]);
sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]);
}
static void
via_vt82c586b_bus_master_handlers(via_vt82c586b_t *dev)
{
uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8);
sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base);
sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8);
}
static uint8_t
via_vt82c586b_read(int func, int addr, void *priv)
{
via_vt82c586b_t *dev = (via_vt82c586b_t *) priv;
uint8_t ret = 0xff;
int c;
switch(func) {
case 0:
if ((addr >= 0x60) && (addr <= 0x6f)) {
c = (addr & 0x0e) >> 1;
if (addr & 0x01)
ret = (dma[c].ab & 0x0000ff00) >> 8;
else {
ret = (dma[c].ab & 0x000000f0);
ret |= (!!(dma_e & (1 << c)) << 3);
}
} else
ret = dev->pci_isa_regs[addr];
break;
case 1:
ret = dev->ide_regs[addr];
break;
case 2:
ret = dev->usb_regs[addr];
break;
case 3:
ret = dev->power_regs[addr];
break;
}
return ret;
}
static uint8_t
usb_reg_read(uint16_t addr, void *p)
{
uint8_t ret = 0xff;
switch (addr & 0x1f) {
case 0x10: case 0x11: case 0x12: case 0x13:
/* Port status */
ret = 0x00;
break;
}
return ret;
}
static void
usb_reg_write(uint16_t addr, uint8_t val, void *p)
{
}
static void
nvr_update_io_mapping(via_vt82c586b_t *dev)
{
if (dev->nvr_enabled)
nvr_at_handler(0, 0x0074, dev->nvr);
if ((dev->pci_isa_regs[0x5b] & 0x02) && (dev->pci_isa_regs[0x48] & 0x08))
nvr_at_handler(1, 0x0074, dev->nvr);
}
static void
usb_update_io_mapping(via_vt82c586b_t *dev)
{
if (dev->usb.io_base != 0x0000)
io_removehandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev);
dev->usb.io_base = (dev->usb_regs[0x20] & ~0x1f) | (dev->usb_regs[0x21] << 8);
if ((dev->usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->usb.io_base != 0x0000))
io_sethandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev);
}
static uint8_t
power_reg_read(uint16_t addr, void *p)
{
via_vt82c586b_t *dev = (via_vt82c586b_t *) p;
uint32_t timer;
uint8_t ret = 0xff;
switch (addr & 0xff) {
case 0x08: case 0x09: case 0x0a: case 0x0b:
/* ACPI timer */
timer = (tsc * ACPI_TIMER_FREQ) / machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed;
if (!(dev->power_regs[0x41] & ACPI_TIMER_32BIT))
timer &= 0x00ffffff;
ret = (timer >> (8 * (addr & 3))) & 0xff;
break;
}
return ret;
}
static void
power_reg_write(uint16_t addr, uint8_t val, void *p)
{
}
static void
power_update_io_mapping(via_vt82c586b_t *dev)
{
if (dev->power.io_base != 0x0000)
io_removehandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev);
dev->power.io_base = (dev->power_regs[0x49] << 8);
if ((dev->power_regs[0x41] & ACPI_IO_ENABLE) && (dev->power.io_base != 0x0000))
io_sethandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev);
}
static void
via_vt82c586b_write(int func, int addr, uint8_t val, void *priv)
{
via_vt82c586b_t *dev = (via_vt82c586b_t *) priv;
int c;
if (func > 3)
return;
switch(func) {
case 0: /* PCI-ISA bridge */
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) ||
(addr == 0x49) || (addr == 0x4b) || ((addr >= 0x51) && (addr < 0x54)) || ((addr >= 0x5d) && (addr < 0x60)) ||
((addr >= 0x68) && (addr < 0x6a)) || (addr >= 0x73))
return;
switch (addr) {
case 0x04:
dev->pci_isa_regs[0x04] = (val & 8) | 7;
break;
case 0x07:
dev->pci_isa_regs[0x07] &= ~(val & 0xb0);
break;
case 0x47:
if ((val & 0x81) == 0x81)
resetx86();
pic_set_shadow(!!(val & 0x10));
pci_elcr_set_enabled(!!(val & 0x20));
dev->pci_isa_regs[0x47] = val & 0xfe;
break;
case 0x48:
dev->pci_isa_regs[0x48] = val;
nvr_update_io_mapping(dev);
break;
case 0x54:
pci_set_irq_level(PCI_INTA, !(val & 8));
pci_set_irq_level(PCI_INTB, !(val & 4));
pci_set_irq_level(PCI_INTC, !(val & 2));
pci_set_irq_level(PCI_INTD, !(val & 1));
break;
case 0x55:
pci_set_irq_routing(PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x55] = val;
break;
case 0x56:
pci_set_irq_routing(PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x56] = val;
break;
case 0x57:
pci_set_irq_routing(PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x57] = val;
break;
case 0x58:
pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x58] = val;
break;
case 0x5b:
dev->pci_isa_regs[0x5b] = val;
nvr_update_io_mapping(dev);
break;
case 0x60: case 0x62: case 0x64: case 0x66:
case 0x6a: case 0x6c: case 0x6e:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0);
dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0);
if (val & 0x08)
dma_e |= (1 << c);
else
dma_e &= ~(1 << c);
break;
case 0x61: case 0x63: case 0x65: case 0x67:
case 0x6b: case 0x6d: case 0x6f:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8);
dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8);
break;
case 0x70: case 0x71: case 0x72: case 0x73:
dev->pci_isa_regs[(addr - 0x44)] = val;
break;
}
break;
case 1: /* IDE regs */
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) ||
((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) ||
((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) ||
((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x54) && (addr < 0x60)) ||
((addr >= 0x52) && (addr < 0x68)) || (addr >= 0x62))
return;
switch (addr) {
case 0x04:
dev->ide_regs[0x04] = val & 0x85;
via_vt82c586b_ide_handlers(dev);
via_vt82c586b_bus_master_handlers(dev);
break;
case 0x07:
dev->ide_regs[0x07] &= ~(val & 0xf1);
break;
case 0x09:
dev->ide_regs[0x09] = (val & 0x05) | 0x8a;
via_vt82c586b_ide_handlers(dev);
via_vt82c586b_ide_irqs(dev);
break;
case 0x10:
dev->ide_regs[0x10] = (val & 0xf8) | 1;
via_vt82c586b_ide_handlers(dev);
break;
case 0x11:
dev->ide_regs[0x11] = val;
via_vt82c586b_ide_handlers(dev);
break;
case 0x14:
dev->ide_regs[0x14] = (val & 0xfc) | 1;
via_vt82c586b_ide_handlers(dev);
break;
case 0x15:
dev->ide_regs[0x15] = val;
via_vt82c586b_ide_handlers(dev);
break;
case 0x18:
dev->ide_regs[0x18] = (val & 0xf8) | 1;
via_vt82c586b_ide_handlers(dev);
break;
case 0x19:
dev->ide_regs[0x19] = val;
via_vt82c586b_ide_handlers(dev);
break;
case 0x1c:
dev->ide_regs[0x1c] = (val & 0xfc) | 1;
via_vt82c586b_ide_handlers(dev);
break;
case 0x1d:
dev->ide_regs[0x1d] = val;
via_vt82c586b_ide_handlers(dev);
break;
case 0x20:
dev->ide_regs[0x20] = (val & 0xf0) | 1;
via_vt82c586b_bus_master_handlers(dev);
break;
case 0x21:
dev->ide_regs[0x21] = val;
via_vt82c586b_bus_master_handlers(dev);
break;
case 0x3d:
dev->ide_regs[0x3d] = val & 0x01;
via_vt82c586b_ide_irqs(dev);
break;
case 0x40:
dev->ide_regs[0x40] = val;
via_vt82c586b_ide_handlers(dev);
break;
default:
dev->ide_regs[addr] = val;
break;
}
break;
case 2:
/* Read-only addresses */
if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) ||
((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) ||
((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2))
return;
switch (addr) {
case 0x04:
dev->usb_regs[0x04] = val & 0x97;
usb_update_io_mapping(dev);
break;
case 0x07:
dev->usb_regs[0x07] &= ~(val & 0x78);
break;
case 0x20:
dev->usb_regs[0x20] = (val & ~0x1f) | 1;
usb_update_io_mapping(dev);
break;
case 0x21:
dev->usb_regs[0x21] = val;
usb_update_io_mapping(dev);
break;
default:
dev->usb_regs[addr] = val;
break;
}
break;
case 3:
/* Read-only addresses */
if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) ||
((addr >= 0x4a) && (addr < 0x50)) || (addr >= 0x54))
return;
switch (addr) {
case 0x41: case 0x49:
dev->power_regs[addr] = val;
power_update_io_mapping(dev);
break;
default:
dev->power_regs[addr] = val;
break;
}
}
}
static void
*via_vt82c586b_init(const device_t *info)
{
via_vt82c586b_t *dev = (via_vt82c586b_t *) malloc(sizeof(via_vt82c586b_t));
memset(dev, 0, sizeof(via_vt82c586b_t));
dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, via_vt82c586b_read, via_vt82c586b_write, dev);
dev->bm[0] = device_add_inst(&sff8038i_device, 1);
sff_set_slot(dev->bm[0], dev->slot);
sff_set_irq_mode(dev->bm[0], 0, 0);
sff_set_irq_mode(dev->bm[0], 1, 0);
sff_set_irq_pin(dev->bm[0], PCI_INTA);
dev->bm[1] = device_add_inst(&sff8038i_device, 2);
sff_set_slot(dev->bm[1], dev->slot);
sff_set_irq_mode(dev->bm[1], 0, 0);
sff_set_irq_mode(dev->bm[1], 1, 0);
sff_set_irq_pin(dev->bm[1], PCI_INTA);
dev->nvr = device_add(&via_nvr_device);
via_vt82c586b_reset_hard(dev);
device_add(&port_92_pci_device);
dma_alias_set();
pci_enable_mirq(0);
pci_enable_mirq(1);
pci_enable_mirq(2);
return dev;
}
static void
via_vt82c586b_close(void *p)
{
via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *)p;
free(via_vt82c586b);
}
const device_t via_vt82c586b_device =
{
"VIA VT82C586B",
DEVICE_PCI,
0,
via_vt82c586b_init,
via_vt82c586b_close,
NULL,
NULL,
NULL,
NULL,
NULL
};

View File

@@ -1,789 +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.
Implementation of the VT82C596B. Based on VT82C586B + PIIX4
Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
Copyright 2020 Tiseno100 <Implemented the 596B overlay>
Copyright 2020 Sarah Walker <Main 586B code>
Copyright 2020 Miran Grca <Author>
Copyright 2020 Melissa Goad <Port to 86Box>
TODO:
- The SMBus must be checked and implemented properly
- Fix Documentation errors
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/cdrom.h>
#include "cpu.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/apm.h>
#include <86box/keyboard.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/port_92.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/zip.h>
#include <86box/machine.h>
#include <86box/chipset.h>
// As of now
#include <86box/smbus_piix4.h>
#define ACPI_TIMER_FREQ 3579545 // Probably Emulator related
#define ACPI_IO_ENABLE (1 << 7)
#define ACPI_TIMER_32BIT (1 << 3)
#if defined(DEV_BRANCH) && defined(USE_596B)
typedef struct
{
uint8_t pci_to_isa_regs[256]; // PCI-to-ISA (Same as 586B)
uint8_t ide_regs[256]; // Common VIA IDE controller
uint8_t usb_regs[256]; // Common VIA USB controller
uint8_t power_regs[256]; // VT82C596B Power Managment Device(Same as 586B + SMBus)
sff8038i_t * bm[2];
nvr_t * nvr;
int nvr_enabled, slot;
struct
{
uint16_t io_base;
}usb;
struct
{
uint16_t io_base;
}power;
smbus_piix4_t * smbus;
} via_vt82c596b_t;
static void
via_vt82c596b_reset(void *priv)
{
via_vt82c596b_t *via_vt82c596b = (via_vt82c596b_t *) priv;
uint16_t old_base = (via_vt82c596b->ide_regs[0x20] & 0xf0) | (via_vt82c596b->ide_regs[0x21] << 8);
sff_bus_master_reset(via_vt82c596b->bm[0], old_base);
sff_bus_master_reset(via_vt82c596b->bm[1], old_base + 8);
memset(via_vt82c596b->pci_to_isa_regs, 0, 256);
memset(via_vt82c596b->ide_regs, 0, 256);
memset(via_vt82c596b->usb_regs, 0, 256);
memset(via_vt82c596b->power_regs, 0, 256);
//PCI-to-ISA registers
via_vt82c596b->pci_to_isa_regs[0x00] = 0x06; //VIA
via_vt82c596b->pci_to_isa_regs[0x01] = 0x11;
via_vt82c596b->pci_to_isa_regs[0x02] = 0x96; //VT82C596B
via_vt82c596b->pci_to_isa_regs[0x03] = 0x05;
via_vt82c596b->pci_to_isa_regs[0x04] = 0x0f; //Control
via_vt82c596b->pci_to_isa_regs[0x07] = 2; //Status
via_vt82c596b->pci_to_isa_regs[0x09] = 0; //Program Interface
via_vt82c596b->pci_to_isa_regs[0x0A] = 1; //Sub-Class code
via_vt82c596b->pci_to_isa_regs[0x0B] = 6; //Class code
via_vt82c596b->pci_to_isa_regs[0x0E] = 0x80; //Header Type
via_vt82c596b->pci_to_isa_regs[0x2C] = 0x73; //Subsystem ID
via_vt82c596b->pci_to_isa_regs[0x2D] = 0x72;
via_vt82c596b->pci_to_isa_regs[0x2E] = 0x71;
via_vt82c596b->pci_to_isa_regs[0x2F] = 0x70;
via_vt82c596b->pci_to_isa_regs[0x48] = 1; //Miscellaneous control 3
via_vt82c596b->pci_to_isa_regs[0x4A] = 4;
via_vt82c596b->pci_to_isa_regs[0x4F] = 3;
via_vt82c596b->pci_to_isa_regs[0x50] = 0x24; //Reserved(?)
via_vt82c596b->pci_to_isa_regs[0x59] = 4; //PIRQ Pin Configuration
//Resetting the DMA
dma_e = 0x00;
for (int i = 0; i < 8; i++) {
dma[i].ab &= 0xffff000f;
dma[i].ac &= 0xffff000f;
}
pic_set_shadow(0);
//IDE registers
via_vt82c596b->ide_regs[0x00] = 0x06; //VIA
via_vt82c596b->ide_regs[0x01] = 0x11;
via_vt82c596b->ide_regs[0x02] = 0x71; //Common VIA IDE Controller
via_vt82c596b->ide_regs[0x03] = 0x05;
via_vt82c596b->ide_regs[0x04] = 0x80; //Command
via_vt82c596b->ide_regs[0x06] = 0x80; //Status
via_vt82c596b->ide_regs[0x07] = 0x02;
via_vt82c596b->ide_regs[0x09] = 0x85; //Programming Interface
via_vt82c596b->ide_regs[0x0A] = 0x01; //Sub class code
via_vt82c596b->ide_regs[0x0B] = 0x01; //Base class code
//Base address control commands
via_vt82c596b->ide_regs[0x10] = 0xF0;
via_vt82c596b->ide_regs[0x11] = 0x01;
via_vt82c596b->ide_regs[0x14] = 0xF4;
via_vt82c596b->ide_regs[0x15] = 0x03;
via_vt82c596b->ide_regs[0x18] = 0x70;
via_vt82c596b->ide_regs[0x19] = 0x01;
via_vt82c596b->ide_regs[0x1C] = 0x74;
via_vt82c596b->ide_regs[0x1D] = 0x03;
via_vt82c596b->ide_regs[0x20] = 0x01;
via_vt82c596b->ide_regs[0x21] = 0xCC;
////
via_vt82c596b->ide_regs[0x3C] = 0x0E; //Interrupt line
via_vt82c596b->ide_regs[0x40] = 0x08; //Chip Enable
via_vt82c596b->ide_regs[0x41] = 0x02; //IDE Configuration
via_vt82c596b->ide_regs[0x42] = 0x09; //Reserved
via_vt82c596b->ide_regs[0x43] = 0x3A; //FIFO Configuration
via_vt82c596b->ide_regs[0x44] = 0x68; //Miscellaneous Control 1
via_vt82c596b->ide_regs[0x46] = 0xC0; //Miscellaneous Control 3
via_vt82c596b->ide_regs[0x48] = 0xA8; //Driver Timing Control
via_vt82c596b->ide_regs[0x49] = 0xA8;
via_vt82c596b->ide_regs[0x4A] = 0xA8;
via_vt82c596b->ide_regs[0x4B] = 0xA8;
via_vt82c596b->ide_regs[0x4C] = 0xFF; //Address Setup Time
via_vt82c596b->ide_regs[0x4E] = 0xFF; //Sec Non-1F0 Port Access Timing
via_vt82c596b->ide_regs[0x4F] = 0xFF; //Pri Non-1F0 Port Access Timing
via_vt82c596b->ide_regs[0x50] = 0x03; //UltraDMA33 Extended Timing Control
via_vt82c596b->ide_regs[0x51] = 0x03;
via_vt82c596b->ide_regs[0x52] = 0x03;
via_vt82c596b->ide_regs[0x53] = 0x03;
via_vt82c596b->ide_regs[0x61] = 0x02; //IDE Primary Sector Size
via_vt82c596b->ide_regs[0x69] = 0x02; //IDE Secondary Sector Size
via_vt82c596b->usb_regs[0x00] = 0x06; //VIA USB Common Controller
via_vt82c596b->usb_regs[0x01] = 0x11;
via_vt82c596b->usb_regs[0x02] = 0x38;
via_vt82c596b->usb_regs[0x03] = 0x30;
//USB Registers
via_vt82c596b->usb_regs[0x04] = 0; //Control
via_vt82c596b->usb_regs[0x05] = 0;
via_vt82c596b->usb_regs[0x06] = 0;
via_vt82c596b->usb_regs[0x07] = 2; //Status
via_vt82c596b->usb_regs[0x0A] = 3; //Sub Class Code
via_vt82c596b->usb_regs[0x0B] = 0x0C; //Base Class Code
via_vt82c596b->usb_regs[0x0D] = 0x16; //Latency Timer
via_vt82c596b->usb_regs[0x20] = 1; //Base address
via_vt82c596b->usb_regs[0x21] = 3;
via_vt82c596b->usb_regs[0x3D] = 4; //Interrupt Pin
via_vt82c596b->usb_regs[0x60] = 0x10; //Serial Bus Release Number(USB 1.0)
via_vt82c596b->usb_regs[0xC1] = 0x20; //Legacy Support
//Power Management Registers
via_vt82c596b->power_regs[0x00] = 0x06; //VT82C596B Power Managment Controller
via_vt82c596b->power_regs[0x01] = 0x11;
via_vt82c596b->power_regs[0x02] = 0x50;
via_vt82c596b->power_regs[0x03] = 0x30;
via_vt82c596b->power_regs[0x04] = 0; //Control
via_vt82c596b->power_regs[0x05] = 0;
via_vt82c596b->power_regs[0x06] = 0x80; //Status
via_vt82c596b->power_regs[0x07] = 2;
via_vt82c596b->power_regs[0x48] = 1; //Power Managment IO Base
via_vt82c596b->power_regs[0x90] = 1; //SMBus IO Base
//Setting up Routing
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);
pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED);
//Disabling the Primary & Secondary controller(?)
ide_pri_disable();
ide_sec_disable();
}
// IDE CONTROLLER
static void
ide_handlers(via_vt82c596b_t *dev)
{
uint16_t main, side;
ide_pri_disable();
ide_sec_disable();
//On Bitfield 0(0x01) Primary Channel operating mode
if (dev->ide_regs[0x09] & 0x01) {
main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8);
side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2;
} else {
main = 0x1f0;
side = 0x3f6;
}
ide_set_base(0, main);
ide_set_side(0, side);
//On Bitfield 2(0x04) Secondary Channel operating mode
if (dev->ide_regs[0x09] & 0x04) {
main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8);
side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2;
} else {
main = 0x170;
side = 0x376;
}
ide_set_base(1, main);
ide_set_side(1, side);
//Enable the Primary & Secondary Controllers
if (dev->ide_regs[0x04] & PCI_COMMAND_IO) {
//On Bitfield 0(0x01) Enable the Secondary Controller
//On Bitfield 1(0x02) Enable the Primary Controller
if (dev->ide_regs[0x40] & 0x02)
ide_pri_enable();
if (dev->ide_regs[0x40] & 0x01)
ide_sec_enable();
}
}
static void
ide_irqs(via_vt82c596b_t *dev)
{
int irq_mode[2] = { 0, 0 };
if (dev->ide_regs[0x09] & 0x01)
irq_mode[0] = (dev->ide_regs[0x3d] & 0x01);
if (dev->ide_regs[0x09] & 0x04)
irq_mode[1] = (dev->ide_regs[0x3d] & 0x01);
sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]);
sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]);
}
static void
bus_master_handlers(via_vt82c596b_t *dev)
{
uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8);
//On Bitfield 0(0x01) I/O Space
sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base);
sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8);
}
////
// USB CONTROLLER
static uint8_t
usb_reg_read(uint16_t addr, void *p)
{
uint8_t ret = 0xff;
switch (addr & 0x1f) {
case 0x10: case 0x11: case 0x12: case 0x13:
// Return 0 on port status
ret = 0x00;
break;
}
return ret;
}
static void
usb_reg_write(uint16_t addr, uint8_t val, void *p) {}
static void
usb_update_io_mapping(via_vt82c596b_t *dev)
{
if (dev->usb.io_base != 0x0000)
io_removehandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev);
//On Bitfield 31 defaults to zero (0x20)
dev->usb.io_base = (dev->usb_regs[0x20] & ~0x1f) | (dev->usb_regs[0x21] << 8);
//0x20
//Master Interrupt Control(?)
//TODO: Find the exact meaning
if ((dev->usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->usb.io_base != 0x0000))
io_sethandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev);
}
////
// NVR
static void
nvr_update_io_mapping(via_vt82c596b_t *dev)
{
//0x74 CMOS Memory Address
//0x75 CMOS Memory Data
//Ports 74-75 may be used to access CMOS if the internal RTC is disabled.
if (dev->nvr_enabled)
nvr_at_handler(0, 0x0074, dev->nvr);
//In case of we are set on 5B bitfield 1(0x02)(RTC SRAM Access Enable) and 48 bitfield 3(0x08)
//(Extra RTC Port 74/75 Enable)
if ((dev->pci_to_isa_regs[0x5b] & 0x02) && (dev->pci_to_isa_regs[0x48] & 0x08))
nvr_at_handler(1, 0x0074, dev->nvr);
}
////
// POWER MANAGMENT
// Need excessive documentation
static uint8_t
power_reg_read(uint16_t addr, void *p)
{
via_vt82c596b_t *dev = (via_vt82c596b_t *) p;
uint32_t timer;
uint8_t ret = 0xff;
switch (addr & 0xff) {
case 0x08: case 0x09: case 0x0a: case 0x0b:
//ACPI Timer
timer = (tsc * ACPI_TIMER_FREQ) / machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed;
if (!(dev->power_regs[0x41] & ACPI_TIMER_32BIT))
timer &= 0x00ffffff;
ret = (timer >> (8 * (addr & 3))) & 0xff;
break;
}
return ret;
}
static void
power_reg_write(uint16_t addr, uint8_t val, void *p) {}
static void
power_update_io_mapping(via_vt82c596b_t *dev)
{
if (dev->power.io_base != 0x0000)
io_removehandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev);
dev->power.io_base = (dev->power_regs[0x49] << 8);
if ((dev->power_regs[0x41] & ACPI_IO_ENABLE) && (dev->power.io_base != 0x0000))
io_sethandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev);
}
static void
smbus_update_io_mapping(via_vt82c596b_t *dev)
{
smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), (dev->power_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->power_regs[0xD2] & 0x01));
}
////
static uint8_t
via_vt82c596b_read(int func, int addr, void *priv)
{
via_vt82c596b_t *dev = (via_vt82c596b_t *) priv;
uint8_t ret = 0xff;
int c;
switch(func) {
case 0:
//By System I/O Map, setting up the Keyboard Controller
//60-6F Keyboard Controller [0000 0000 0110] xnxn
if ((addr >= 0x60) && (addr <= 0x6f)) {
c = (addr & 0x0e) >> 1;
if (addr & 0x01) //If Enabled
ret = (dma[c].ab & 0x0000ff00) >> 8;
else {
ret = (dma[c].ab & 0x000000f0);
ret |= (!!(dma_e & (1 << c)) << 3);
}
} else
ret = dev->pci_to_isa_regs[addr];
break;
case 1:
ret = dev->ide_regs[addr];
break;
case 2:
ret = dev->usb_regs[addr];
break;
case 3:
ret = dev->power_regs[addr];
break;
}
return ret;
}
static void
via_vt82c596b_write(int func, int addr, uint8_t val, void *priv)
{
via_vt82c596b_t *dev = (via_vt82c596b_t *) priv;
int c;
//Excessive Documentation is needed!!
if (func > 3)
return;
switch(func) {
//PCI-to-ISA
case 0:
//Read-only addresses
if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) ||
(addr == 0x49) || (addr == 0x4b) || ((addr >= 0x51) && (addr < 0x54)) ||
((addr >= 0x5d) && (addr < 0x60)) ||
((addr >= 0x68) && (addr < 0x6a)) || (addr >= 0x73))
return;
switch (addr) {
case 0x04:
dev->pci_to_isa_regs[0x04] = (val & 8) | 7;
break;
case 0x07:
dev->pci_to_isa_regs[0x07] &= ~(val & 0xb0);
break;
case 0x47:
if ((val & 0x81) == 0x81)
resetx86();
pic_set_shadow(!!(val & 0x10));
pci_elcr_set_enabled(!!(val & 0x20));
dev->pci_to_isa_regs[0x47] = val & 0xfe;
break;
case 0x48:
dev->pci_to_isa_regs[0x48] = val;
nvr_update_io_mapping(dev);
break;
case 0x54:
pci_set_irq_level(PCI_INTA, !(val & 8));
pci_set_irq_level(PCI_INTB, !(val & 4));
pci_set_irq_level(PCI_INTC, !(val & 2));
pci_set_irq_level(PCI_INTD, !(val & 1));
break;
case 0x55:
pci_set_irq_routing(PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_to_isa_regs[0x55] = val;
break;
case 0x56:
pci_set_irq_routing(PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_to_isa_regs[0x56] = val;
break;
case 0x57:
pci_set_irq_routing(PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_to_isa_regs[0x57] = val;
break;
case 0x58:
pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_to_isa_regs[0x58] = val;
break;
case 0x5b:
dev->pci_to_isa_regs[0x5b] = val;
nvr_update_io_mapping(dev);
break;
case 0x60: case 0x62: case 0x64: case 0x66:
case 0x6a: case 0x6c: case 0x6e:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0);
dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0);
if (val & 0x08)
dma_e |= (1 << c);
else
dma_e &= ~(1 << c);
break;
case 0x61: case 0x63: case 0x65: case 0x67:
case 0x6b: case 0x6d: case 0x6f:
c = (addr & 0x0e) >> 1;
dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8);
dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8);
break;
case 0x70: case 0x71: case 0x72: case 0x73:
dev->pci_to_isa_regs[(addr - 0x44)] = val;
break;
}
break;
//IDE Controller
case 1:
//Read-only addresses
if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) ||
((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) ||
((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) ||
((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x54) && (addr < 0x60)) ||
((addr >= 0x52) && (addr < 0x68)) || (addr >= 0x62))
return;
switch (addr) {
case 0x04:
dev->ide_regs[0x04] = val & 0x85;
ide_handlers(dev);
bus_master_handlers(dev);
break;
case 0x07:
dev->ide_regs[0x07] &= ~(val & 0xf1);
break;
case 0x09:
dev->ide_regs[0x09] = (val & 0x05) | 0x8a;
ide_handlers(dev);
ide_irqs(dev);
break;
case 0x10:
dev->ide_regs[0x10] = (val & 0xf8) | 1;
ide_handlers(dev);
break;
case 0x11:
dev->ide_regs[0x11] = val;
ide_handlers(dev);
break;
case 0x14:
dev->ide_regs[0x14] = (val & 0xfc) | 1;
ide_handlers(dev);
break;
case 0x15:
dev->ide_regs[0x15] = val;
ide_handlers(dev);
break;
case 0x18:
dev->ide_regs[0x18] = (val & 0xf8) | 1;
ide_handlers(dev);
break;
case 0x19:
dev->ide_regs[0x19] = val;
ide_handlers(dev);
break;
case 0x1c:
dev->ide_regs[0x1c] = (val & 0xfc) | 1;
ide_handlers(dev);
break;
case 0x1d:
dev->ide_regs[0x1d] = val;
ide_handlers(dev);
break;
case 0x20:
dev->ide_regs[0x20] = (val & 0xf0) | 1;
bus_master_handlers(dev);
break;
case 0x21:
dev->ide_regs[0x21] = val;
bus_master_handlers(dev);
break;
case 0x3d:
dev->ide_regs[0x3d] = val & 0x01;
ide_irqs(dev);
break;
case 0x40:
dev->ide_regs[0x40] = val;
ide_handlers(dev);
break;
default:
dev->ide_regs[addr] = val;
break;
}
break;
//USB Controller
case 2:
//Read-only addresses
if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) ||
((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) ||
((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) ||
((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2))
return;
switch (addr) {
case 0x04:
dev->usb_regs[0x04] = val & 0x97;
usb_update_io_mapping(dev);
break;
case 0x07:
dev->usb_regs[0x07] &= ~(val & 0x78);
break;
case 0x20:
dev->usb_regs[0x20] = (val & ~0x1f) | 1;
usb_update_io_mapping(dev);
break;
case 0x21:
dev->usb_regs[0x21] = val;
usb_update_io_mapping(dev);
break;
default:
dev->usb_regs[addr] = val;
break;
}
break;
//Power Management
case 3:
//Read-Only Addresses
if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) ||
((addr >= 0x4a) && (addr < 0x50)) || (addr >= 0x54))
return;
switch (addr) {
case 0x41: case 0x49:
dev->power_regs[addr] = val;
power_update_io_mapping(dev);
smbus_update_io_mapping(dev);
break;
case 0x90:
dev->power_regs[0x90] = (val & 0xf0) | 1;
smbus_update_io_mapping(dev);
break;
case 0x91:
dev->power_regs[0x91] = val;
smbus_update_io_mapping(dev);
break;
default:
dev->power_regs[addr] = val;
break;
}
}
}
static void *
via_vt82c596b_init(const device_t *info)
{
via_vt82c596b_t *dev = (via_vt82c596b_t *) malloc(sizeof(via_vt82c596b_t));
memset(dev, 0, sizeof(via_vt82c596b_t));
dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, via_vt82c596b_read, via_vt82c596b_write, dev);
dev->bm[0] = device_add_inst(&sff8038i_device, 1);
sff_set_slot(dev->bm[0], dev->slot);
sff_set_irq_mode(dev->bm[0], 0, 0);
sff_set_irq_mode(dev->bm[0], 1, 0);
sff_set_irq_pin(dev->bm[0], PCI_INTA);
dev->bm[1] = device_add_inst(&sff8038i_device, 2);
sff_set_slot(dev->bm[1], dev->slot);
sff_set_irq_mode(dev->bm[1], 0, 0);
sff_set_irq_mode(dev->bm[1], 1, 0);
sff_set_irq_pin(dev->bm[1], PCI_INTA);
dev->nvr = device_add(&via_nvr_device);
via_vt82c596b_reset(dev);
dev->smbus = device_add(&piix4_smbus_device);
device_add(&port_92_pci_device);
dma_alias_set();
pci_enable_mirq(0);
pci_enable_mirq(1);
pci_enable_mirq(2);
return dev;
}
static void
via_vt82c596b_close(void *p)
{
via_vt82c596b_t *via_vt82c596b = (via_vt82c596b_t *)p;
free(via_vt82c596b);
}
const device_t via_vt82c596b_device =
{
"VIA VT82C596B",
DEVICE_PCI,
0,
via_vt82c596b_init,
via_vt82c596b_close,
NULL,
NULL,
NULL,
NULL,
NULL
};
#endif

View File

@@ -423,6 +423,7 @@ extern int machine_at_ax6bc_init(const machine_t *);
extern int machine_at_atc6310bxii_init(const machine_t *);
extern int machine_at_tsunamiatx_init(const machine_t *);
extern int machine_at_p6sba_init(const machine_t *);
extern int machine_at_6vx_init(const machine_t *);
#ifdef EMU_DEVICE_H
extern const device_t *at_tsunamiatx_get_device(void);

View File

@@ -567,6 +567,39 @@ machine_at_tsunamiatx_init(const machine_t *model)
}
int
machine_at_6vx_init(const machine_t *model)
{
int ret;
ret = bios_load_linear(L"roms/machines/6vx/6vx.f1a",
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, 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);
pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 3, 4);
device_add(&via_apro_device);
device_add(&via_vt82c596b_device);
device_add(&w83877f_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
return ret;
}
const device_t *
at_tsunamiatx_get_device(void)
{

View File

@@ -363,6 +363,7 @@ const machine_t machines[] = {
{ "[i440BX] A-Trend ATC6310BXII", "atc6310bxii", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_atc6310bxii_init, NULL },
{ "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_SOUND, 8, 1024, 8, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device },
{ "[i440BX] SuperMicro Super P6SBA", "p6sba", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_p6sba_init, NULL },
{ "[VIA Apollo Pro] Gigabyte GA-6VX", "6vx", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_6vx_init, NULL },
/* Slot 2 machines(Including Slot 1/2 Hybrids) */
/* 440GX */

View File

@@ -630,7 +630,7 @@ CHIPSETOBJ := acc2168.o cs8230.o ali1429.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 opti895.o opti5x7.o scamp.o scat.o via_vt82c49x.o via_vt82c505.o \
sis_85c310.o sis_85c471.o sis_85c496.o opti283.o opti291.o umc491.o \
via_apollo.o via_vpx.o via_vt82c586b.o via_vt82c596b.o wd76c10.o vl82c480.o \
via_apollo.o via_vpx.o via_pipc.o wd76c10.o vl82c480.o \
amd640.o
MCHOBJ := machine.o machine_table.o \