Files
86Box/src/chipset/via_vt82c49x.c
Jasmine Iwanek 998cfe5cc8 Constification
2023-07-25 17:59:24 -04:00

424 lines
12 KiB
C

/*
* 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 VIA VT82C49X chipset.
*
*
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020 Tiseno100.
* Copyright 2020 Miran Grca.
*/
#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 "cpu.h"
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/smram.h>
#include <86box/pic.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
typedef struct vt82c49x_t {
uint8_t has_ide;
uint8_t index;
uint8_t regs[256];
smram_t *smram_smm;
smram_t *smram_low;
smram_t *smram_high;
} vt82c49x_t;
#ifdef ENABLE_VT82C49X_LOG
int vt82c49x_do_log = ENABLE_VT82C49X_LOG;
static void
vt82c49x_log(const char *fmt, ...)
{
va_list ap;
if (vt82c49x_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define vt82c49x_log(fmt, ...)
#endif
static void
vt82c49x_recalc(vt82c49x_t *dev)
{
int relocate;
uint8_t reg;
uint8_t bit;
uint32_t base;
uint32_t state;
uint32_t shadow_bitmap = 0x00000000;
relocate = (dev->regs[0x33] >> 2) & 0x03;
shadowbios = 0;
shadowbios_write = 0;
for (uint8_t i = 0; i < 8; i++) {
base = 0xc0000 + (i << 14);
reg = 0x30 + (i >> 2);
bit = (i & 3) << 1;
if ((base >= 0xc0000) && (base <= 0xc7fff)) {
if (dev->regs[0x40] & 0x80)
state = MEM_WRITE_DISABLED;
else if ((dev->regs[reg]) & (1 << bit))
state = MEM_WRITE_INTERNAL;
else
state = (dev->regs[0x33] & 0x40) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL;
if ((dev->regs[reg]) & (1 << (bit + 1)))
state |= MEM_READ_INTERNAL;
else
state |= (dev->regs[0x33] & 0x40) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL;
}
if ((base >= 0xc8000) && (base <= 0xcffff)) {
if ((dev->regs[reg]) & (1 << bit))
state = MEM_WRITE_INTERNAL;
else
state = (dev->regs[0x33] & 0x80) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL;
if ((dev->regs[reg]) & (1 << (bit + 1)))
state |= MEM_READ_INTERNAL;
else
state |= (dev->regs[0x33] & 0x80) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL;
} else {
state = ((dev->regs[reg]) & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
state |= ((dev->regs[reg]) & (1 << (bit + 1))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
}
vt82c49x_log("(%02X=%02X, %i) Setting %08X-%08X to: write %sabled, read %sabled\n",
reg, dev->regs[reg], bit, base, base + 0x3fff,
((dev->regs[reg]) & (1 << bit)) ? "en" : "dis", ((dev->regs[reg]) & (1 << (bit + 1))) ? "en" : "dis");
if ((dev->regs[reg]) & (1 << bit))
shadow_bitmap |= (1 << i);
if ((dev->regs[reg]) & (1 << (bit + 1)))
shadow_bitmap |= (1 << (i + 16));
mem_set_mem_state_both(base, 0x4000, state);
}
for (uint8_t i = 0; i < 4; i++) {
base = 0xe0000 + (i << 15);
bit = 6 - (i & 2);
if ((base >= 0xe0000) && (base <= 0xe7fff)) {
if (dev->regs[0x40] & 0x20)
state = MEM_WRITE_DISABLED;
else if ((dev->regs[0x32]) & (1 << bit))
state = MEM_WRITE_INTERNAL;
else
state = (dev->regs[0x33] & 0x10) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL;
if ((dev->regs[0x32]) & (1 << (bit + 1)))
state |= MEM_READ_INTERNAL;
else
state |= (dev->regs[0x33] & 0x10) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL;
} else if ((base >= 0xe8000) && (base <= 0xeffff)) {
if (dev->regs[0x40] & 0x20)
state = MEM_WRITE_DISABLED;
else if ((dev->regs[0x32]) & (1 << bit))
state = MEM_WRITE_INTERNAL;
else
state = (dev->regs[0x33] & 0x20) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL;
if ((dev->regs[0x32]) & (1 << (bit + 1)))
state |= MEM_READ_INTERNAL;
else
state |= (dev->regs[0x33] & 0x20) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL;
} else {
if (dev->regs[0x40] & 0x40)
state = MEM_WRITE_DISABLED;
else if ((dev->regs[0x32]) & (1 << bit))
state = ((dev->regs[0x32]) & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
state |= ((dev->regs[0x32]) & (1 << (bit + 1))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
}
vt82c49x_log("(32=%02X, %i) Setting %08X-%08X to: write %sabled, read %sabled\n",
dev->regs[0x32], bit, base, base + 0x7fff,
((dev->regs[0x32]) & (1 << bit)) ? "en" : "dis", ((dev->regs[0x32]) & (1 << (bit + 1))) ? "en" : "dis");
if ((dev->regs[0x32]) & (1 << bit)) {
shadow_bitmap |= (0xf << ((i << 2) + 8));
shadowbios_write |= 1;
}
if ((dev->regs[0x32]) & (1 << (bit + 1))) {
shadow_bitmap |= (0xf << ((i << 2) + 24));
shadowbios |= 1;
}
mem_set_mem_state_both(base, 0x8000, state);
}
vt82c49x_log("Shadow bitmap: %08X\n", shadow_bitmap);
mem_remap_top(0);
switch (relocate) {
case 0x02:
if (!(shadow_bitmap & 0xfff0fff0))
mem_remap_top(256);
break;
case 0x03:
if (!shadow_bitmap)
mem_remap_top(384);
break;
default:
break;
}
}
static void
vt82c49x_write(uint16_t addr, uint8_t val, void *priv)
{
vt82c49x_t *dev = (vt82c49x_t *) priv;
uint8_t valxor;
switch (addr) {
case 0xa8:
dev->index = val;
break;
case 0xa9:
valxor = (val ^ dev->regs[dev->index]);
if (dev->index == 0x55)
dev->regs[dev->index] &= ~val;
else
dev->regs[dev->index] = val;
vt82c49x_log("dev->regs[0x%02x] = %02x\n", dev->index, val);
switch (dev->index) {
/* Wait States */
case 0x03:
cpu_update_waitstates();
break;
/* Shadow RAM and top of RAM relocation */
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x40:
vt82c49x_recalc(dev);
break;
/* External Cache Enable(Based on the 486-VC-HD BIOS) */
case 0x50:
cpu_cache_ext_enabled = (val & 0x84);
break;
/* Software SMI */
case 0x54:
if ((dev->regs[0x5b] & 0x80) && (valxor & 0x01) && (val & 0x01)) {
if (dev->regs[0x5b] & 0x20)
smi_raise();
else
picint(1 << 15);
dev->regs[0x55] = 0x01;
}
break;
/* SMRAM */
case 0x5b:
smram_disable_all();
if (val & 0x80) {
smram_enable(dev->smram_smm, (val & 0x40) ? 0x00060000 : 0x00030000, 0x000a0000, 0x00020000,
0, (val & 0x10));
smram_enable(dev->smram_high, 0x000a0000, 0x000a0000, 0x00020000,
(val & 0x08), (val & 0x08));
smram_enable(dev->smram_low, 0x00030000, 0x000a0000, 0x00020000,
(val & 0x02), 0);
}
break;
/* Edge/Level IRQ Control */
case 0x62:
case 0x63:
if (dev->index == 0x63)
pic_elcr_write(dev->index, val & 0xde, &pic2);
else {
pic_elcr_write(dev->index, val & 0xf8, &pic);
pic_elcr_set_enabled(val & 0x01);
}
break;
/* Local Bus IDE Controller */
case 0x71:
if (dev->has_ide) {
ide_pri_disable();
ide_set_base(0, (val & 0x40) ? 0x170 : 0x1f0);
ide_set_side(0, (val & 0x40) ? 0x376 : 0x3f6);
if (val & 0x01)
ide_pri_enable();
vt82c49x_log("VT82C496 IDE now %sabled as %sary\n", (val & 0x01) ? "en" : "dis",
(val & 0x40) ? "second" : "prim");
}
break;
default:
break;
}
break;
default:
break;
}
}
static uint8_t
vt82c49x_read(uint16_t addr, void *priv)
{
uint8_t ret = 0xff;
const vt82c49x_t *dev = (vt82c49x_t *) priv;
switch (addr) {
case 0xa9:
/* Register 64h is jumper readout. */
if (dev->index == 0x64)
ret = 0xff;
else if (dev->index == 0x63)
ret = pic_elcr_read(dev->index, &pic2) | (dev->regs[dev->index] & 0x01);
else if (dev->index == 0x62)
ret = pic_elcr_read(dev->index, &pic) | (dev->regs[dev->index] & 0x07);
else if (dev->index < 0x80)
ret = dev->regs[dev->index];
break;
default:
break;
}
return ret;
}
static void
vt82c49x_reset(void *priv)
{
for (uint16_t i = 0; i < 256; i++)
vt82c49x_write(i, 0x00, priv);
}
static void
vt82c49x_close(void *priv)
{
vt82c49x_t *dev = (vt82c49x_t *) priv;
smram_del(dev->smram_high);
smram_del(dev->smram_low);
smram_del(dev->smram_smm);
free(dev);
}
static void *
vt82c49x_init(const device_t *info)
{
vt82c49x_t *dev = (vt82c49x_t *) malloc(sizeof(vt82c49x_t));
memset(dev, 0x00, sizeof(vt82c49x_t));
dev->smram_smm = smram_add();
dev->smram_low = smram_add();
dev->smram_high = smram_add();
dev->has_ide = info->local & 1;
if (dev->has_ide) {
device_add(&ide_vlb_2ch_device);
ide_sec_disable();
}
device_add(&port_92_device);
io_sethandler(0x0a8, 0x0002, vt82c49x_read, NULL, NULL, vt82c49x_write, NULL, NULL, dev);
pic_elcr_io_handler(0);
pic_elcr_set_enabled(1);
vt82c49x_recalc(dev);
return dev;
}
const device_t via_vt82c49x_device = {
.name = "VIA VT82C49X",
.internal_name = "via_vt82c49x",
.flags = 0,
.local = 0,
.init = vt82c49x_init,
.close = vt82c49x_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t via_vt82c49x_pci_device = {
.name = "VIA VT82C49X PCI",
.internal_name = "via_vt82c49x_pci",
.flags = DEVICE_PCI,
.local = 0,
.init = vt82c49x_init,
.close = vt82c49x_close,
.reset = vt82c49x_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t via_vt82c49x_ide_device = {
.name = "VIA VT82C49X (With IDE)",
.internal_name = "via_vt82c49x_ide",
.flags = 0,
.local = 1,
.init = vt82c49x_init,
.close = vt82c49x_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t via_vt82c49x_pci_ide_device = {
.name = "VIA VT82C49X PCI (With IDE)",
.internal_name = "via_vt82c49x_pci_ide",
.flags = DEVICE_PCI,
.local = 1,
.init = vt82c49x_init,
.close = vt82c49x_close,
.reset = vt82c49x_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};