From 5d68fa68c0fd73e4427b4c737c9284dfcaca4d6c Mon Sep 17 00:00:00 2001 From: Panagiotis <58827426+tiseno100@users.noreply.github.com> Date: Mon, 5 Apr 2021 22:28:04 +0300 Subject: [PATCH] Implemented the OPTi 822 VLB to PCI bridge Needed for early OPTi Pentium's but also 486's like the Packard Bell PB450 PCI. IRQ routing is hacking though!! --- src/chipset/opti5x7.c | 67 ++++---- src/chipset/opti822.c | 322 +++++++++++++++++++++++++++++++++++ src/include/86box/chipset.h | 2 + src/include/86box/machine.h | 3 + src/machine/m_at_socket4_5.c | 55 ++++++ src/machine/machine_table.c | 4 + 6 files changed, 416 insertions(+), 37 deletions(-) create mode 100644 src/chipset/opti822.c diff --git a/src/chipset/opti5x7.c b/src/chipset/opti5x7.c index 1199c634f..9c506daad 100644 --- a/src/chipset/opti5x7.c +++ b/src/chipset/opti5x7.c @@ -32,32 +32,6 @@ #include <86box/port_92.h> #include <86box/chipset.h> -/* Shadow RAM */ - -/* Register 4h: C0000-CFFFF range | Register 5h: D0000-DFFFF range */ -#define CURRENT_REGISTER dev->regs[4 + !!(i & 4)] - -/* -Bits 7-6: xC000-xFFFF -Bits 5-4: x8000-xBFFF -Bits 3-2: x4000-x7FFF -Bits 0-1: x0000-x3FFF - - x-y - 0 0 Read/Write AT bus - 1 0 Read from AT - Write to DRAM - 1 1 Read from DRAM - Write to DRAM - 0 1 Read from DRAM (write protected) -*/ -#define CAN_READ (1 << (i - (4 * !!(i & 4))) * 2) -#define CAN_WRITE (1 << ((i - (4 * !!(i & 4))) * 2 + 1)) - -/* Shadow Recalc for the C/D segments */ -#define SHADOW_RECALC (((CURRENT_REGISTER & CAN_READ) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((CURRENT_REGISTER & CAN_WRITE) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)) - -/* Shadow Recalc for the E/F segments */ -#define SHADOW_EF_RECALC (((dev->regs[6] & CAN_READ) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[6] & CAN_WRITE) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)) - typedef struct { uint8_t idx, regs[16]; @@ -83,17 +57,36 @@ opti5x7_log(const char *fmt, ...) #endif static void -shadow_map(opti5x7_t *dev) +opti5x7_shadow_map(int cur_reg, opti5x7_t *dev) { - for (int i = 0; i < 8; i++) + +/* +Register 4h: Cxxxx Segment +Register 5h: Dxxxx Segment + +Bits 7-6: xC000-xFFFF +Bits 5-4: x8000-xBFFF +Bits 3-2: x4000-x7FFF +Bits 0-1: x0000-x3FFF + + x-y + 0 0 Read/Write AT bus + 1 0 Read from AT - Write to DRAM + 1 1 Read from DRAM - Write to DRAM + 0 1 Read from DRAM (write protected) +*/ + if (cur_reg == 0x06) { - mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, SHADOW_RECALC); - if (i < 2) - mem_set_mem_state_both(0xe0000 + (i << 16), 0x10000, SHADOW_EF_RECALC); + mem_set_mem_state_both(0xe0000, 0x10000, ((dev->regs[6] & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[6] & 2) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0xf0000, 0x10000, ((dev->regs[6] & 4) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[6] & 8) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); } - shadowbios = !!(dev->regs[0x06] & 5); - shadowbios_write = !!(dev->regs[0x06] & 0x0a); - flushmmucache(); + else + { + for (int i = 0; i < 4; i++) + mem_set_mem_state_both(0xc0000 + ((cur_reg & 1) << 16) + (i << 14), 0x4000, ((dev->regs[cur_reg] & (1 << (2 * i))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[cur_reg] & (2 << (2 * i))) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + } + + flushmmucache_nopc(); } static void @@ -107,7 +100,6 @@ opti5x7_write(uint16_t addr, uint8_t val, void *priv) dev->idx = val; break; case 0x24: - opti5x7_log("OPTi 5x7: dev->regs[%02x] = %02x\n", dev->idx, val); switch (dev->idx) { case 0x00: /* DRAM Configuration Register #1 */ @@ -116,7 +108,7 @@ opti5x7_write(uint16_t addr, uint8_t val, void *priv) case 0x01: /* DRAM Control Register #1 */ dev->regs[dev->idx] = val; break; - case 0x02: /* Cache Control Register #1 */ + case 0x02: /* Cache Control Register #1 */ dev->regs[dev->idx] = val; cpu_cache_ext_enabled = !!(dev->regs[0x02] & 0x0c); cpu_update_waitstates(); @@ -128,7 +120,7 @@ opti5x7_write(uint16_t addr, uint8_t val, void *priv) case 0x05: /* Shadow RAM Control Register #2 */ case 0x06: /* Shadow RAM Control Register #3 */ dev->regs[dev->idx] = val; - shadow_map(dev); + opti5x7_shadow_map(dev->idx, dev); break; case 0x07: /* Tag Test Register */ case 0x08: /* CPU Cache Control Register #1 */ @@ -148,6 +140,7 @@ opti5x7_write(uint16_t addr, uint8_t val, void *priv) dev->regs[dev->idx] = val; break; } + opti5x7_log("OPTi 5x7: dev->regs[%02x] = %02x\n", dev->idx, dev->regs[dev->idx]); break; } } diff --git a/src/chipset/opti822.c b/src/chipset/opti822.c new file mode 100644 index 000000000..546a9778f --- /dev/null +++ b/src/chipset/opti822.c @@ -0,0 +1,322 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the OPTi 82C822 VESA Local Bus to PCI Bridge Interface. + * + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/mem.h> +#include <86box/pci.h> + +#include <86box/chipset.h> + +/* Shadow RAM */ +#define SYSTEM_READ ((dev->pci_conf[0x44] & 2) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define SYSTEM_WRITE ((dev->pci_conf[0x44] & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) +#define SHADOW_READ ((dev->pci_conf[cur_reg] & (1 << (4 + i))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define SHADOW_WRITE ((dev->pci_conf[cur_reg] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) + +#ifdef ENABLE_OPTI822_LOG +int opti822_do_log = ENABLE_OPTI822_LOG; +static void +opti822_log(const char *fmt, ...) +{ + va_list ap; + + if (opti822_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti822_log(fmt, ...) +#endif + +typedef struct opti822_t +{ + uint8_t pci_conf[256]; +} opti822_t; + +int opti822_irq_routing[7] = {5, 9, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f}; + +void opti822_shadow(int cur_reg, opti822_t *dev) +{ + if (cur_reg == 0x44) + mem_set_mem_state_both(0xf0000, 0x10000, SYSTEM_READ | SYSTEM_WRITE); + else + for (int i = 0; i < 4; i++) + mem_set_mem_state_both(0xe0000 - (((cur_reg & 3) - 1) << 16) + (i << 14), 0x4000, SHADOW_READ | SHADOW_WRITE); + + flushmmucache_nopc(); +} + +static void +opti822_write(int func, int addr, uint8_t val, void *priv) +{ + + opti822_t *dev = (opti822_t *)priv; + + switch (func) + { + case 0x04: /* Command Register */ + dev->pci_conf[addr] = val & 0x40; + break; + + case 0x05: /* Command Register */ + dev->pci_conf[addr] = val & 1; + break; + + case 0x06: /* Status Register */ + dev->pci_conf[addr] |= val & 0xc0; + break; + + case 0x07: /* Status Register */ + dev->pci_conf[addr] = val & 0xa9; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0xc0; + break; + + case 0x41: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0x42: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x43: + dev->pci_conf[addr] = val; + break; + + case 0x44: /* Shadow RAM */ + case 0x45: + case 0x46: + case 0x47: + dev->pci_conf[addr] = (addr == 0x44) ? (val & 0xcb) : val; + opti822_shadow(addr, dev); + break; + + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + dev->pci_conf[addr] = val; + break; + + case 0x58: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + dev->pci_conf[addr] = val; + break; + + case 0x60: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + dev->pci_conf[addr] = val; + break; + + case 0x68: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + dev->pci_conf[addr] = val; + break; + + case 0x70: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x71: + case 0x72: + case 0x73: + dev->pci_conf[addr] = val; + break; + + case 0x74: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x75: + case 0x76: + dev->pci_conf[addr] = val; + break; + + case 0x77: + dev->pci_conf[addr] = val & 0xe7; + break; + + case 0x78: + dev->pci_conf[addr] = val; + break; + + case 0x79: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + dev->pci_conf[addr] = val; + break; + + case 0x7f: + dev->pci_conf[addr] = val & 3; + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x86: + dev->pci_conf[addr] = val; + break; + + case 0x88: /* PCI IRQ Routing */ + case 0x89: /* Very hacky implementation. Needs surely a rewrite after */ + case 0x8a: /* a PCI rework happens. */ + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + dev->pci_conf[addr] = val; + if (addr % 2) + { + pci_set_irq_routing(PCI_INTB, ((val & 0x0f) != 0) ? opti822_irq_routing[(val & 7) - 1] : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTA, (((val >> 4) & 0x0f) != 0) ? opti822_irq_routing[((val >> 4) & 7) - 1] : PCI_IRQ_DISABLED); + } + else + { + pci_set_irq_routing(PCI_INTD, ((val & 0x0f) != 0) ? opti822_irq_routing[(val & 7) - 1] : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, (((val >> 4) & 0x0f) != 0) ? opti822_irq_routing[((val >> 4) & 7) - 1] : PCI_IRQ_DISABLED); + } + break; + } + + opti822_log("OPTI822: dev->pci_conf[%02x] = %02x\n", addr, dev->pci_conf[addr]); +} + +static uint8_t +opti822_read(int func, int addr, void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + return dev->pci_conf[addr]; +} + +static void +opti822_reset(void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + + dev->pci_conf[0x00] = 0x45; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x22; + dev->pci_conf[0x03] = 0xc8; + dev->pci_conf[0x04] = 7; + dev->pci_conf[0x06] = 0x40; + dev->pci_conf[0x07] = 1; + dev->pci_conf[0x08] = 1; + dev->pci_conf[0x0b] = 6; + dev->pci_conf[0x0d] = 0x20; + dev->pci_conf[0x40] = 1; + dev->pci_conf[0x43] = 0x20; + dev->pci_conf[0x52] = 6; + dev->pci_conf[0x53] = 0x90; +} + +static void +opti822_close(void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + + free(dev); +} + +static void * +opti822_init(const device_t *info) +{ + opti822_t *dev = (opti822_t *)malloc(sizeof(opti822_t)); + memset(dev, 0, sizeof(opti822_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, opti822_read, opti822_write, dev); + + opti822_reset(dev); + + return dev; +} + +const device_t opti822_device = { + "OPTi 82C822 PCIB", + DEVICE_PCI, + 0, + opti822_init, + opti822_close, + opti822_reset, + {NULL}, + NULL, + NULL, + NULL}; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 8e433e713..79be9dd6f 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -97,7 +97,9 @@ extern const device_t opti291_device; extern const device_t opti493_device; extern const device_t opti495_device; extern const device_t opti802g_device; +extern const device_t opti822_device; extern const device_t opti895_device; + extern const device_t opti5x7_device; /* SiS */ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 6d7bd69d0..e5ae67d8f 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -380,6 +380,9 @@ extern const device_t *at_cpqiii_get_device(void); /* m_at_socket4_5.c */ extern int machine_at_excalibur_init(const machine_t *); +extern int machine_at_hot543_init(const machine_t *); +extern int machine_at_p54vl_init(const machine_t *); + extern int machine_at_batman_init(const machine_t *); extern int machine_at_ambradp60_init(const machine_t *); extern int machine_at_dellxp60_init(const machine_t *); diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket4_5.c index 7cab65e8c..548ec039b 100644 --- a/src/machine/m_at_socket4_5.c +++ b/src/machine/m_at_socket4_5.c @@ -63,6 +63,61 @@ machine_at_excalibur_init(const machine_t *model) return ret; } +int +machine_at_hot543_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hot543/543_R21.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + +int +machine_at_p54vl_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54vl/SM507.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} static void machine_at_premiere_common_init(const machine_t *model, int pci_switch) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 0be485d26..192b76320 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -282,6 +282,10 @@ const machine_t machines[] = { { "[i430FX] NEC PowerMate V", "powermate_v", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 2.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_powermate_v_init, NULL }, { "[i430FX] PC Partner MB500N", "mb500n", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 3380, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb500n_init, NULL }, + /* OPTi 596/597/822 */ + { "[OPTi 597] Shuttle HOT-543", "hot543", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_hot543_init, NULL }, + { "[OPTi 597] Supermicro P54VL-PCI", "p54vl", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, 0, 60000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_VLB, 8192, 131072, 8192, 127, machine_at_p54vl_init, NULL }, + /* SiS 85C50x */ { "[SiS 85C50x] ASUS PCI/I-P54SP4", "p54sp4", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_K5, CPU_5K86), 40000000, 66666667, 3380, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_p54sp4_init, NULL }, { "[SiS 85C50x] BCM SQ-588", "sq588", MACHINE_TYPE_SOCKET5, CPU_PKG_SOCKET5_7, CPU_BLOCK(CPU_PENTIUMMMX), 50000000, 66666667, 3520, 3520, 1.5, 1.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_sq588_init, NULL },