Move ICH2 to it's own branch

This commit is contained in:
Jasmine Iwanek
2022-07-23 02:22:54 -04:00
committed by GitHub
40 changed files with 4877 additions and 75 deletions

View File

@@ -35,6 +35,7 @@
#include <86box/nvr.h>
#include <86box/pit.h>
#include <86box/apm.h>
#include <86box/tco.h>
#include <86box/acpi.h>
#include <86box/machine.h>
#include <86box/i2c.h>
@@ -160,6 +161,8 @@ acpi_raise_smi(void *priv, int do_smi)
smi_raise();
}
}
else if ((dev->vendor == VEN_INTEL_ICH2) && do_smi && (dev->regs.smi_en & 1))
smi_line = 1;
}
@@ -346,6 +349,83 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p)
}
static uint32_t
acpi_reg_read_intel_ich2(int size, uint16_t addr, void *p)
{
acpi_t *dev = (acpi_t *) p;
uint32_t ret = 0x00000000;
int shift16, shift32;
addr &= 0x7f;
shift16 = (addr & 1) << 3;
shift32 = (addr & 3) << 3;
switch (addr) {
case 0x10: case 0x11: case 0x12: case 0x13:
/* PROC_CNT—Processor Control Register */
ret = (dev->regs.pcntrl >> shift32) & 0xff;
break;
case 0x28: case 0x29:
/* GPE0_STS—General Purpose Event 0 Status Register */
ret = (dev->regs.gpsts >> shift16) & 0xff;
break;
case 0x2a: case 0x2b:
/* GPE0_EN—General Purpose Event 0 Enables Register */
ret = (dev->regs.gpen >> shift16) & 0xff;
break;
case 0x2c: case 0x2d:
/* GPE1_STS—General Purpose Event 1 Status Register */
ret = (dev->regs.gpsts1 >> shift16) & 0xff;
break;
case 0x2e: case 0x2f:
/* GPE1_EN—General Purpose Event 1 Enable Register */
ret = (dev->regs.gpen1 >> shift16) & 0xff;
break;
case 0x30: case 0x31: case 0x32: case 0x33:
/* SMI_EN—SMI Control and Enable Register */
ret = (dev->regs.smi_en >> shift32) & 0xff;
break;
case 0x34: case 0x35: case 0x36: case 0x37:
/* SMI_STS—SMI Status Register */
ret = (dev->regs.smi_sts >> shift32) & 0xff;
break;
case 0x40: case 0x41:
/* MON_SMI—Device Monitor SMI Status and Enable Register */
ret = (dev->regs.mon_smi >> shift16) & 0xff;
break;
case 0x44: case 0x45:
/* DEVACT_STS—Device Activity Status Register */
ret = (dev->regs.devact_sts >> shift16) & 0xff;
break;
case 0x48: case 0x49:
/* DEVTRAP_EN—Device Trap Enable Register */
ret = (dev->regs.devtrap_en >> shift16) & 0xff;
break;
case 0x4c ... 0x4d:
/* BUS_ADDR_TRACK—Bus Address Tracker Register */
ret = (dev->regs.bus_addr_track >> shift16) & 0xff;
break;
case 0x4e:
/* BUS_CYC_TRACK—Bus Cycle Tracker Register */
ret = dev->regs.bus_cyc_track;
break;
case 0x60 ... 0x70:
/* TCO Registers */
ret = tco_read(addr, dev->tco);
break;
default:
ret = acpi_reg_read_common_regs(size, addr, p);
break;
}
#ifdef ENABLE_ACPI_LOG
// if (size != 1)
// acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
#endif
return ret;
}
static uint32_t
acpi_reg_read_via_common(int size, uint16_t addr, void *p)
{
@@ -605,7 +685,11 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p)
break;
case 0x04: case 0x05:
/* PMCNTRL - Power Management Control Register (IO) */
if ((addr == 0x05) && (val & 0x20)) {
if((addr == 0x05) && !!(val & 0x20) && !!(val & 4) && !!(dev->regs.smi_en & 0x00000010) && (dev->vendor == VEN_INTEL_ICH2)) {
dev->regs.smi_sts |= 0x00000010; /* ICH2 Specific. Trigger an SMI if SLP_SMI_EN bit is set instead of transistioning to a Sleep State. */
acpi_raise_smi(dev, 1);
}
else if ((addr == 0x05) && (val & 0x20)) {
sus_typ = dev->suspend_types[(val >> 2) & 7];
if (sus_typ & SUS_POWER_OFF) {
@@ -796,6 +880,99 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p)
}
static void
acpi_reg_write_intel_ich2(int size, uint16_t addr, uint8_t val, void *p)
{
acpi_t *dev = (acpi_t *) p;
int shift16, shift32;
addr &= 0x7f;
#ifdef ENABLE_ACPI_LOG
if (size != 1)
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
#endif
shift16 = (addr & 1) << 3;
shift32 = (addr & 3) << 3;
switch (addr) {
case 0x10: case 0x11: case 0x12: case 0x13:
/* PROC_CNT—Processor Control Register */
dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x000201fe;
break;
case 0x28: case 0x29:
/* GPE0_STS—General Purpose Event 0 Status Register */
dev->regs.gpsts &= ~((val << shift16) & 0x09fb);
break;
case 0x2a: case 0x2b:
/* GPE0_EN—General Purpose Event 0 Enables Register */
dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x097d;
break;
case 0x2c: case 0x2d:
/* GPE1_STS—General Purpose Event 1 Status Register */
dev->regs.gpsts1 &= ~((val << shift16) & 0x09fb);
break;
case 0x2e: case 0x2f:
/* GPE1_EN—General Purpose Event 1 Enable Register */
dev->regs.gpen1 = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x097d;
break;
case 0x30: case 0x31: case 0x32: case 0x33:
/* SMI_EN—SMI Control and Enable Register */
dev->regs.smi_en = ((dev->regs.smi_en & ~(0xff << shift32)) | (val << shift32)) & 0x0000867f;
if(addr == 0x30) {
apm_set_do_smi(dev->apm, !!(val & 0x20));
if(val & 0x80) {
dev->regs.glbsts |= 0x0020;
acpi_update_irq(dev);
}
}
break;
case 0x34: case 0x35: case 0x36: case 0x37:
/* SMI_STS—SMI Status Register */
dev->regs.smi_sts &= ~((val << shift32) & 0x0001ff7c);
break;
case 0x40: case 0x41:
/* MON_SMI—Device Monitor SMI Status and Enable Register */
dev->regs.mon_smi = ((dev->regs.mon_smi & ~(0xff << shift16)) | (val << shift16)) & 0x097d;
break;
case 0x44: case 0x45:
/* DEVACT_STS—Device Activity Status Register */
dev->regs.devact_sts &= ~((val << shift16) & 0x3fef);
break;
case 0x48: case 0x49:
/* DEVTRAP_EN—Device Trap Enable Register */
dev->regs.devtrap_en = ((dev->regs.devtrap_en & ~(0xff << shift16)) | (val << shift16)) & 0x3c2f;
if (dev->trap_update)
dev->trap_update(dev->trap_priv);
break;
case 0x4c ... 0x4d:
/* BUS_ADDR_TRACK—Bus Address Tracker Register */
dev->regs.bus_addr_track = ((dev->regs.bus_addr_track & ~(0xff << shift16)) | (val << shift16)) & 0x097d;
break;
case 0x4e:
/* BUS_CYC_TRACK—Bus Cycle Tracker Register */
dev->regs.bus_cyc_track = val;
break;
case 0x60 ... 0x70:
/* TCO Registers */
tco_write(addr, val, dev->tco);
break;
default:
acpi_reg_write_common_regs(size, addr, val, p);
if((addr == 0x04) && !!(val & 4) && !!(dev->regs.smi_en & 4)) {
dev->regs.smi_sts = 0x00000004;
acpi_raise_smi(dev, 1);
}
if((addr == 0x02) || !!(val & 0x20) || !!(dev->regs.glbsts & 0x0020))
acpi_update_irq(dev);
break;
}
}
static void
acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p)
{
@@ -1063,6 +1240,8 @@ acpi_reg_read_common(int size, uint16_t addr, void *p)
ret = acpi_reg_read_via_596b(size, addr, p);
else if (dev->vendor == VEN_INTEL)
ret = acpi_reg_read_intel(size, addr, p);
else if (dev->vendor == VEN_INTEL_ICH2)
ret = acpi_reg_read_intel_ich2(size, addr, p);
else if (dev->vendor == VEN_SMC)
ret = acpi_reg_read_smc(size, addr, p);
@@ -1083,6 +1262,8 @@ acpi_reg_write_common(int size, uint16_t addr, uint8_t val, void *p)
acpi_reg_write_via_596b(size, addr, val, p);
else if (dev->vendor == VEN_INTEL)
acpi_reg_write_intel(size, addr, val, p);
else if (dev->vendor == VEN_INTEL_ICH2)
acpi_reg_write_intel_ich2(size, addr, val, p);
else if (dev->vendor == VEN_SMC)
acpi_reg_write_smc(size, addr, val, p);
}
@@ -1276,6 +1457,7 @@ acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en)
case VEN_VIA:
size = 0x100;
break;
case VEN_INTEL_ICH2:
case VEN_VIA_596B:
size = 0x080;
break;
@@ -1412,6 +1594,13 @@ acpi_set_nvr(acpi_t *dev, nvr_t *nvr)
}
void
acpi_set_tco(acpi_t *dev, tco_t *tco)
{
dev->tco = tco;
}
void
acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv)
{
@@ -1458,6 +1647,8 @@ acpi_apm_out(uint16_t port, uint8_t val, void *p)
dev->apm->cmd = val;
if (dev->vendor == VEN_INTEL)
dev->regs.glbsts |= 0x20;
else if (dev->vendor == VEN_INTEL_ICH2)
dev->regs.smi_sts |= 0x00000020;
acpi_raise_smi(dev, dev->apm->do_smi);
} else
dev->apm->stat = val;
@@ -1582,7 +1773,7 @@ acpi_init(const device_t *info)
dev->irq_line = 9;
if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) {
if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI) || (dev->vendor == VEN_INTEL_ICH2)) {
if (dev->vendor == VEN_ALI)
dev->irq_mode = 2;
dev->apm = device_add(&apm_pci_acpi_device);
@@ -1624,6 +1815,13 @@ acpi_init(const device_t *info)
dev->suspend_types[3] = SUS_SUSPEND | SUS_RESET_CACHE;
dev->suspend_types[4] = SUS_SUSPEND;
break;
case VEN_INTEL_ICH2:
dev->suspend_types[1] = SUS_SUSPEND | SUS_RESET_CPU;
dev->suspend_types[5] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI;
dev->suspend_types[6] = SUS_POWER_OFF;
dev->suspend_types[7] = SUS_POWER_OFF;
break;
}
timer_add(&dev->timer, acpi_timer_overflow, dev, 0);
@@ -1662,6 +1860,20 @@ const device_t acpi_intel_device = {
.config = NULL
};
const device_t acpi_intel_ich2_device = {
.name = "Intel ICH2 ACPI",
.internal_name = "acpi_intel_ich2",
.flags = DEVICE_PCI,
.local = VEN_INTEL_ICH2,
.init = acpi_init,
.close = acpi_close,
.reset = acpi_reset,
{ .available = NULL },
.speed_changed = acpi_speed_changed,
.force_redraw = NULL,
.config = NULL
};
const device_t acpi_via_device = {
.name = "VIA ACPI",
.internal_name = "acpi_via",

View File

@@ -15,9 +15,9 @@
add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c
ali1621.c ali6117.c headland.c ims8848.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c
intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.c
opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c sis_85c4xx.c
sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c sis_85c310.c
intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c intel_815ep.c intel_ich2.c ../ioapic.c neat.c
opti283.c opti291.c opti391.c opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c
sis_85c4xx.c sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c sis_85c310.c
sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c
via_pipc.c vl82c480.c wd76c10.c)

369
src/chipset/intel_815ep.c Normal file
View File

@@ -0,0 +1,369 @@
/*
* Intel 815EP MCH Bridge
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#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 "x86.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/chipset.h>
#ifdef ENABLE_INTEL_815EP_LOG
int intel_815ep_do_log = ENABLE_INTEL_815EP_LOG;
static void
intel_815ep_log(const char *fmt, ...)
{
va_list ap;
if (intel_815ep_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define intel_815ep_log(fmt, ...)
#endif
typedef struct intel_815ep_t
{
uint8_t pci_conf[256];
smram_t *lsmm_segment, *h_segment, *usmm_segment;
} intel_815ep_t;
static void
intel_usmm_segment_recalc(intel_815ep_t *dev, uint8_t val)
{
intel_815ep_log("Intel 815EP MCH: USMM update to status %d\n", val); /* Check the 815EP datasheet for status */
smram_disable(dev->h_segment);
smram_disable(dev->usmm_segment);
if(val != 0)
smram_enable(dev->h_segment, 0xfeea0000, 0x000a0000, 0x20000, 0, 1);
if(val >= 2) { /* TOM recalc based on intel_4x0.c by OBattler */
uint32_t tom = (mem_size << 10);
mem_set_mem_state_smm(tom, 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
uint32_t size = (val != 3) ? 0x100000 : 0x80000;
smram_enable(dev->usmm_segment, tom + 0x10000000, tom, size, 0, 1);
mem_set_mem_state_smm(tom, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
}
}
static void
intel_lsmm_segment_recalc(intel_815ep_t *dev, uint8_t val)
{
intel_815ep_log("Intel 815EP MCH: LSMM update to status %d\n", val); /* Check the 815EP datasheet for status */
smram_disable(dev->lsmm_segment);
switch(val)
{
case 1:
smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 1, 0);
break;
case 2:
smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 0);
break;
case 3:
smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 1);
break;
}
}
static void
intel_pam_recalc(int addr, uint8_t val)
{
int region = 0xc0000 + ((addr - 0x5a) << 15);
if(addr == 0x59)
mem_set_mem_state_both(0xf0000, 0x10000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY));
else
{
mem_set_mem_state_both(region, 0x4000, ((val & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY));
mem_set_mem_state_both(region + 0x4000, 0x4000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY));
}
}
static void
intel_815ep_write(int func, int addr, uint8_t val, void *priv)
{
intel_815ep_t *dev = (intel_815ep_t *)priv;
intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] = %02x\n", addr, val);
switch(addr)
{
case 0x05:
dev->pci_conf[addr] = val & 3;
break;
case 0x07:
dev->pci_conf[addr] &= val & 0x70;
break;
case 0x2c ... 0x2f:
if(dev->pci_conf[addr] != 0)
dev->pci_conf[addr] = val;
break;
case 0x13:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x50:
dev->pci_conf[addr] = val & 0xdc;
break;
case 0x51:
dev->pci_conf[addr] = val & 2; // Brute force to AGP Mode
break;
case 0x52:
case 0x54:
if (!(dev->pci_conf[0x70] & 2)) {
dev->pci_conf[addr] = val & ((addr & 4) ? 0x0f : 0xff);
spd_write_drbs_intel_815ep(dev->pci_conf);
}
break;
case 0x53:
dev->pci_conf[addr] = val;
break;
case 0x58:
dev->pci_conf[addr] = val & 0x80;
break;
case 0x59 ... 0x5f:
dev->pci_conf[addr] = val;
intel_pam_recalc(addr, val);
break;
case 0x70:
if(!(dev->pci_conf[0x70] & 2)) {
dev->pci_conf[addr] = val & 0xfe;
intel_usmm_segment_recalc(dev, (val >> 4) & 3);
}
else {
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfa) | (val & 4);
}
intel_lsmm_segment_recalc(dev, (val >> 2) & 3);
break;
case 0x72:
dev->pci_conf[addr] = val & 0xfb;
break;
case 0x73:
dev->pci_conf[addr] = val & 0xa8;
break;
case 0x92 ... 0x93:
dev->pci_conf[addr] = val;
break;
case 0x94:
dev->pci_conf[addr] = val & 0x3f;
break;
case 0x98:
dev->pci_conf[addr] = val & 0x77;
break;
case 0x99:
dev->pci_conf[addr] = val & 0x80;
break;
case 0x9a:
dev->pci_conf[addr] = val & 0xef;
break;
case 0x9b:
case 0x9d:
dev->pci_conf[addr] = val & 0x80;
break;
case 0xa4:
dev->pci_conf[addr] = val & 7;
break;
case 0xa8:
dev->pci_conf[addr] = val & 0x37;
break;
case 0xa9:
dev->pci_conf[addr] = (val & 2) | 1;
break;
case 0xb0:
dev->pci_conf[addr] = val & 0x81;
break;
case 0xb4:
dev->pci_conf[addr] = val & 8;
break;
case 0xb9:
dev->pci_conf[addr] = val & 0xf0;
break;
case 0xba:
dev->pci_conf[addr] = val;
break;
case 0xbb:
dev->pci_conf[addr] = val & 0x1f;
break;
case 0xbc ... 0xbd:
dev->pci_conf[addr] = val & 0xf8;
break;
case 0xbe:
dev->pci_conf[addr] = val & 0x28;
break;
case 0xcb:
dev->pci_conf[addr] = val & 0x3f;
break;
}
}
static uint8_t
intel_815ep_read(int func, int addr, void *priv)
{
intel_815ep_t *dev = (intel_815ep_t *)priv;
intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[addr]);
if(addr == 0x51) // Bit 2 is Write Only. It cannot be read.
return dev->pci_conf[addr] & 3;
else
return dev->pci_conf[addr];
}
static void
intel_815ep_reset(void *priv)
{
intel_815ep_t *dev = (intel_815ep_t *)priv;
memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); /* Wash out the registers */
dev->pci_conf[0x00] = 0x86; /* Intel */
dev->pci_conf[0x01] = 0x80;
dev->pci_conf[0x02] = 0x30; /* 815EP */
dev->pci_conf[0x03] = 0x11;
dev->pci_conf[0x04] = 0x06;
dev->pci_conf[0x06] = 0x90;
dev->pci_conf[0x08] = 0x02;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x10] = 0x03;
dev->pci_conf[0x34] = 0xa0;
dev->pci_conf[0x50] = 0x40;
dev->pci_conf[0x88] = 0x09;
dev->pci_conf[0x89] = 0xa0;
dev->pci_conf[0x8a] = 0x04;
dev->pci_conf[0x8b] = 0xf1;
dev->pci_conf[0x92] = 0xff;
dev->pci_conf[0x93] = 0xff;
dev->pci_conf[0x94] = 0xff;
dev->pci_conf[0x95] = 0xff;
dev->pci_conf[0xa0] = 0x02;
dev->pci_conf[0xa2] = 0x20;
dev->pci_conf[0xa4] = 0x07;
dev->pci_conf[0xa5] = 0x02;
dev->pci_conf[0xa7] = 0x1f;
dev->pci_conf[0xa9] = 0x01; /* Hack: Brute Force AGP Enabled */
for(int i = 0x58; i <= 0x5f; i++) /* Reset PAM to defaults */
intel_pam_recalc(i, 0);
intel_lsmm_segment_recalc(dev, 0); /* Reset LSMM SMRAM to defaults */
intel_usmm_segment_recalc(dev, 0); /* Reset USMM SMRAM to defaults */
}
static void
intel_815ep_close(void *priv)
{
intel_815ep_t *dev = (intel_815ep_t *)priv;
smram_del(dev->lsmm_segment);
smram_del(dev->h_segment);
smram_del(dev->usmm_segment);
free(dev);
}
static void *
intel_815ep_init(const device_t *info)
{
intel_815ep_t *dev = (intel_815ep_t *)malloc(sizeof(intel_815ep_t));
memset(dev, 0, sizeof(intel_815ep_t));
/* Device */
pci_add_card(PCI_ADD_NORTHBRIDGE, intel_815ep_read, intel_815ep_write, dev); /* Device 0: Intel 815EP MCH */
/* AGP Bridge */
device_add(&intel_815ep_agp_device);
/* L1 & L2 Cache */
cpu_cache_int_enabled = 1;
cpu_cache_ext_enabled = 1;
cpu_update_waitstates();
/* SMRAM Segments */
dev->lsmm_segment = smram_add();
dev->h_segment = smram_add();
dev->usmm_segment = smram_add();
intel_815ep_reset(dev);
return dev;
}
const device_t intel_815ep_device = {
.name = "Intel 815EP MCH Bridge",
.internal_name = "intel_815ep",
.flags = DEVICE_PCI,
.local = 0,
.init = intel_815ep_init,
.close = intel_815ep_close,
.reset = intel_815ep_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

903
src/chipset/intel_ich2.c Normal file
View File

@@ -0,0 +1,903 @@
/*
* Intel ICH2
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#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 "x86.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/apm.h>
#include <86box/nvr.h>
#include <86box/acpi.h>
#include <86box/dma.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/intel_ich2_gpio.h>
#include <86box/intel_ich2_trap.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/port_92.h>
#include <86box/smbus.h>
#include <86box/tco.h>
#include <86box/usb.h>
#include <86box/chipset.h>
#ifdef ENABLE_INTEL_ICH2_LOG
int intel_ich2_do_log = ENABLE_INTEL_ICH2_LOG;
static void
intel_ich2_log(const char *fmt, ...)
{
va_list ap;
if (intel_ich2_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define intel_ich2_log(fmt, ...)
#endif
typedef struct intel_ich2_t
{
uint8_t pci_conf[5][256];
acpi_t *acpi;
intel_ich2_gpio_t *gpio;
intel_ich2_trap_t *trap_device[10];
nvr_t *nvr;
sff8038i_t *ide_drive[2];
smbus_piix4_t *smbus;
tco_t *tco;
usb_t *usb_hub[2];
} intel_ich2_t;
/* LPC Bridge functions */
static void
intel_ich2_acpi_setup(intel_ich2_t *dev)
{
uint32_t base = (dev->pci_conf[0][0x41] << 8) | (dev->pci_conf[0][0x40] & 0x80);
int acpi_irq = ((dev->pci_conf[0][0x44] & 7) < 3) ? (9 + (dev->pci_conf[0][0x44] & 7)) : 9; /* Under APIC you can set this even higher but */
int enable = !!(dev->pci_conf[0][0x44] & 0x10); /* as we lack it we are restricted with low. */
acpi_update_io_mapping(dev->acpi, base, enable);
acpi_set_irq_line(dev->acpi, acpi_irq);
}
static void
intel_ich2_trap_update(void *priv)
{
intel_ich2_t *dev = (intel_ich2_t *) priv;
uint16_t temp_addr = 0;
/* Hard Drives */
intel_ich2_device_trap_setup(1, 0x48, 0x01, 0x1f0, 8, 1, dev->trap_device[0]); // HDD's don't have a decode bit
intel_ich2_device_trap_setup(1, 0x48, 0x01, 0x3f6, 1, 1, dev->trap_device[0]);
intel_ich2_device_trap_setup(1, 0x48, 0x02, 0x170, 8, 1, dev->trap_device[1]);
intel_ich2_device_trap_setup(1, 0x48, 0x02, 0x376, 1, 1, dev->trap_device[1]);
/* COM A */
switch(dev->pci_conf[0][0xe0] & 7)
{
case 0:
temp_addr = 0x3f8;
break;
case 1:
temp_addr = 0x2f8;
break;
case 2:
temp_addr = 0x220;
break;
case 3:
temp_addr = 0x228;
break;
case 4:
temp_addr = 0x238;
break;
case 5:
temp_addr = 0x2e8;
break;
case 6:
temp_addr = 0x338;
break;
case 7:
temp_addr = 0x3e8;
break;
}
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 1), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[2]);
/* COM B */
switch((dev->pci_conf[0][0xe0] >> 4) & 7)
{
case 0:
temp_addr = 0x3f8;
break;
case 1:
temp_addr = 0x2f8;
break;
case 2:
temp_addr = 0x220;
break;
case 3:
temp_addr = 0x228;
break;
case 4:
temp_addr = 0x238;
break;
case 5:
temp_addr = 0x2e8;
break;
case 6:
temp_addr = 0x338;
break;
case 7:
temp_addr = 0x3e8;
break;
}
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 2), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[3]);
/* LPT */
switch(dev->pci_conf[0][0xe1] & 3)
{
case 0:
temp_addr = 0x378;
break;
case 1:
temp_addr = 0x278;
break;
case 2:
temp_addr = 0x3bc;
break;
}
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 4), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[4]);
/* FDC */
temp_addr = (dev->pci_conf[0][0xe1] & 0x10) ? 0x3f0 : 0x370;
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 8), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[5]);
/* MSS */
switch((dev->pci_conf[0][0xe2] >> 4) & 3)
{
case 0:
temp_addr = 0x530;
break;
case 1:
temp_addr = 0x604;
break;
case 2:
temp_addr = 0xe80;
break;
case 3:
temp_addr = 0xf40;
break;
}
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x40), 0x49, 0x04, 0x170, 8, 0, dev->trap_device[6]);
/* MIDI */
temp_addr = (dev->pci_conf[0][0xe2] & 8) ? 0x300 : 0x330;
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x20), 0x49, 0x08, temp_addr, 2, 0, dev->trap_device[7]);
/* KBC */
intel_ich2_device_trap_setup(1, 0x49, 0x10, 0x60, 4, 0, dev->trap_device[8]); // KBC doesn't have a decode bit
/* Adlib */
intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x80), 0x49, 0x20, 0x388, 4, 0, dev->trap_device[9]);
}
static void
intel_ich2_tco_interrupt(intel_ich2_t *dev)
{
uint16_t tco_irq = ((dev->pci_conf[0][0x54] & 7) < 3) ? (9 + (dev->pci_conf[0][0x45] & 7)) : 9; /* Under APIC you can set this even higher but */
/* as we lack it we are restricted with low. */
tco_irq_update(dev->tco, tco_irq);
}
static void
intel_ich2_gpio_setup(intel_ich2_t *dev)
{
uint16_t base = (dev->pci_conf[0][0x59] << 8) | (dev->pci_conf[0][0x58] & 0xc0);
int enable = !!(dev->pci_conf[0][0x5c] & 0x10);
intel_ich2_gpio_base(enable, base, dev->gpio);
}
static int
intel_ich2_pirq_table(uint8_t val)
{
switch(val)
{
case 0 ... 2:
case 8:
case 13:
return PCI_IRQ_DISABLED;
default:
return val;
}
}
static void
intel_ich2_pirq_update(int reset, int addr, uint8_t val)
{
int pirq = (addr >= 0x68) ? (addr - 0x63) : (addr - 0x5f);
if(((val & 0x80) != 0x80) && !reset) { /* 86Box doesn't have an APIC yet. */
intel_ich2_log("Intel ICH2 LPC: Update PIRQ %c to IRQ %d\n", '@' + pirq, val); /* Under normal circumstances on an APIC enabled motherboard*/
pci_set_irq_routing(pirq, intel_ich2_pirq_table(val)); /* this remains disabled and the IRQ are handed by the APIC */
} /* itself. */
else if(reset)
for(int i = 1; i <= 8; i++)
pci_set_irq_routing(i, PCI_IRQ_DISABLED);
}
static void
intel_ich2_nvr_handler(intel_ich2_t *dev)
{
intel_ich2_log("Intel ICH2 LPC: Extended NVR Aliases %s\n", (dev->pci_conf[0][0xd8] & 4) ? "Enabled" : "Disabled");
nvr_at_handler(!!(dev->pci_conf[0][0xd8] & 4), 0x74, dev->nvr);
nvr_at_handler(!!(dev->pci_conf[0][0xd8] & 4), 0x76, dev->nvr);
}
static void
intel_ich2_function_disable(intel_ich2_t *dev)
{
uint16_t smbus_addr = (dev->pci_conf[3][0x21] << 8) | (dev->pci_conf[3][0x20] & 0xf0); // Hold the SMBus Base Address value
/* Disable IDE */
if(dev->pci_conf[0][0xf2] & 2) {
ide_pri_disable();
ide_sec_disable();
}
/* Disable USB Hub 1 */
if(dev->pci_conf[0][0xf2] & 4) {
uhci_update_io_mapping(dev->usb_hub[0], dev->pci_conf[2][0x20] & 0xe0, dev->pci_conf[0][0x21], 0);
}
/* Disable SMBus */
if(dev->pci_conf[0][0xf2] & 8) { //ICH2 Supports the ability of the SMBus Controller to be active even if it's PCI device is disabled
smbus_piix4_remap(dev->smbus, smbus_addr, dev->pci_conf[0][0xf3] & 1);
}
/* Disable USB Hub 2 */
if(dev->pci_conf[0][0xf2] & 0x10) {
uhci_update_io_mapping(dev->usb_hub[1], 0, 0, 0);
}
}
/* IDE Controller functions */
static void
intel_ich2_ide_setup(intel_ich2_t *dev)
{
ide_pri_disable();
ide_sec_disable();
intel_ich2_log("Intel ICH2 IDE: Primary Channel is %s.\n", !!(dev->pci_conf[1][0x41] & 0x80) ? "Enabled" : "Disabled");
if(dev->pci_conf[1][0x41] & 0x80) {
ide_pri_enable();
}
intel_ich2_log("Intel ICH2 IDE: Secondary Channel is %s.\n", !!(dev->pci_conf[1][0x43] & 0x80) ? "Enabled" : "Disabled");
if(dev->pci_conf[1][0x43] & 0x80) {
ide_sec_enable();
}
}
static void
intel_ich2_bus_master_setup(intel_ich2_t *dev)
{
uint16_t bm_base = ((dev->pci_conf[1][0x21] & 0xf0) << 8) | (dev->pci_conf[1][0x20] & 0xf0);
intel_ich2_log("Intel ICH2 IDE: IDE Bus Master address is 0x%04x.\n", bm_base);
sff_bus_master_handler(dev->ide_drive[0], dev->pci_conf[1][0x04] & 1, bm_base);
sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf[1][0x04] & 1, bm_base + 8);
}
/* USB Controller functions */
static void
intel_ich2_usb_setup(int func, intel_ich2_t* dev)
{
int current_hub = (func == 4) ? 4 : 2;
int hub_num = (func == 4);
uhci_update_io_mapping(dev->usb_hub[hub_num], dev->pci_conf[current_hub][0x20] & 0xe0, dev->pci_conf[current_hub][0x21], !!(dev->pci_conf[current_hub][0x04] & 1));
}
/* SMBus Controller functions */
static void
intel_ich2_smbus_setup(intel_ich2_t *dev)
{
uint16_t base = (dev->pci_conf[3][0x21] << 8) | (dev->pci_conf[3][0x20] & 0xf0);
if((dev->pci_conf[3][0x40] & 1) && (dev->pci_conf[3][0x04] & 1))
intel_ich2_log("Intel ICH2 SMBus: SMBus is enabled.\n");
smbus_piix4_remap(dev->smbus, base, (dev->pci_conf[3][0x40] & 1) && (dev->pci_conf[3][0x04] & 1));
}
/* ICH2 Registers */
static void
intel_ich2_write(int func, int addr, uint8_t val, void *priv)
{
intel_ich2_t *dev = (intel_ich2_t *)priv;
if(func == 0) {
intel_ich2_log("Intel ICH2 LPC: dev->regs[%02x] = %02x\n", addr, val);
switch(addr)
{
case 0x04:
dev->pci_conf[func][addr] = (val & 0x40) | 0x0f;
break;
case 0x05:
dev->pci_conf[func][addr] = val & 0x01;
break;
case 0x07:
dev->pci_conf[func][addr] &= val & 0xf9;
break;
case 0x40 ... 0x41:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0x80 | 1));
intel_ich2_acpi_setup(dev);
break;
case 0x44:
dev->pci_conf[func][addr] = val & 0x17;
intel_ich2_acpi_setup(dev);
break;
case 0x4e:
dev->pci_conf[func][addr] = val & 0x03;
if((val & 0x01) && ((val & 0x02) == 0x02))
smi_line = 1;
break;
case 0x54:
dev->pci_conf[func][addr] = val & 0x0f;
intel_ich2_tco_interrupt(dev);
break;
case 0x58 ... 0x59:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xc0 | 1));
intel_ich2_gpio_setup(dev);
break;
case 0x5c:
dev->pci_conf[func][addr] = val & 0x10;
intel_ich2_gpio_setup(dev);
break;
case 0x60 ... 0x63:
case 0x68 ... 0x6b:
dev->pci_conf[func][addr] = val & 0x8f;
intel_ich2_pirq_update(0, addr, val);
break;
case 0x64:
dev->pci_conf[func][addr] = val;
break;
case 0x88:
dev->pci_conf[func][addr] = val & 6;
break;
case 0x8a:
dev->pci_conf[func][addr] &= val & 6;
break;
case 0x90:
dev->pci_conf[func][addr] = val;
break;
case 0x91:
dev->pci_conf[func][addr] = val & 0xfc;
break;
case 0xd0:
dev->pci_conf[func][addr] = val & 0x4f; /* Brute force APIC support as disabled */
break;
case 0xd1:
dev->pci_conf[func][addr] = val & 0x38; /* Brute force APIC support as disabled */
break;
case 0xd3:
dev->pci_conf[func][addr] = val & 0x03;
break;
case 0xd4:
dev->pci_conf[func][addr] = val & 0x02;
break;
case 0xd5:
dev->pci_conf[func][addr] = val & 0x3f;
break;
case 0xd8:
dev->pci_conf[func][addr] = val & 0x1c;
intel_ich2_nvr_handler(dev);
break;
case 0xe0:
dev->pci_conf[func][addr] = val & 0x77;
break;
case 0xe1:
dev->pci_conf[func][addr] = val & 0x13;
intel_ich2_trap_update(dev);
break;
case 0xe2:
dev->pci_conf[func][addr] = val & 0x3b;
intel_ich2_trap_update(dev);
break;
case 0xe3:
dev->pci_conf[func][addr] = val;
break;
case 0xe4:
dev->pci_conf[func][addr] = val & 0x81;
break;
case 0xe5 ... 0xe6:
dev->pci_conf[func][addr] = val;
if(addr == 0xe6)
intel_ich2_trap_update(dev);
break;
case 0xe7:
dev->pci_conf[func][addr] = val & 0x3f;
break;
case 0xe8 ... 0xeb:
dev->pci_conf[func][addr] = val;
break;
case 0xec:
dev->pci_conf[func][addr] = val & 0xf1;
break;
case 0xed:
dev->pci_conf[func][addr] = val;
break;
case 0xee ... 0xef:
dev->pci_conf[func][addr] = val;
break;
case 0xf0:
dev->pci_conf[func][addr] = val & 0x0f;
break;
case 0xf2 ... 0xf3:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0x01 : 0xfe);
intel_ich2_function_disable(dev);
break;
}
}
else if((func == 1) && !(dev->pci_conf[0][0xf2] & 2)) {
intel_ich2_log("Intel ICH2 IDE: dev->regs[%02x] = %02x\n", addr, val);
switch(addr)
{
case 0x04:
dev->pci_conf[func][addr] = val & 5;
intel_ich2_ide_setup(dev);
intel_ich2_bus_master_setup(dev);
break;
case 0x07:
dev->pci_conf[func][addr] &= val & 0x2e;
break;
case 0x20 ... 0x21:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1));
intel_ich2_bus_master_setup(dev);
break;
case 0x2c ... 0x2f:
if(dev->pci_conf[func][addr] != 0)
dev->pci_conf[func][addr] = val;
break;
case 0x40 ... 0x43:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xf3 : 0xff);
intel_ich2_ide_setup(dev);
break;
case 0x44:
dev->pci_conf[func][addr] = val;
break;
case 0x48:
dev->pci_conf[func][addr] = val & 0x0f;
break;
case 0x4a ... 0x4b:
dev->pci_conf[func][addr] = val & 0x33;
break;
}
}
else if(((func == 2) && !(dev->pci_conf[0][0xf2] & 4)) || ((func == 4) && !(dev->pci_conf[0][0xf2] & 0x10))) {
intel_ich2_log("Intel ICH2 USB Hub %d: dev->regs[%02x] = %02x\n", (func == 4), addr, val);
switch(addr)
{
case 0x04:
dev->pci_conf[func][addr] = val & 5;
intel_ich2_usb_setup(func, dev);
break;
case 0x07:
dev->pci_conf[func][addr] &= val & 0x2e;
break;
case 0x20 ... 0x21:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1));
intel_ich2_usb_setup(func, dev);
break;
case 0xc0:
dev->pci_conf[func][addr] = val & 0xbf;
break;
case 0xc1:
dev->pci_conf[func][addr] &= val & 0xaf;
break;
case 0xc4:
dev->pci_conf[func][addr] = val & 3;
break;
}
}
else if((func == 3) && !(dev->pci_conf[0][0xf2] & 8)) {
intel_ich2_log("Intel ICH2 SMBus: dev->regs[%02x] = %02x\n", addr, val);
switch(addr)
{
case 0x04:
dev->pci_conf[func][addr] = val & 1;
intel_ich2_smbus_setup(dev);
break;
case 0x07:
dev->pci_conf[func][addr] &= val & 0x0e;
break;
case 0x20 ... 0x21:
dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1));
intel_ich2_smbus_setup(dev);
break;
case 0x3c:
dev->pci_conf[func][addr] = val;
smbus_piix4_get_irq(val, dev->smbus);
break;
case 0x40:
dev->pci_conf[func][addr] = val & 7;
intel_ich2_smbus_setup(dev);
smbus_piix4_smi_en(!!(val & 2), dev->smbus);
break;
}
}
}
static uint8_t
intel_ich2_read(int func, int addr, void *priv)
{
intel_ich2_t *dev = (intel_ich2_t *)priv;
if(func == 0) {
intel_ich2_log("Intel ICH2 LPC: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]);
return dev->pci_conf[func][addr];
}
else if((func == 1) && !(dev->pci_conf[0][0xf2] & 2)) {
intel_ich2_log("Intel ICH2 IDE: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]);
return dev->pci_conf[func][addr];
}
else if(((func == 2) && !(dev->pci_conf[0][0xf2] & 4)) || ((func == 4) && !(dev->pci_conf[0][0xf2] & 0x10))) {
intel_ich2_log("Intel ICH2 USB Hub %d: dev->regs[%02x] (%02x)\n", (func == 4), addr, dev->pci_conf[func][addr]);
if((addr >= 0x2c) && (addr <= 0x2f)) /* USB shares the same subsystem vendor info as the IDE */
return dev->pci_conf[1][addr];
return dev->pci_conf[func][addr];
}
else if((func == 3) && !(dev->pci_conf[0][0xf2] & 8)) {
intel_ich2_log("Intel ICH2 SMBus: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]);
if((addr >= 0x2c) && (addr <= 0x2f)) /* SMBus shares the same subsystem vendor info as the IDE */
return dev->pci_conf[1][addr];
return dev->pci_conf[func][addr];
}
else return 0xff;
}
static void
intel_ich2_reset(void *priv)
{
intel_ich2_t *dev = (intel_ich2_t *)priv;
memset(dev->pci_conf, 0, sizeof(dev->pci_conf)); /* Wash out the Registers */
/* Function 0: LPC Bridge */
dev->pci_conf[0][0x00] = 0x86;
dev->pci_conf[0][0x01] = 0x80;
dev->pci_conf[0][0x02] = 0x40;
dev->pci_conf[0][0x03] = 0x24;
dev->pci_conf[0][0x04] = 0x0f;
dev->pci_conf[0][0x06] = 0x80;
dev->pci_conf[0][0x07] = 0x02;
dev->pci_conf[0][0x08] = 0x02;
dev->pci_conf[0][0x0a] = 0x01;
dev->pci_conf[0][0x0b] = 0x06;
dev->pci_conf[0][0x0e] = 0x80;
dev->pci_conf[0][0x40] = 0x01;
dev->pci_conf[0][0x58] = 0x01;
dev->pci_conf[0][0x60] = 0x80;
dev->pci_conf[0][0x61] = 0x80;
dev->pci_conf[0][0x62] = 0x80;
dev->pci_conf[0][0x63] = 0x80;
dev->pci_conf[0][0x64] = 0x10;
dev->pci_conf[0][0x68] = 0x80;
dev->pci_conf[0][0x69] = 0x80;
dev->pci_conf[0][0x6a] = 0x80;
dev->pci_conf[0][0x6b] = 0x80;
dev->pci_conf[0][0xd5] = 0x0f;
dev->pci_conf[0][0xe3] = 0xff;
dev->pci_conf[0][0xe8] = 0x33;
dev->pci_conf[0][0xe9] = 0x22;
dev->pci_conf[0][0xea] = 0x11;
dev->pci_conf[0][0xeb] = 0x00;
dev->pci_conf[0][0xee] = 0x78;
dev->pci_conf[0][0xef] = 0x56;
dev->pci_conf[0][0xf0] = 0x0f;
intel_ich2_acpi_setup(dev); /* Setup the ACPI Interface */
intel_ich2_tco_interrupt(dev); /* Configure the TCO Interrupt */
intel_ich2_gpio_setup(dev); /* Setup the GPIO */
intel_ich2_pirq_update(1, 0, 0); /* Reset the PIRQ interrupts */
intel_ich2_nvr_handler(dev); /* Set the NVR aliases */
/* Function 1: IDE Controller */
dev->pci_conf[1][0x00] = 0x86;
dev->pci_conf[1][0x01] = 0x80;
dev->pci_conf[1][0x02] = 0x4b;
dev->pci_conf[1][0x03] = 0x24;
dev->pci_conf[1][0x06] = 0x80;
dev->pci_conf[1][0x07] = 0x02;
dev->pci_conf[1][0x08] = 0x02;
dev->pci_conf[1][0x09] = 0x80;
dev->pci_conf[1][0x0a] = 0x01;
dev->pci_conf[1][0x0b] = 0x01;
dev->pci_conf[1][0x20] = 0x01;
dev->pci_conf[1][0x54] = 0xff; /* Hack: Fake Cable Conductor & UltraDMA details */
if(cpu_busspeed >= 100000000) /* Go UltraDMA 100 if CPU is up for it. Not that it actually matters */
dev->pci_conf[1][0x55] = 0xf0;
sff_bus_master_reset(dev->ide_drive[0], 0); /* Setup the IDE */
sff_bus_master_reset(dev->ide_drive[1], 8);
intel_ich2_ide_setup(dev);
/* Function 2: USB Hub 0 */
dev->pci_conf[2][0x00] = 0x86;
dev->pci_conf[2][0x01] = 0x80;
dev->pci_conf[2][0x02] = 0x42;
dev->pci_conf[2][0x03] = 0x24;
dev->pci_conf[2][0x06] = 0x80;
dev->pci_conf[2][0x07] = 0x02;
dev->pci_conf[2][0x08] = 0x02;
dev->pci_conf[2][0x0a] = 0x03;
dev->pci_conf[2][0x0b] = 0x0c;
dev->pci_conf[2][0x20] = 0x01;
dev->pci_conf[2][0x3d] = 0x03;
dev->pci_conf[2][0x60] = 0x10;
dev->pci_conf[2][0xc1] = 0x20;
intel_ich2_usb_setup(2, dev);
/* Function 3: SMBus Controller */
dev->pci_conf[3][0x00] = 0x86;
dev->pci_conf[3][0x01] = 0x80;
dev->pci_conf[3][0x02] = 0x43;
dev->pci_conf[3][0x03] = 0x24;
dev->pci_conf[3][0x06] = 0x80;
dev->pci_conf[3][0x07] = 0x02;
dev->pci_conf[3][0x08] = 0x02;
dev->pci_conf[3][0x09] = 0x80;
dev->pci_conf[3][0x0a] = 0x05;
dev->pci_conf[3][0x0b] = 0x0c;
dev->pci_conf[3][0x20] = 0x01;
dev->pci_conf[3][0x3d] = 0x02;
intel_ich2_smbus_setup(dev); /* Setup the SMBus */
/* Function 4: USB Hub 1*/
dev->pci_conf[4][0x00] = 0x86;
dev->pci_conf[4][0x01] = 0x80;
dev->pci_conf[4][0x02] = 0x44;
dev->pci_conf[4][0x03] = 0x24;
dev->pci_conf[4][0x06] = 0x80;
dev->pci_conf[4][0x07] = 0x02;
dev->pci_conf[4][0x08] = 0x02;
dev->pci_conf[4][0x0a] = 0x03;
dev->pci_conf[4][0x0b] = 0x0c;
dev->pci_conf[4][0x20] = 0x01;
dev->pci_conf[4][0x3d] = 0x03;
dev->pci_conf[4][0x60] = 0x10;
dev->pci_conf[4][0xc1] = 0x20;
intel_ich2_usb_setup(4, dev);
}
static void
intel_ich2_close(void *priv)
{
intel_ich2_t *dev = (intel_ich2_t *)priv;
free(dev);
}
static void *
intel_ich2_init(const device_t *info)
{
intel_ich2_t *dev = (intel_ich2_t *)malloc(sizeof(intel_ich2_t));
memset(dev, 0, sizeof(intel_ich2_t));
int slot;
/* Device */
slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, intel_ich2_read, intel_ich2_write, dev); /* Device 31: Intel ICH2 */
/* ACPI Interface */
dev->acpi = device_add(&acpi_intel_ich2_device);
acpi_set_slot(dev->acpi, slot);
/* DMA */
dma_alias_set_piix();
dma_lpc_init();
/* GPIO */
dev->gpio = device_add(&intel_ich2_gpio_device);
/* NVR Handler */
dev->nvr = device_add(&piix4_nvr_device);
acpi_set_nvr(dev->acpi, dev->nvr);
/* Intel ICH2 Hub */
device_add(&intel_ich2_hub_device);
/* PIC */
pic_set_pci();
/* SMBus */
dev->smbus = device_add(&intel_ich2_smbus_device);
smbus_piix4_get_acpi(dev->smbus, dev->acpi);
/* SFF Compatible IDE Drives */
dev->ide_drive[0] = device_add_inst(&sff8038i_device, 1);
dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2);
sff_set_slot(dev->ide_drive[0], slot);
sff_set_slot(dev->ide_drive[1], slot);
/* TCO */
dev->tco = device_add(&tco_device);
acpi_set_tco(dev->acpi, dev->tco);
/* I/O Traps */
acpi_set_trap_update(dev->acpi, intel_ich2_trap_update, dev);
for (int i = 0; i < 10; i++) {
dev->trap_device[i] = device_add_inst(&intel_ich2_trap_device, i + 1);
intel_ich2_trap_set_acpi(dev->trap_device[i], dev->acpi);
}
/* USB */
dev->usb_hub[0] = device_add_inst(&usb_device, 1);
dev->usb_hub[1] = device_add_inst(&usb_device, 2);
intel_ich2_reset(dev);
return dev;
}
const device_t intel_ich2_device = {
.name = "Intel ICH2",
.internal_name = "intel_ich2",
.flags = DEVICE_PCI,
.local = 0,
.init = intel_ich2_init,
.close = intel_ich2_close,
.reset = intel_ich2_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -2439,6 +2439,22 @@ amd_k_invalid_rdmsr:
EAX = msr.ecx187 & 0xffffffff;
EDX = msr.ecx187 >> 32;
break;
case 0x198:
EAX = msr.ecx198 & 0xffffffff;
EDX = msr.ecx198 >> 32;
break;
case 0x19a:
EAX = msr.ecx19a & 0xffffffff;
EDX = msr.ecx19a >> 32;
break;
case 0x19d:
EAX = msr.ecx19d & 0xffffffff;
EDX = msr.ecx19d >> 32;
break;
case 0x1a0:
EAX = msr.ecx1a0 & 0xffffffff;
EDX = msr.ecx1a0 >> 32;
break;
case 0x1e0:
EAX = msr.ecx1e0 & 0xffffffff;
EDX = msr.ecx1e0 >> 32;
@@ -2814,6 +2830,18 @@ amd_k_invalid_wrmsr:
case 0x187:
msr.ecx187 = EAX | ((uint64_t)EDX << 32);
break;
case 0x198:
msr.ecx198 = EAX | ((uint64_t)EDX << 32);
break;
case 0x19a:
msr.ecx19a = EAX | ((uint64_t)EDX << 32);
break;
case 0x19d:
msr.ecx19d = EAX | ((uint64_t)EDX << 32);
break;
case 0x1a0:
msr.ecx1a0 = EAX | ((uint64_t)EDX << 32);
break;
case 0x1e0:
msr.ecx1e0 = EAX | ((uint64_t)EDX << 32);
break;

View File

@@ -284,6 +284,12 @@ typedef struct {
on the VIA Cyrix III */
uint64_t mtrr_deftype; /* 0x000002ff */
/* Pentium II/III/IV MSR's needed for late BIOS */
uint64_t ecx1a0; /* 0x000001a0 */
uint64_t ecx198; /* 0x00000198 */
uint64_t ecx19a; /* 0x0000019a */
uint64_t ecx19d; /* 0x0000019d */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t mca_ctl[5]; /* 0x00000400, 0x00000404, 0x00000408, 0x0000040c, 0x00000410 - Machine Check Architecture */
uint64_t ecx570; /* 0x00000570 */

View File

@@ -13,11 +13,12 @@
# Copyright 2020,2021 David Hrdlička.
#
add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c
hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c
add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_nsc366.c
hwm_vt82c686.c ibm_5161.c intel_ich2_gpio.c intel_ich2_trap.c isamem.c isartc.c ../lpt.c pci_bridge.c
postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c
smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c
mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c)
mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c
tco.c)
if(ISAMEM_RAMPAGE)
target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE)

399
src/device/hwm_nsc366.c Normal file
View File

@@ -0,0 +1,399 @@
/*
* National Semiconductor PC87366(NSC366) Hardware Monitor
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
/* The conversion algorithms were taken by the pc87360.c driver of the Linux kernel.
Respective credits goes to the authors. */
#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/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/hwm.h>
#include <86box/nsc366.h>
#define FAN_TO_REG(val, div) ((val) <= 100 ? 0 : 480000 / ((val) * (div)))
#define FAN_DIV_FROM_REG(val) (1 << (((val) >> 5) & 0x03))
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 480000 / ((val) * (div)))
#define IN_TO_REG(val, ref) ((val) < 0 ? 0 : (val) * 256 >= (ref) * 255 ? 255 : ((val) * 256 + (ref) / 2) / (ref))
#define IN_FROM_REG(val, ref) (((val) * (ref) + 128) / 256)
#define VREF (dev->vlm_config_global[0x08] & 2) ? 3025 : 2966 //VREF taken from pc87360.c
#define VLM_BANK dev->vlm_config_global[0x09]
#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : (val) > 127000 ? 127 : (val) < 0 ? ((val) - 500) / 1000 : ((val) + 500) / 1000)
#define TEMP_FROM_REG(val) ((val) * 1000)
#define TMS_BANK dev->tms_config_global[0x09]
#ifdef ENABLE_NSC366_HWM_LOG
int nsc366_hwm_do_log = ENABLE_NSC366_HWM_LOG;
void
nsc366_hwm_log(const char *fmt, ...)
{
va_list ap;
if (nsc366_hwm_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define nsc366_hwm_log(fmt, ...)
#endif
/* Fans */
static void
nsc366_fscm_write(uint16_t addr, uint8_t val, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
nsc366_hwm_log("NSC366 Fan Control: Write 0x%02x to register 0x%02x\n", val, addr);
switch(addr)
{
case 0x00:
case 0x02:
case 0x04:
dev->fscm_config[addr] = val;
break;
case 0x01:
case 0x03:
case 0x05:
dev->fscm_config[addr] = val;
break;
case 0x06:
case 0x09:
case 0x0c:
dev->fscm_config[addr] = val;
break;
case 0x08:
case 0x0b:
case 0x0d:
dev->fscm_config[addr] = (val & 0x78) | 1;
break;
}
}
static uint8_t
nsc366_fscm_read(uint16_t addr, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
switch(addr)
{
case 0x00 ... 0x06:
case 0x08 ... 0x09:
case 0x0b ... 0x0c:
return dev->fscm_config[addr];
case 0x07:
case 0x0a:
case 0x0d:
nsc366_hwm_log("NSC366 Fan Control: Reading %d RPM's from Bank %d\n", FAN_FROM_REG(dev->fscm_config[addr], FAN_DIV_FROM_REG(dev->fscm_config[0x06])), (addr - 7) / 3);
return dev->fscm_config[addr];
default:
return 0;
}
}
void
nsc366_update_fscm_io(int enable, uint16_t addr, nsc366_hwm_t *dev)
{
if(dev->fscm_addr != 0)
io_removehandler(dev->fscm_addr, 15, nsc366_fscm_read, NULL, NULL, nsc366_fscm_write, NULL, NULL, dev);
dev->fscm_addr = addr;
if((addr != 0) && enable)
io_sethandler(addr, 15, nsc366_fscm_read, NULL, NULL, nsc366_fscm_write, NULL, NULL, dev);
}
/* Voltage */
static void
nsc366_vlm_write(uint16_t addr, uint8_t val, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
if(addr <= 9)
nsc366_hwm_log("NSC366 Voltage Monitor: Write 0x%02x to register 0x%02x\n", val, addr);
else
nsc366_hwm_log("NSC366 Voltage Monitor: Write 0x%02x to register 0x%02x of bank %d\n", val, addr, VLM_BANK);
switch(addr)
{
case 0x02 ... 0x04:
dev->vlm_config_global[addr] = val;
break;
case 0x05:
dev->vlm_config_global[addr] = val & 0x3f;
break;
case 0x06:
dev->vlm_config_global[addr] = val & 0xc0;
break;
case 0x07:
dev->vlm_config_global[addr] = val & 0x3f;
break;
case 0x08:
dev->vlm_config_global[addr] = val & 3;
break;
case 0x09:
dev->vlm_config_global[addr] = val & 0x1f;
break;
case 0x0a:
if(VLM_BANK < 13)
dev->vlm_config_bank[VLM_BANK][addr - 0x0a] = val & 1;
break;
case 0x0c ... 0x0e:
if(VLM_BANK < 13)
dev->vlm_config_bank[VLM_BANK][addr - 0x0a] = val;
break;
}
}
static uint8_t
nsc366_vlm_read(uint16_t addr, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
switch(addr)
{
case 0x00 ... 0x09:
return dev->vlm_config_global[addr];
case 0x0a:
case 0x0c ... 0x0e:
if(VLM_BANK < 13)
return dev->vlm_config_bank[VLM_BANK][addr - 0x0a];
else
return 0;
case 0x0b:
if (VLM_BANK < 13) {
nsc366_hwm_log("NSC366 Voltage Monitor: Reading %d Volts from Bank %d\n", IN_FROM_REG(dev->vlm_config_bank[VLM_BANK][1], VREF), VLM_BANK);
return dev->vlm_config_bank[VLM_BANK][1];
}
else
return 0;
default:
return 0;
}
}
void
nsc366_update_vlm_io(int enable, uint16_t addr, nsc366_hwm_t *dev)
{
if(dev->vlm_addr != 0)
io_removehandler(dev->vlm_addr, 15, nsc366_vlm_read, NULL, NULL, nsc366_vlm_write, NULL, NULL, dev);
dev->vlm_addr = addr;
if((addr != 0) && enable)
io_sethandler(addr, 15, nsc366_vlm_read, NULL, NULL, nsc366_vlm_write, NULL, NULL, dev);
}
/* Temperature */
static void
nsc366_tms_write(uint16_t addr, uint8_t val, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
if(addr <= 9)
nsc366_hwm_log("NSC366 Temperature Monitor: Write 0x%02x to register 0x%02x\n", val, addr);
else
nsc366_hwm_log("NSC366 Temperature Monitor: Write 0x%02x to register 0x%02x of bank %d\n", val, addr, TMS_BANK);
switch(addr)
{
case 0x02:
dev->tms_config_global[addr] = val & 0x3f;
break;
case 0x04:
dev->tms_config_global[addr] = val & 0x3f;
break;
case 0x08:
dev->tms_config_global[addr] = val & 3;
break;
case 0x09:
dev->tms_config_global[addr] = val & 3;
break;
case 0x0a:
if(TMS_BANK < 3)
dev->tms_config_bank[TMS_BANK][addr - 0x0a] = val & 1;
break;
case 0x0c ... 0x0e:
if(TMS_BANK < 13)
dev->tms_config_bank[TMS_BANK][addr - 0x0a] = val;
break;
}
}
static uint8_t
nsc366_tms_read(uint16_t addr, void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
addr &= 0x0f;
addr++;
pclog("Reading %02x\n", addr);
switch(addr)
{
case 0x00 ... 0x09:
return dev->tms_config_global[addr];
case 0x0a:
case 0x0c ... 0x0e:
//return dev->tms_config_bank[TMS_BANK][addr - 0x0a];
return 1;
case 0x0b:
nsc366_hwm_log("NSC366 Temperature Monitor: Reading %d Degrees Celsius from Bank %d\n", TEMP_FROM_REG(dev->tms_config_bank[TMS_BANK][1]), TMS_BANK);
return dev->tms_config_bank[TMS_BANK][1];
default:
return 0;
}
}
void
nsc366_update_tms_io(int enable, uint16_t addr, nsc366_hwm_t *dev)
{
if(dev->vlm_addr != 0)
io_removehandler(dev->tms_addr, 15, nsc366_tms_read, NULL, NULL, nsc366_tms_write, NULL, NULL, dev);
dev->tms_addr = addr;
if((addr != 0) && enable)
io_sethandler(addr, 15, nsc366_tms_read, NULL, NULL, nsc366_tms_write, NULL, NULL, dev);
}
#define TEMP_FROM_REG(val) ((val) * 1000)
static void
nsc366_hwm_reset(void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
memset(dev->fscm_config, 0, sizeof(dev->fscm_config));
dev->fscm_addr = 0;
/* Get fan reports from defaults */
dev->fscm_config[0x07] = FAN_TO_REG(dev->values->fans[0], FAN_DIV_FROM_REG(dev->fscm_config[0x06]));
dev->fscm_config[0x0a] = FAN_TO_REG(dev->values->fans[1], FAN_DIV_FROM_REG(dev->fscm_config[0x06]));
dev->fscm_config[0x0d] = FAN_TO_REG(dev->values->fans[2], FAN_DIV_FROM_REG(dev->fscm_config[0x06]));
memset(dev->vlm_config_global, 0, sizeof(dev->vlm_config_global));
memset(dev->vlm_config_bank, 0, sizeof(dev->vlm_config_bank));
dev->vlm_addr = 0;
dev->vlm_config_global[0x08] = 3;
/* Get voltage reports from defaults */
for(int i = 0; i < 13; i++) {
dev->vlm_config_bank[i][1] = IN_TO_REG(dev->values->voltages[i], VREF);
}
memset(dev->tms_config_global, 0, sizeof(dev->tms_config_global));
memset(dev->tms_config_bank, 0, sizeof(dev->tms_config_bank));
dev->tms_addr = 0;
dev->tms_config_global[0x08] = 3;
/* Get temperature reports from defaults */
for(int i = 0; i < 4; i++)
dev->tms_config_bank[i][1] = TEMP_TO_REG(dev->values->temperatures[i]);
}
static void
nsc366_hwm_close(void *priv)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)priv;
free(dev);
}
static void *
nsc366_hwm_init(const device_t *info)
{
nsc366_hwm_t *dev = (nsc366_hwm_t *)malloc(sizeof(nsc366_hwm_t));
memset(dev, 0, sizeof(nsc366_hwm_t));
/* Initialize the default values */
hwm_values_t defaults = {
{
3000, /* FAN 0 */
3000, /* FAN 1 */
3000 /* FAN 2 */
},
{
255, /* Temperature 0 */
255,
255,
155
},
{
65535,
65535,
65535,
}
};
hwm_values = defaults;
dev->values = &hwm_values;
return dev;
}
const device_t nsc366_hwm_device = {
.name = "National Semiconductor NSC366 Hardware Monitor",
.internal_name = "nsc366_hwm",
.flags = 0,
.local = 0,
.init = nsc366_hwm_init,
.close = nsc366_hwm_close,
.reset = nsc366_hwm_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,180 @@
/*
* Intel ICH2 GPIO
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#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/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/intel_ich2_gpio.h>
#ifdef ENABLE_INTEL_ICH2_GPIO_LOG
int intel_ich2_gpio_do_log = ENABLE_INTEL_ICH2_GPIO_LOG;
static void
intel_ich2_gpio_log(const char *fmt, ...)
{
va_list ap;
if (intel_ich2_gpio_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define intel_ich2_gpio_log(fmt, ...)
#endif
static void
intel_ich2_gpio_write(uint16_t addr, uint8_t val, void *priv)
{
intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv;
addr -= dev->gpio_addr;
intel_ich2_gpio_log("Intel ICH2 GPIO: Write 0x%02x on GPIO Register 0x%02x\n", val, addr);
switch(addr)
{
/* GPIO Use Enable */
case 0x00:
dev->gpio_regs[addr] = val & 0x3f;
break;
case 0x01:
dev->gpio_regs[addr] = val & 8;
break;
case 0x02:
dev->gpio_regs[addr] = val & 0x20;
break;
/* GPIO I/O Select */
case 0x07:
dev->gpio_regs[addr] = val & 0x1b;
break;
/* GPIO Level */
case 0x0e:
dev->gpio_regs[addr] = val;
break;
case 0x0f:
dev->gpio_regs[addr] = val & 0x1b;
dev->gpio_regs[addr] &= dev->gpio_regs[0x1b]; // Mask out whatever change if the bits aren't programmed as outputs.
break;
/* GPIO Blink which is not Utilized */
case 0x1a:
dev->gpio_regs[addr] = val & 6;
break;
case 0x1b:
dev->gpio_regs[addr] = val & 0x1a;
break;
/* GPIO Signal Inverter */
case 0x2d:
dev->gpio_regs[addr] = val & 0x39;
break;
}
}
static uint8_t
intel_ich2_gpio_read(uint16_t addr, void *priv)
{
intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv;
addr -= dev->gpio_addr;
intel_ich2_gpio_log("Intel ICH2 GPIO: Reading 0x%02x from Register 0x%02x\n", dev->gpio_regs[addr], addr);
if(addr <= 0x2f)
return dev->gpio_regs[addr];
else
return 0xff;
}
void
intel_ich2_gpio_base(int enable, uint16_t addr, intel_ich2_gpio_t *dev)
{
if(dev->gpio_addr != 0)
io_removehandler(dev->gpio_addr, 15, intel_ich2_gpio_read, NULL, NULL, intel_ich2_gpio_write, NULL, NULL, dev);
dev->gpio_addr = addr;
if((addr != 0) && enable)
io_sethandler(addr, 15, intel_ich2_gpio_read, NULL, NULL, intel_ich2_gpio_write, NULL, NULL, dev);
}
static void
intel_ich2_gpio_reset(void *priv)
{
intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv;
dev->gpio_addr = 0;
/* Enabled GPIO's */
dev->gpio_regs[0x00] = 0x80;
dev->gpio_regs[0x01] = 0x31;
dev->gpio_regs[0x03] = 0x1a;
/* GPIO Drives (Input or Output) */
dev->gpio_regs[0x04] = 0xff;
dev->gpio_regs[0x05] = 0xff;
dev->gpio_regs[0x0e] = 0x3f;
dev->gpio_regs[0x0f] = 0x1b;
dev->gpio_regs[0x16] = 0x63;
dev->gpio_regs[0x17] = 0x06;
}
static void
intel_ich2_gpio_close(void *priv)
{
intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv;
free(dev);
}
static void *
intel_ich2_gpio_init(const device_t *info)
{
intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) malloc(sizeof(intel_ich2_gpio_t));
memset(dev, 0, sizeof(intel_ich2_gpio_t));
intel_ich2_gpio_reset(dev);
return dev;
}
const device_t intel_ich2_gpio_device = {
.name = "Intel ICH2 GPIO",
.internal_name = "intel_ich2_gpio",
.flags = 0,
.local = 0,
.init = intel_ich2_gpio_init,
.close = intel_ich2_gpio_close,
.reset = intel_ich2_gpio_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,107 @@
/*
* Intel ICH2 Trap Handler
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#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/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/apm.h>
#include <86box/nvr.h>
#include <86box/acpi.h>
#include <86box/intel_ich2_trap.h>
#ifdef ENABLE_INTEL_ICH2_TRAP_LOG
int intel_ich2_trap_do_log = ENABLE_INTEL_ICH2_TRAP_LOG;
static void
intel_ich2_trap_log(const char *fmt, ...)
{
va_list ap;
if (intel_ich2_trap_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define intel_ich2_trap_log(fmt, ...)
#endif
void
intel_ich2_trap_set_acpi(intel_ich2_trap_t *trap, acpi_t *acpi)
{
trap->acpi = acpi;
}
static void
intel_ich2_trap_kick(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
{
intel_ich2_trap_t *trap = (intel_ich2_trap_t *) priv;
intel_ich2_trap_log("Intel ICH2 Trap: Entered an I/O Trap. Provoking an SMI.\n");
acpi_raise_smi(trap->acpi, 1);
}
void
intel_ich2_device_trap_setup(int enable, uint8_t acpi_reg, uint8_t acpi_reg_val, uint16_t addr, uint16_t size, int is_hdd, intel_ich2_trap_t *trap)
{
uint8_t acpi_trap_recieve = ((acpi_reg == 0x49) ? (trap->acpi->regs.devtrap_en >> 8) : (trap->acpi->regs.devtrap_en)) & 0xff; // Check if the decoded range is enabled on ACPIS
int acpi_enable = !!(acpi_trap_recieve & acpi_reg_val);
int trap_enabled = acpi_enable && enable;
if(trap_enabled)
{
intel_ich2_trap_log("Intel ICH2 Trap: An I/O has been enabled on range 0x%x\n", addr);
io_trap_add(intel_ich2_trap_kick, trap->trap);
}
io_trap_remap(trap->trap, trap_enabled, addr, size);
}
static void
intel_ich2_trap_close(void *priv)
{
intel_ich2_trap_t *trap = (intel_ich2_trap_t *) priv;
io_trap_remove(trap->trap); // Remove the I/O Trap
free(trap);
}
static void *
intel_ich2_trap_init(const device_t *info)
{
intel_ich2_trap_t *trap = (intel_ich2_trap_t *) malloc(sizeof(intel_ich2_trap_t));
memset(trap, 0, sizeof(intel_ich2_trap_t));
intel_ich2_trap_log("Intel ICH2 Trap: Starting a new Trap handler.");
return trap;
}
const device_t intel_ich2_trap_device = {
.name = "Intel ICH2 Trap Hander",
.internal_name = "intel_ich2_trap",
.flags = 0,
.local = 0,
.init = intel_ich2_trap_init,
.close = intel_ich2_trap_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -33,20 +33,22 @@
#define PCI_BRIDGE_DEC_21150 0x10110022
#define PCI_BRIDGE_INTEL_ICH2 0x8086244e
#define AGP_BRIDGE_ALI_M5243 0x10b95243
#define AGP_BRIDGE_ALI_M5247 0x10b95247
#define AGP_BRIDGE_INTEL_440LX 0x80867181
#define AGP_BRIDGE_INTEL_440BX 0x80867191
#define AGP_BRIDGE_INTEL_440GX 0x808671a1
#define AGP_BRIDGE_INTEL_815EP 0x80861131
#define AGP_BRIDGE_VIA_597 0x11068597
#define AGP_BRIDGE_VIA_598 0x11068598
#define AGP_BRIDGE_VIA_691 0x11068691
#define AGP_BRIDGE_VIA_8601 0x11068601
#define AGP_BRIDGE_ALI(x) (((x) >> 16) == 0x10b9)
#define AGP_BRIDGE_INTEL(x) (((x) >> 16) == 0x8086)
#define AGP_BRIDGE_INTEL(x) ((((x) >> 16) == 0x8086) && ((x) != PCI_BRIDGE_INTEL_ICH2))
#define AGP_BRIDGE_VIA(x) (((x) >> 16) == 0x1106)
#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_ALI_M5243)
#define AGP_BRIDGE(x) (((x) >= AGP_BRIDGE_ALI_M5243) && ((x) != PCI_BRIDGE_INTEL_ICH2))
typedef struct
@@ -116,6 +118,10 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
if (AGP_BRIDGE_INTEL(dev->local)) {
if (dev->local == AGP_BRIDGE_INTEL_440BX)
val &= 0x1f;
else if (dev->local == AGP_BRIDGE_INTEL_815EP)
val &= 0x17;
else if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0x47;
} else if (dev->local == AGP_BRIDGE_ALI_M5243)
val |= 0x02;
else if (dev->local == AGP_BRIDGE_ALI_M5247)
@@ -129,13 +135,17 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
val &= 0x01;
else if (AGP_BRIDGE_ALI(dev->local))
val &= 0x01;
else if (PCI_BRIDGE_INTEL_ICH2)
val &= 0x01;
else
val &= 0x03;
break;
case 0x07:
if (dev->local == AGP_BRIDGE_INTEL_440LX)
if ((dev->local == AGP_BRIDGE_INTEL_440LX) || (dev->local == AGP_BRIDGE_INTEL_815EP))
dev->regs[addr] &= ~(val & 0x40);
else if (dev->local == PCI_BRIDGE_INTEL_ICH2)
dev->regs[addr] &= ~(val & 0xf9);
else if (dev->local == AGP_BRIDGE_ALI_M5243)
dev->regs[addr] &= ~(val & 0xf8);
else if (dev->local == AGP_BRIDGE_ALI_M5247)
@@ -165,15 +175,22 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
case 0x1f:
if (AGP_BRIDGE_INTEL(dev->local)) {
if (dev->local == AGP_BRIDGE_INTEL_440LX)
if ((dev->local == AGP_BRIDGE_INTEL_440LX) || (dev->local == PCI_BRIDGE_INTEL_ICH2))
dev->regs[addr] &= ~(val & 0xf1);
else if ((dev->local == AGP_BRIDGE_INTEL_440BX) ||
(dev->local == AGP_BRIDGE_INTEL_440GX))
dev->regs[addr] &= ~(val & 0xf0);
else if (dev->local == AGP_BRIDGE_INTEL_815EP)
dev->regs[addr] &= ~(val & 0xb2);
} else if (AGP_BRIDGE_ALI(dev->local))
dev->regs[addr] &= ~(val & 0xf0);
return;
case 0x1b:
if ((dev->local == AGP_BRIDGE_INTEL_815EP) || (dev->local == PCI_BRIDGE_INTEL_ICH2))
val &= 0xf8;
break;
case 0x1c: case 0x1d: case 0x20: case 0x22:
case 0x24: case 0x26:
val &= 0xf0;
@@ -200,6 +217,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
}
else if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0xef;
else if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0x2f;
break;
case 0x3f:
@@ -219,6 +238,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
case 0x40:
if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x32;
else if ((dev->local == AGP_BRIDGE_INTEL_815EP) || (dev->local == PCI_BRIDGE_INTEL_ICH2))
val &= 0x01;
break;
case 0x41:
@@ -238,6 +259,16 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
val &= 0x03;
break;
case 0x50:
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0x06;
break;
case 0x51:
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0x03;
break;
case 0x64:
if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x7e;
@@ -248,6 +279,11 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
val &= 0x3f;
break;
case 0x70:
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0xf8;
break;
case 0x86:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x3f;
@@ -278,6 +314,16 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
return;
break;
case 0x90:
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
val &= 0x06;
break;
case 0x91:
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
dev->regs[addr] = ~(val & 0x06);
break;
case 0xe0: case 0xe1:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
@@ -379,6 +425,11 @@ pci_bridge_reset(void *priv)
dev->regs[0x07] = 0x02;
break;
case PCI_BRIDGE_INTEL_ICH2:
dev->regs[0x04] = 0x01;
dev->regs[0x06] = 0x80;
break;
case AGP_BRIDGE_ALI_M5243:
dev->regs[0x04] = 0x06;
dev->regs[0x07] = 0x04;
@@ -411,6 +462,11 @@ pci_bridge_reset(void *priv)
dev->regs[0x07] = dev->regs[0x08] = 0x02;
break;
case AGP_BRIDGE_INTEL_815EP:
dev->regs[0x06] = 0x20;
dev->regs[0x08] = 0x02;
break;
case AGP_BRIDGE_VIA_597:
case AGP_BRIDGE_VIA_598:
case AGP_BRIDGE_VIA_691:
@@ -453,6 +509,9 @@ pci_bridge_reset(void *priv)
dev->regs[0x43] = 0x02;
dev->regs[0xdc] = dev->regs[0xde] = 0x01;
}
if (dev->local == PCI_BRIDGE_INTEL_ICH2)
dev->regs[0x70] = 0x20;
}
@@ -471,27 +530,32 @@ pci_bridge_init(const device_t *info)
pci_bridge_reset(dev);
dev->slot = pci_add_card(AGP_BRIDGE(dev->local) ? PCI_ADD_AGPBRIDGE : PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev);
interrupt_count = sizeof(interrupts);
interrupt_mask = interrupt_count - 1;
if (dev->slot < 32) {
for (i = 0; i < interrupt_count; i++)
interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i);
}
pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]);
if (info->local == PCI_BRIDGE_DEC_21150)
slot_count = 9; /* 9 bus masters */
else
slot_count = 1; /* AGP bridges always have 1 slot */
if ((info->local != PCI_BRIDGE_INTEL_ICH2) && (info->local != AGP_BRIDGE_INTEL_815EP)) /* Let the machine configuration slot handle the absurd interrupt tables */
{
interrupt_count = sizeof(interrupts);
interrupt_mask = interrupt_count - 1;
if (dev->slot < 32) {
for (i = 0; i < interrupt_count; i++)
interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i);
}
for (i = 0; i < slot_count; i++) {
/* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */
pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]);
pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL,
interrupts[i & interrupt_mask],
interrupts[(i + 1) & interrupt_mask],
interrupts[(i + 2) & interrupt_mask],
interrupts[(i + 3) & interrupt_mask]);
pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]);
if (info->local == PCI_BRIDGE_DEC_21150)
slot_count = 9; /* 9 bus masters */
else
slot_count = 1; /* AGP bridges always have 1 slot */
for (i = 0; i < slot_count; i++) {
/* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */
pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]);
pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL,
interrupts[i & interrupt_mask],
interrupts[(i + 1) & interrupt_mask],
interrupts[(i + 2) & interrupt_mask],
interrupts[(i + 3) & interrupt_mask]);
}
}
return dev;
@@ -584,6 +648,34 @@ const device_t i440gx_agp_device = {
.config = NULL
};
const device_t intel_ich2_hub_device = {
.name = "Intel ICH2 Hub Bridge",
.internal_name = "intel_ich2_hub",
.flags = DEVICE_PCI,
.local = PCI_BRIDGE_INTEL_ICH2,
.init = pci_bridge_init,
.close = NULL,
.reset = pci_bridge_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t intel_815ep_agp_device = {
.name = "Intel 815EP MCH AGP Bridge",
.internal_name = "intel_815ep_agp",
.flags = DEVICE_PCI,
.local = AGP_BRIDGE_INTEL_815EP,
.init = pci_bridge_init,
.close = NULL,
.reset = pci_bridge_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t via_vp3_agp_device = {
.name = "VIA Apollo VP3 AGP Bridge",
.internal_name = "via_vp3_agp",

View File

@@ -24,11 +24,14 @@
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/pic.h>
#include <86box/timer.h>
#include <86box/i2c.h>
#include <86box/apm.h>
#include <86box/nvr.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#ifdef ENABLE_SMBUS_PIIX4_LOG
int smbus_piix4_do_log = ENABLE_SMBUS_PIIX4_LOG;
@@ -48,6 +51,34 @@ smbus_piix4_log(const char *fmt, ...)
#define smbus_piix4_log(fmt, ...)
#endif
void
smbus_piix4_get_acpi(smbus_piix4_t *dev, acpi_t *acpi)
{
dev->acpi = acpi;
}
void
smbus_piix4_get_irq(uint8_t irq, smbus_piix4_t *dev)
{
dev->irq = irq;
}
void
smbus_piix4_smi_en(uint8_t smi_en, smbus_piix4_t *dev)
{
dev->smi_en = smi_en;
}
static void
smbus_piix4_raise_smi(smbus_piix4_t *dev)
{
if (dev->smi_en) { /* Raise SMI when needed if it's enabled by the Chipset */
dev->acpi->regs.smi_sts |= 0x00010000;
acpi_raise_smi(dev->acpi, 1);
}
else
picint(1 << dev->irq);
}
static uint8_t
smbus_piix4_read(uint16_t addr, void *priv)
@@ -99,7 +130,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
{
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
uint8_t smbus_addr, cmd, read, block_len, prev_stat;
uint16_t timer_bytes = 0, i;
uint16_t timer_bytes = 0, i = 0;
smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val);
@@ -107,7 +138,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
dev->next_stat = 0x00;
switch (addr - dev->io_base) {
case 0x00:
for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */
for (smbus_addr = 0x02; smbus_addr <= ((dev->local == SMBUS_INTEL_ICH2) ? 0x40 : 0x10); smbus_addr <<= 1) { /* handle clearable bits */
if (val & smbus_addr)
dev->stat &= ~smbus_addr;
}
@@ -213,22 +244,52 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
/* fall-through */
case 0xd: /* I2C block R/W */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
timer_bytes++;
if (dev->local == SMBUS_INTEL_ICH2) {
if (!dev->byte_rw) {
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if(read)
dev->data0 = i2c_read(i2c_smbus, smbus_addr); // For byte reads, the count is recieved and stored at the DATA0 register
else
i2c_write(i2c_smbus, smbus_addr, dev->data0);
if (read) {
/* block read [data0] (I2C) or [first byte] (SMBus) bytes */
if (cmd == 0x5)
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
for (i = 0; i < dev->data0; i++)
dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr);
} else {
if (cmd == 0x5) /* send length [data0] as first byte on SMBus */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
/* block write [data0] bytes */
for (i = 0; i < dev->data0; i++) {
if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK]))
break;
dev->byte_rw = 1;
}
if (read) {
dev->block_data_byte = i2c_read(i2c_smbus, smbus_addr);
dev->stat |= 0x80;
smbus_piix4_raise_smi(dev);
if(dev->ctl & 0x20) { /* Finish the Transfer */
dev->byte_rw = 0;
dev->stat |= 2;
}
}
else {
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if (((dev->byte_rw >> 4) & 0xff) < dev->data0) {
i2c_write(i2c_smbus, smbus_addr, dev->block_data_byte);
dev->stat |= 0x80;
dev->byte_rw += 0x10000;
}
else dev->byte_rw = 0;
}
}
else {
if (read) {
timer_bytes++;
/* block read [data0] (I2C) or [first byte] (SMBus) bytes */
if (cmd == 0x5)
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
for (i = 0; i < dev->data0; i++)
dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr);
} else {
if (cmd == 0x5) /* send length [data0] as first byte on SMBus */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
/* block write [data0] bytes */
for (i = 0; i < dev->data0; i++) {
if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK]))
break;
}
}
}
timer_bytes += i;
@@ -283,7 +344,12 @@ unknown_protocol:
}
/* Finish transfer. */
i2c_stop(i2c_smbus, smbus_addr);
if (dev->local == SMBUS_INTEL_ICH2) {
/* ICH2 SMBus specific. Transfer on Byte command doesn't stop till their specific points. */
if (!dev->byte_rw)
i2c_stop(i2c_smbus, smbus_addr);
} else
i2c_stop(i2c_smbus, smbus_addr);
}
break;
@@ -304,9 +370,13 @@ unknown_protocol:
break;
case 0x07:
dev->data[dev->index++] = val;
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
dev->index = 0;
if (dev->local == SMBUS_INTEL_ICH2)
dev->block_data_byte = val;
else {
dev->data[dev->index++] = val;
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
dev->index = 0;
}
break;
}
@@ -362,7 +432,20 @@ smbus_piix4_init(const device_t *info)
dev->local = info->local;
/* We save the I2C bus handle on dev but use i2c_smbus for all operations because
dev and therefore dev->i2c will be invalidated if a device triggers a hard reset. */
i2c_smbus = dev->i2c = i2c_addbus((dev->local == SMBUS_VIA) ? "smbus_vt82c686b" : "smbus_piix4");
switch(dev->local)
{
case SMBUS_PIIX4:
i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4");
break;
case SMBUS_INTEL_ICH2:
i2c_smbus = dev->i2c = i2c_addbus("smbus_intel_ich2");
break;
case SMBUS_VIA:
i2c_smbus = dev->i2c = i2c_addbus("smbus_vt82c686b");
break;
}
timer_add(&dev->response_timer, smbus_piix4_response, dev, 0);
@@ -398,6 +481,20 @@ const device_t piix4_smbus_device = {
.config = NULL
};
const device_t intel_ich2_smbus_device = {
.name = "Intel ICH2 SMBus Host Controller",
.internal_name = "intel_ich2_smbus",
.flags = DEVICE_AT,
.local = SMBUS_INTEL_ICH2,
.init = smbus_piix4_init,
.close = smbus_piix4_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t via_smbus_device = {
.name = "VIA VT82C686B SMBus Host Controller",
.internal_name = "via_smbus",

198
src/device/tco.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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.
*
* Intel TCO Handler.
*
* Note: There's a TCO Timer too but for now it's of no use thus
* not implemented
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#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/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/nmi.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/tco.h>
#ifdef ENABLE_TCO_LOG
int tco_do_log = ENABLE_TCO_LOG;
static void
tco_log(const char *fmt, ...)
{
va_list ap;
if (tco_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define tco_log(fmt, ...)
#endif
void
tco_timer_handler(void *priv)
{
/* TODO: Implement the TCO timer. */
// tco_t *dev = (tco_t *) priv;
}
void
tco_irq_update(tco_t *dev, uint16_t new_irq)
{
tco_log("TCO: Update IRQ to %d\n", new_irq);
dev->tco_irq = new_irq;
}
void
tco_write(uint16_t addr, uint8_t val, tco_t *dev)
{
addr -= 0x60;
tco_log("TCO: Write 0x%02x to Register 0x%02x\n", val, addr);
switch(addr) {
case 0x00:
dev->regs[addr] = val;
break;
case 0x01:
dev->regs[addr] = val & 0x3f;
break;
case 0x02: /* TCO Data in */
dev->regs[addr] = val;
dev->regs[0x04] |= 2;
smi_line = 1;
break;
case 0x03: /* TCO Data out */
dev->regs[addr] = val;
dev->regs[0x04] |= 4;
picint(dev->tco_irq);
break;
case 0x04:
dev->regs[addr] &= 0x8f;
break;
case 0x05:
dev->regs[addr] &= 0x1f;
break;
case 0x06:
dev->regs[addr] &= 0x07;
break;
case 0x09:
if (val & 1) {
if (!nmi) /* If we're already on NMI */
nmi = 1;
dev->regs[addr] = (dev->regs[addr] & 1) | val;
dev->regs[addr] &= val;
} else
dev->regs[addr] = 0x0f;
break;
case 0x0a:
dev->regs[addr] = val & 0x06; // Intrusion Interrupt or SMI. We never get intruded so we never control it.
break;
case 0x0c ... 0x0d:
dev->regs[addr] = val;
break;
case 0x10:
dev->regs[addr] = val & 0x03;
break;
}
}
uint8_t
tco_read(uint16_t addr, tco_t *dev)
{
addr -= 0x60;
uint8_t ret = 0x00;
if (addr <= 0x10) {
tco_log("TCO: Read 0x%02x from Register 0x%02x\n", dev->regs[addr], addr);
ret = dev->regs[addr];
}
return ret;
}
static void
tco_reset(void *priv)
{
tco_t *dev = (tco_t *) priv;
memset(dev->regs, 0, sizeof(dev->regs));
dev->tco_irq = 9;
dev->regs[0x01] = 0x04;
dev->regs[0x10] = 0x03;
}
static void
tco_close(void *priv)
{
tco_t *dev = (tco_t *) priv;
free(dev);
}
static void *
tco_init(const device_t *info)
{
tco_t *dev = (tco_t *) malloc(sizeof(tco_t));
memset(dev, 0, sizeof(tco_t));
tco_reset(dev);
return dev;
}
const device_t tco_device = {
.name = "Intel TCO",
.internal_name = "tco",
.flags = 0,
.local = 0,
.init = tco_init,
.close = tco_close,
.reset = tco_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -1171,6 +1171,28 @@ dma_alias_set_piix(void)
}
void
dma_lpc_init(void) /* Addresses LPC DMA uses */
{
io_sethandler(0x1000, 16,
dma_read,NULL,NULL, dma_write,NULL,NULL, NULL);
io_sethandler(0x1080, 8,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
io_sethandler(0x10C0, 32,
dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL);
io_sethandler(0x1088, 8,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
io_sethandler(0x1090, 1,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
io_sethandler(0x1094, 3,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
io_sethandler(0x1098, 1,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
io_sethandler(0x109C, 3,
dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL);
}
void
dma_alias_remove(void)
{

View File

@@ -22,6 +22,8 @@
extern "C" {
#endif
#include <86box/tco.h> /* TCO Header. Needed for Intel ICH chipsets. */
#define ACPI_TIMER_FREQ 3579545
#define PM_FREQ ACPI_TIMER_FREQ
@@ -51,6 +53,7 @@ extern "C" {
#define VEN_ALI 0x010b9
#define VEN_INTEL 0x08086
#define VEN_INTEL_ICH2 0x18086
#define VEN_SIS 0x01039
#define VEN_SMC 0x01055
#define VEN_VIA 0x01106
@@ -59,18 +62,19 @@ extern "C" {
typedef struct
{
uint8_t acpitst, auxen, auxsts, plvl2, plvl3,
uint8_t acpitst, auxen, auxsts, bus_cyc_track, plvl2, plvl3,
smicmd, gpio_dir,
gpio_val, muxcntrl, ali_soft_smi,
timer32, smireg,
gpireg[3], gporeg[4],
gpireg[3], gporeg[4], tco[17],
extiotrapsts, extiotrapen;
uint16_t pmsts, pmen,
pmcntrl, gpsts, gpsts1,
pmcntrl, bus_addr_track, devact_sts,
devtrap_en, gpsts, gpsts1,
gpen, gpen1, gpscien,
gpcntrl, gplvl, gpmux,
gpsel, gpsmien, pscntrl,
gpscists;
gpscists, mon_smi;
int smi_lock, smi_active;
uint32_t pcntrl, p2cntrl, glbsts,
devsts, glben,
@@ -78,7 +82,7 @@ typedef struct
padsts, paden,
gptren, gptimer,
gpo_val, gpi_val,
extsmi_val, pad0;
extsmi_val, smi_en, smi_sts, pad0;
} acpi_regs_t;
@@ -96,6 +100,7 @@ typedef struct
pc_timer_t timer, resume_timer;
nvr_t *nvr;
apm_t *apm;
tco_t *tco;
void *i2c,
(*trap_update)(void *priv), *trap_priv;
} acpi_t;
@@ -106,6 +111,7 @@ extern int acpi_rtc_status;
extern const device_t acpi_ali_device;
extern const device_t acpi_intel_device;
extern const device_t acpi_intel_ich2_device;
extern const device_t acpi_smc_device;
extern const device_t acpi_via_device;
extern const device_t acpi_via_596b_device;
@@ -125,6 +131,7 @@ extern void acpi_set_irq_line(acpi_t *dev, int irq_line);
extern void acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level);
extern void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default);
extern void acpi_set_nvr(acpi_t *dev, nvr_t *nvr);
extern void acpi_set_tco(acpi_t *dev, tco_t *tco);
extern void acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv);
extern uint8_t acpi_ali_soft_smi_status_read(acpi_t *dev);
extern void acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi);

View File

@@ -99,6 +99,9 @@ extern const device_t slc90e66_device;
extern const device_t ioapic_device;
extern const device_t intel_815ep_device;
extern const device_t intel_ich2_device;
/* OPTi */
extern const device_t opti283_device;
extern const device_t opti291_device;

View File

@@ -52,6 +52,7 @@
#define CONFIG_HEX20 8
#define CONFIG_MAC 9
#define CONFIG_MIDI_IN 10
#define CONFIG_BIOS 11
enum {
@@ -77,6 +78,14 @@ typedef struct {
int value;
} device_config_selection_t;
typedef struct {
const char *name;
const char *internal_name;
int bios_type;
int files_no;
const char **files;
} device_config_bios_t;
typedef struct {
int16_t min;
int16_t max;
@@ -92,6 +101,7 @@ typedef struct {
const char *file_filter;
const device_config_spinner_t spinner;
const device_config_selection_t selection[16];
const device_config_bios_t *bios;
} device_config_t;
typedef struct _device_ {
@@ -161,6 +171,7 @@ extern void device_set_config_hex16(const char *s, int val);
extern void device_set_config_hex20(const char *s, int val);
extern void device_set_config_mac(const char *s, int val);
extern const char *device_get_config_string(const char *name);
#define device_get_config_bios device_get_config_string
extern char * device_get_internal_name(const device_t *d);

View File

@@ -93,6 +93,8 @@ extern void dma_alias_set_piix(void);
extern void dma_alias_remove(void);
extern void dma_alias_remove_piix(void);
extern void dma_lpc_init(void);
extern void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize);
extern void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize);

View File

@@ -30,4 +30,7 @@ extern const device_t sst_flash_39sf010_device;
extern const device_t sst_flash_39sf020_device;
extern const device_t sst_flash_39sf040_device;
extern const device_t sst_flash_49lf002_device;
extern const device_t sst_flash_49lf004_device;
#endif /*EMU_FLASH_H*/

View File

@@ -55,6 +55,8 @@ extern uint8_t lm78_as99127f_write(void *priv, uint8_t reg, uint8_t val);
/* hwm_vt82c686.c */
extern void vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv);
/* sio_w83627hf.c */
extern void w83627hf_stabilizer(int vcoreb, int fan1, int fan2, int fan3);
/* Refer to specific hardware monitor implementations for the meaning of hwm_values. */
extern hwm_values_t hwm_values;

View File

@@ -0,0 +1,30 @@
/*
* Intel ICH2 GPIO Header
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#ifndef EMU_INTEL_ICH2_GPIO_H
# define EMU_INTEL_ICH2_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct intel_ich2_gpio_t
{
uint16_t gpio_addr;
uint8_t gpio_regs[48];
} intel_ich2_gpio_t;
void intel_ich2_gpio_base(int enable, uint16_t addr, intel_ich2_gpio_t *dev);
extern const device_t intel_ich2_gpio_device;
#ifdef __cplusplus
}
#endif
#endif /*EMU_INTEL_ICH2_GPIO_H*/

View File

@@ -0,0 +1,31 @@
/*
* Intel ICH2 Trap Header
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#ifndef EMU_INTEL_ICH2_TRAP_H
# define EMU_INTEL_ICH2_TRAP_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct intel_ich2_trap_t
{
acpi_t *acpi;
void *trap;
} intel_ich2_trap_t;
extern void intel_ich2_trap_set_acpi(intel_ich2_trap_t *trap, acpi_t *acpi);
extern void intel_ich2_device_trap_setup(int enable, uint8_t acpi_reg, uint8_t acpi_reg_val, uint16_t addr, uint16_t size, int is_hdd, intel_ich2_trap_t *trap);
extern const device_t intel_ich2_trap_device;
#ifdef __cplusplus
}
#endif
#endif /*EMU_INTEL_ICH2_TRAP_H*/

View File

@@ -161,6 +161,7 @@ enum {
MACHINE_TYPE_SLOT1_370,
MACHINE_TYPE_SLOT2,
MACHINE_TYPE_SOCKET370,
MACHINE_TYPE_ICH2,
MACHINE_TYPE_MISC,
MACHINE_TYPE_MAX
};
@@ -206,6 +207,7 @@ enum {
MACHINE_CHIPSET_INTEL_440BX,
MACHINE_CHIPSET_INTEL_440ZX,
MACHINE_CHIPSET_INTEL_440GX,
MACHINE_CHIPSET_INTEL_I815EP,
MACHINE_CHIPSET_OPTI_283,
MACHINE_CHIPSET_OPTI_291,
MACHINE_CHIPSET_OPTI_493,
@@ -332,6 +334,11 @@ extern int machine_get_ram_granularity(int m);
extern int machine_get_type(int m);
extern void machine_close(void);
extern uint8_t machine_get_p1(void);
extern void machine_load_p1(int m);
extern uint32_t machine_get_gpi(void);
extern void machine_load_gpi(int m);
extern void machine_set_gpi(uint32_t gpi);
/* Initialization functions for boards and systems. */
extern void machine_common_init(const machine_t *);
@@ -696,6 +703,11 @@ extern int machine_at_p6bap_init(const machine_t *);
/* m_at_misc.c */
extern int machine_at_vpc2007_init(const machine_t *);
/* m_at_ich2.c */
extern int machine_at_m6tsl_init(const machine_t *);
extern int machine_at_m6tss_init(const machine_t *);
extern int machine_at_s2080_init(const machine_t *);
/* m_at_t3100e.c */
extern int machine_at_t3100e_init(const machine_t *);

View File

@@ -0,0 +1,44 @@
/*
* National Semiconductor PC87366(NSC366) Header
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#ifndef EMU_NSC_366_H
# define EMU_NSC_366_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
hwm_values_t *values;
uint8_t fscm_enable;
uint16_t fscm_addr;
uint8_t fscm_config[15];
uint16_t vlm_addr;
uint8_t vlm_config_global[10];
uint8_t vlm_config_bank[13][5];
uint16_t tms_addr;
uint8_t tms_config_global[10];
uint8_t tms_config_bank[4][5];
} nsc366_hwm_t;
extern void nsc366_update_fscm_io(int enable, uint16_t addr, nsc366_hwm_t *dev);
extern void nsc366_update_vlm_io(int enable, uint16_t addr, nsc366_hwm_t *dev);
extern void nsc366_update_tms_io(int enable, uint16_t addr, nsc366_hwm_t *dev);
/* The Hardware Monitor */
extern const device_t nsc366_hwm_device;
#ifdef __cplusplus
}
#endif
#endif /*EMU_NSC_366_H*/

View File

@@ -138,11 +138,14 @@ extern void pci_pic_reset(void);
#ifdef EMU_DEVICE_H
extern const device_t dec21150_device;
extern const device_t intel_ich2_hub_device;
extern const device_t ali5243_agp_device;
extern const device_t ali5247_agp_device;
extern const device_t i440lx_agp_device;
extern const device_t i440bx_agp_device;
extern const device_t i440gx_agp_device;
extern const device_t intel_815ep_agp_device;
extern const device_t via_vp3_agp_device;
extern const device_t via_mvp3_agp_device;
extern const device_t via_apro_agp_device;

View File

@@ -70,7 +70,8 @@ extern uint64_t PITCONST, ISACONST,
HERCCONST,
VGACONST1,
VGACONST2,
RTCCONST;
RTCCONST,
TCOCONST;
extern int refresh_at_enable;

View File

@@ -45,6 +45,8 @@ extern const device_t i82091aa_device;
extern const device_t i82091aa_398_device;
extern const device_t i82091aa_ide_pri_device;
extern const device_t i82091aa_ide_device;
extern const device_t nsc366_device;
extern const device_t nsc366_4f_device;
extern const device_t pc87306_device;
extern const device_t pc87307_device;
extern const device_t pc87307_15c_device;
@@ -71,6 +73,8 @@ extern const device_t sio_detect_device;
#endif
extern const device_t um8669f_device;
extern const device_t via_vt82c686_sio_device;
extern const device_t w83627hf_device;
extern const device_t w83627hf_no_hwm_device;
extern const device_t w83787f_device;
extern const device_t w83787f_ide_device;
extern const device_t w83787f_ide_en_device;

View File

@@ -18,6 +18,9 @@
#ifndef EMU_SMBUS_PIIX4_H
# define EMU_SMBUS_PIIX4_H
#include <86box/apm.h>
#include <86box/nvr.h>
#include <86box/acpi.h>
#define SMBUS_PIIX4_BLOCK_DATA_SIZE 32
#define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1)
@@ -28,17 +31,20 @@
enum {
SMBUS_PIIX4 = 0,
SMBUS_INTEL_ICH2,
SMBUS_VIA
};
typedef struct {
uint32_t local;
uint16_t io_base;
uint16_t io_base, byte_rw;
int clock;
double bit_period;
uint8_t stat, next_stat, ctl, cmd, addr,
data0, data1,
index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE];
index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE], block_data_byte,
irq, smi_en;
acpi_t *acpi;
pc_timer_t response_timer;
void *i2c;
} smbus_piix4_t;
@@ -53,6 +59,9 @@ typedef struct {
void *i2c;
} smbus_ali7101_t;
extern void smbus_piix4_get_acpi(smbus_piix4_t *dev, acpi_t *acpi);
extern void smbus_piix4_get_irq(uint8_t irq, smbus_piix4_t *dev);
extern void smbus_piix4_smi_en(uint8_t smi_en, smbus_piix4_t *dev);
extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable);
extern void smbus_piix4_setclock(smbus_piix4_t *dev, int clock);
@@ -62,6 +71,7 @@ extern void smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint
#ifdef EMU_DEVICE_H
extern const device_t piix4_smbus_device;
extern const device_t intel_ich2_smbus_device;
extern const device_t via_smbus_device;
extern const device_t ali7101_smbus_device;

View File

@@ -25,9 +25,11 @@
#define SPD_TYPE_FPM 0x01
#define SPD_TYPE_EDO 0x02
#define SPD_TYPE_SDRAM 0x04
#define SPD_TYPE_DDR 0x07
#define SPD_MIN_SIZE_EDO 8
#define SPD_MIN_SIZE_SDRAM 8
#define SPD_MIN_SIZE_DDR 8
#define SPD_SIGNAL_LVTTL 0x01
@@ -89,6 +91,29 @@ typedef struct {
checksum2;
} spd_sdram_t;
typedef struct {
uint8_t bytes_used, spd_size, mem_type,
row_bits, col_bits, rows,
data_width_lsb, data_width_msb,
signal_level, tclk, tac,
config, refresh_rate,
sdram_width, ecc_width,
tccd, burst, banks, cas, cslat, we,
mod_attr, dev_attr,
tclk2, tac2, tclk3, tac3,
trp, trrd, trcd, tras,
bank_density,
ca_setup, ca_hold, data_setup, data_hold,
reserved[26],
spd_rev, checksum,
mfg_jedec[8], mfg_loc;
char part_no[18];
uint8_t rev_code[2],
mfg_year, mfg_week, serial[4], mfg_specific[27],
other_data[127],
checksum2;
} spd_ddr_t;
typedef struct {
uint8_t slot;
uint16_t size;
@@ -99,6 +124,7 @@ typedef struct {
uint8_t data[SPD_DATA_SIZE];
spd_edo_t edo_data;
spd_sdram_t sdram_data;
spd_ddr_t ddr_data;
};
void *eeprom;
} spd_t;
@@ -109,5 +135,6 @@ extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint
extern void spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit);
extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit);
extern void spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max);
extern void spd_write_drbs_intel_815ep(uint8_t *regs);
#endif /*EMU_SPD_H*/

33
src/include/86box/tco.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Intel TCO Header
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#ifndef EMU_TCO_H
# define EMU_TCO_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
uint8_t regs[17];
uint16_t tco_irq;
pc_timer_t *tco_timer;
} tco_t;
extern const device_t tco_device;
extern void tco_irq_update(tco_t *dev, uint16_t new_irq);
extern void tco_write(uint16_t addr, uint8_t val, tco_t *dev);
extern uint8_t tco_read(uint16_t addr, tco_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* EMU_TCO_H */

View File

@@ -22,7 +22,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c
m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c
m_at_socket4.c m_at_socket5.c m_at_socket7_3v.c m_at_socket7.c
m_at_sockets7.c m_at_socket8.c m_at_slot1.c m_at_slot2.c m_at_socket370.c
m_at_misc.c)
m_at_misc.c m_at_ich2.c)
if(AN430TX)
target_compile_definitions(mch PRIVATE USE_AN430TX)

148
src/machine/m_at_ich2.c Normal file
View File

@@ -0,0 +1,148 @@
/*
* Intel ICH2 based Motherboards
*
* Authors: Tiseno100,
*
* Copyright 2022 Tiseno100.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/mem.h>
#include <86box/io.h>
#include <86box/rom.h>
#include <86box/pci.h>
#include <86box/device.h>
#include <86box/chipset.h>
#include <86box/flash.h>
#include <86box/sio.h>
#include <86box/spd.h>
#include <86box/clock.h>
#include "cpu.h"
#include <86box/machine.h>
/*
* Biostar M6TSL
*
* North Bridge: Intel 815E
* Super I/O: National Semiconductor NSC366 (PC87366)
* BIOS: AwardBIOS 6.00PG
* Notes: No integrated ESS Solo & GPU
*/
int
machine_at_m6tsl_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/m6tsl/tsl0425b.bin",
0x00080000, 524288, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4);
pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x03, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x08, PCI_CARD_NORMAL, 2, 3, 4, 1);
device_add(&intel_815ep_device); /* Intel 815EP MCH (This board has normally an i815E but this doesn't matter on our implementation) */
device_add(&intel_ich2_device); /* Intel ICH2 */
device_add(&nsc366_device); /* National Semiconductor NSC366 */
device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */
device_add(ics9xxx_get(ICS9250_08)); /* ICS Clock Chip */
spd_register(SPD_TYPE_SDRAM, 0x7, 512);
return ret;
}
int
machine_at_m6tss_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/m6tss/tss0518b.bin",
0x00080000, 524288, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4);
pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x03, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); // 0x0a
pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 1, 2, 3, 4);
device_add(&intel_815ep_device); /* Intel 815EP MCH */
device_add(&intel_ich2_device); /* Intel ICH2 */
device_add(&nsc366_device); /* National Semiconductor NSC366 */
device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */
device_add(ics9xxx_get(ICS9250_08)); /* ICS Clock Chip */
spd_register(SPD_TYPE_SDRAM, 0x7, 512);
return ret;
}
/*
* Tyan Tomcat 815T (S2080)
*
* North Bridge: Intel 815EP
* Super I/O: National Semiconductor NSC366 (PC87366)
* BIOS: AMIBIOS 7 (AMI Home BIOS Fork)
* Notes: None
*/
int
machine_at_s2080_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/s2080/2080V110.ROM",
0x00080000, 524288, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0);
pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0);
pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4);
pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4);
pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 5);
pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 5, 6);
pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 5, 6, 7);
pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 5, 6, 7, 8);
pci_register_bus_slot(2, 0x08, PCI_CARD_NORMAL, 6, 7, 8, 2); // 0x0a
pci_register_bus_slot(2, 0x09, PCI_CARD_NORMAL, 7, 8, 2, 3);
device_add(&intel_815ep_device); /* Intel 815EP MCH */
device_add(&intel_ich2_device); /* Intel ICH2 */
device_add(&nsc366_device); /* National Semiconductor NSC366 */
device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */
spd_register(SPD_TYPE_SDRAM, 0x7, 512);
return ret;
}

View File

@@ -77,6 +77,7 @@ const machine_filter_t machine_types[] = {
{ "Slot 1/Socket 370", MACHINE_TYPE_SLOT1_370 },
{ "Slot 2", MACHINE_TYPE_SLOT2 },
{ "Socket 370", MACHINE_TYPE_SOCKET370 },
{ "Intel ICH2", MACHINE_TYPE_ICH2 },
{ "Miscellaneous", MACHINE_TYPE_MISC }
};
@@ -121,6 +122,7 @@ const machine_filter_t machine_chipsets[] = {
{ "Intel 440BX", MACHINE_CHIPSET_INTEL_440BX },
{ "Intel 440ZX", MACHINE_CHIPSET_INTEL_440ZX },
{ "Intel 440GX", MACHINE_CHIPSET_INTEL_440GX },
{ "Intel i815EP", MACHINE_CHIPSET_INTEL_I815EP },
{ "OPTi 283", MACHINE_CHIPSET_OPTI_283 },
{ "OPTi 291", MACHINE_CHIPSET_OPTI_291 },
{ "OPTi 493", MACHINE_CHIPSET_OPTI_493 },
@@ -10931,6 +10933,108 @@ const machine_t machines[] = {
.vid_device = NULL
},
/* Intel ICH2 */
/* Has a NSC PC87366 LPC Super I/O with on-chip AMIKey-2 KBC firmware*/
{
.name = "[Intel i815E] Biostar M6TSL",
.internal_name = "m6tsl",
.type = MACHINE_TYPE_ICH2,
.chipset = MACHINE_CHIPSET_INTEL_I815EP,
.init = machine_at_m6tsl_init,
.pad = 0,
.pad0 = 0,
.pad1 = MACHINE_AVAILABLE,
.pad2 = 0,
.cpu = {
.package = CPU_PKG_SOCKET370,
.block= CPU_BLOCK(CPU_CYRIX3S),
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0,
},
.bus_flags = MACHINE_PS2_NOISA,
.flags = MACHINE_IDE_DUAL,
.ram = {
.min = 32768,
.max = 524288,
.step = 32768,
},
.nvrmask = 255,
.device = NULL,
.vid_device = NULL
},
{
.name = "[Intel i815EP] Biostar M6TSS",
.internal_name = "m6tss",
.type = MACHINE_TYPE_ICH2,
.chipset = MACHINE_CHIPSET_INTEL_I815EP,
.init = machine_at_m6tss_init,
.pad = 0,
.pad0 = 0,
.pad1 = MACHINE_AVAILABLE,
.pad2 = 0,
.cpu = {
.package = CPU_PKG_SOCKET370,
.block = CPU_BLOCK_NONE,
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0,
},
.bus_flags = MACHINE_PS2_AGP,
.flags = MACHINE_IDE_DUAL,
.ram = {
.min = 32768,
.max = 524288,
.step = 32768,
},
.nvrmask = 255,
.kbc = KBC_UNKNOWN,
.kbc_p1 = 0,
.gpio = 0,
.device = NULL,
.vid_device = NULL
},
{
.name = "[Intel i815EP] Tyan Tomcat i815T",
.internal_name = "s2080",
.type = MACHINE_TYPE_ICH2,
.chipset = MACHINE_CHIPSET_INTEL_I815EP,
.init = machine_at_s2080_init,
.pad = 0,
.pad0 = 0,
.pad1 = MACHINE_AVAILABLE,
.pad2 = 0,
.cpu = {
.package = CPU_PKG_SOCKET370,
.block = CPU_BLOCK_NONE,
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0,
},
.bus_flags = MACHINE_PS2_AGP,
.flags = MACHINE_IDE_DUAL,
.ram = {
.min = 32768,
.max = 524288,
.step = 32768
},
.nvrmask = 255,
.kbc = KBC_UNKNOWN,
.kbc_p1 = 0,
.gpio = 0,
.device = NULL,
.vid_device = NULL
},
{
.name = NULL,
.internal_name = NULL,
@@ -10967,6 +11071,41 @@ const machine_t machines[] = {
}
};
/* Saved copies - jumpers get applied to these.
We use also machine_gpio to store IBM PC/XT jumpers as they need more than one byte. */
static uint16_t machine_p1;
static uint32_t machine_gpio;
uint8_t
machine_get_p1(void)
{
return machine_p1;
}
void
machine_load_p1(int m)
{
machine_p1 = machines[machine].kbc_p1;
}
uint32_t
machine_get_gpio(void)
{
return machine_gpio;
}
void
machine_load_gpio(int m)
{
machine_gpio = machines[machine].gpio;
}
void
machine_set_gpio(uint32_t gpio)
{
machine_gpio = gpio;
}
int
machine_count(void)
{

View File

@@ -190,6 +190,7 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
uint16_t min_module_size, rows[SPD_MAX_SLOTS], asym;
spd_edo_t *edo_data;
spd_sdram_t *sdram_data;
spd_ddr_t *ddr_data;
/* Determine the minimum module size for this RAM type. */
switch (ram_type) {
@@ -202,6 +203,10 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
min_module_size = SPD_MIN_SIZE_SDRAM;
break;
case SPD_TYPE_DDR:
min_module_size = SPD_MIN_SIZE_DDR;
break;
default:
spd_log("SPD: unknown RAM type %02X\n", ram_type);
return;
@@ -335,6 +340,60 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
for (i = 0; i < 129; i++)
sdram_data->checksum2 += spd_modules[slot]->data[i];
break;
case SPD_TYPE_DDR:
ddr_data = &spd_modules[slot]->ddr_data;
ddr_data->bytes_used = 0x80;
ddr_data->spd_size = 0x08;
ddr_data->mem_type = ram_type;
ddr_data->row_bits = SPD_ROLLUP(6 + log2i(spd_modules[slot]->row1)); /* first row */
ddr_data->col_bits = 9;
if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
ddr_data->row_bits |= SPD_ROLLUP(6 + log2i(spd_modules[slot]->row2)) << 4; /* second row, if different from first */
ddr_data->col_bits |= 9 << 4; /* same as first row, but just in case */
}
ddr_data->rows = 2;
ddr_data->data_width_lsb = 64;
ddr_data->signal_level = SPD_SIGNAL_LVTTL;
ddr_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */
ddr_data->tac = 0x10;
ddr_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL;
ddr_data->sdram_width = 8;
ddr_data->tccd = 1;
ddr_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8;
ddr_data->banks = 4;
ddr_data->cas = 0x7f; /* CAS Latency */
ddr_data->cslat = ddr_data->we = 0x7f;
ddr_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST;
ddr_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */
ddr_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */
ddr_data->tac2 = ddr_data->tac3 = 0x10;
ddr_data->trp = ddr_data->trrd = ddr_data->trcd = ddr_data->tras = 1;
if (spd_modules[slot]->row1 != spd_modules[slot]->row2) {
/* Utilities interpret bank_density a bit differently on asymmetric modules. */
ddr_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 2); /* first row */
ddr_data->bank_density |= 1 << (log2i(spd_modules[slot]->row2 >> 1) - 2); /* second row */
} else {
ddr_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */
}
ddr_data->ca_setup = ddr_data->data_setup = 0x15;
ddr_data->ca_hold = ddr_data->data_hold = 0x08;
ddr_data->spd_rev = 0x10;
for (i = spd_write_part_no(ddr_data->part_no, "DDR", rows[row]);
i < sizeof(ddr_data->part_no); i++)
ddr_data->part_no[i] = ' '; /* part number should be space-padded */
ddr_data->rev_code[0] = BCD8(EMU_VERSION_MAJ);
ddr_data->rev_code[1] = BCD8(EMU_VERSION_MIN);
ddr_data->mfg_year = 20;
ddr_data->mfg_week = 13;
for (i = 0; i < 63; i++)
ddr_data->checksum += spd_modules[slot]->data[i];
for (i = 0; i < 129; i++)
ddr_data->checksum2 += spd_modules[slot]->data[i];
break;
}
row++;
@@ -518,7 +577,7 @@ spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max)
}
/* Write DRBs for each row. */
spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit);
// spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit);
for (dimm = 0; dimm <= ((reg_max - reg_min) >> 2); dimm++) {
size = 0;
drb = reg_min + (dimm << 2);
@@ -577,6 +636,84 @@ spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max)
}
void
spd_write_drbs_intel_815ep(uint8_t *regs)
{
/* All Intel MCH based boards demand SPD so we ignore completely the non-SPD calculations */
int size;
int reg_apply;
uint16_t rows[SPD_MAX_SLOTS];
if(!spd_present)
spd_populate(rows, 3, mem_size << 10, 32, 512, 0);
/* Clear previous configurations */
regs[0x52] = regs[0x54] = 0;
/* Write DRBs for each row. */
for (int slot = 0; slot < 3; slot++) {
size = spd_modules[slot]->row1 + spd_modules[slot]->row2;
spd_log("Intel 815EP SPD: Registering Slot %d with size %dMB.\n", slot, size);
/* Calculate Size. Nullify if the size is illegal. */
switch(size)
{
default:
reg_apply = 0;
spd_log("Intel 815EP SPD: Illegal Size on Slot %d. Size not divisible by 32.\n", slot);
break;
case 32:
reg_apply = 1;
break;
case 48:
reg_apply = 3;
break;
case 64:
reg_apply = 4;
break;
case 96:
reg_apply = 6;
break;
case 128:
reg_apply = 7;
break;
case 192:
reg_apply = 11;
break;
case 256:
reg_apply = 12;
break;
case 512:
reg_apply = 15;
break;
}
/* Write on the representative register */
switch(slot)
{
case 0:
regs[0x52] |= reg_apply;
break;
case 1:
regs[0x52] |= reg_apply << 4;
break;
case 2:
regs[0x54] |= reg_apply;
break;
}
}
}
static const device_t spd_device = {
.name = "Serial Presence Detect ROMs",
.internal_name = "spd",

View File

@@ -80,6 +80,9 @@ static char flash_path[1024];
#define SST39SF020 0xb600
#define SST39SF040 0xb700
#define SST49LF002 0x5700
#define SST49LF004 0x6000
#define WINBOND 0xda /* Winbond Manufacturer's ID */
#define W29C020 0x4500
@@ -564,3 +567,39 @@ const device_t sst_flash_39sf040_device = {
.force_redraw = NULL,
.config = NULL
};
/*
* Firmware Hubs. The FWH signals are not implemented yet. Firmware Hubs do write cycles
* to read/write on the flash. SST Flashes still do traditional flashing via PP Mode. Our
* BIOS firmwares don't seem to utilize FWH R/W thus the FWH ports remain unknown for an
* implementation. We just contain the ID's so the BIOS can do ESCD & DMI writes with no
* worries.
*/
const device_t sst_flash_49lf002_device = {
.name = "SST 49LF002 Firmware Hub",
.internal_name = "sst_flash_49lf002",
.flags = 0,
.local = SST | SST49LF002 | SIZE_2M,
.init = sst_init,
.close = sst_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sst_flash_49lf004_device = {
.name = "SST 49LF004 Firmware Hub",
.internal_name = "sst_flash_49lf004",
.flags = 0,
.local = SST | SST49LF004 | SIZE_4M,
.init = sst_init,
.close = sst_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -540,6 +540,11 @@ pic_set_pci(void)
io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
}
for (i = 0xff20; i < 0xff40; i += 4) {
io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
}
}

View File

@@ -15,10 +15,11 @@
add_library(sio OBJECT sio_acc3221.c sio_ali5123.c sio_f82c710.c sio_82091aa.c
sio_fdc37c6xx.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c
sio_nsc366.c
sio_it8661f.c
sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c
sio_prime3b.c sio_prime3c.c
sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c
sio_w83627hf.c sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c
sio_vt82c686.c)
if(SIO_DETECT)

530
src/sio/sio_nsc366.c Normal file
View File

@@ -0,0 +1,530 @@
/*
* 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.
*
* Emulation of the National Semiconductor PC87366 (NSC366)
* Super I/O chip.
*
* Author: Tiseno100,
* Copyright 2022 Tiseno100.
*/
#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/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/hwm.h>
#include <86box/keyboard.h>
#include <86box/lpt.h>
#include <86box/nsc366.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/fdd_common.h>
#include <86box/port_92.h>
#include <86box/sio.h>
typedef struct
{
fdc_t *fdc;
serial_t *uart[2];
nsc366_hwm_t *hwm;
uint8_t index, ldn, sio_config[14],
ld_activate[15],
io_base0[2][15],
io_base1[2][15],
int_num_irq[15],
irq[15],
dma_select0[15],
dma_select1[15],
dev_specific_config[3][15];
int siofc_lock;
} nsc366_t;
#ifdef ENABLE_NSC366_LOG
int nsc366_do_log = ENABLE_NSC366_LOG;
void
nsc366_log(const char *fmt, ...)
{
va_list ap;
if (nsc366_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define nsc366_log(fmt, ...)
#endif
static void
nsc366_fdc(nsc366_t *dev)
{
fdc_remove(dev->fdc);
int base = ((dev->io_base0[0][0] & 7) << 8) | (dev->io_base0[1][0] & 0xf8);
int irq = dev->int_num_irq[0] & 0x0f;
int dma_ch = dev->dma_select0[0] & 7;
if (dev->ld_activate[0]) {
nsc366_log("NSC 366 FDC: Reconfigured with Base: 0x%04x IRQ: %d DMA Channel: %d\n", base, irq, dma_ch);
fdc_set_base(dev->fdc, base);
fdc_set_irq(dev->fdc, irq);
fdc_set_dma_ch(dev->fdc, dma_ch);
fdc_update_densel_polarity(dev->fdc, !!(dev->dev_specific_config[0][0] & 0x20));
if (dev->dev_specific_config[0][0] & 8)
fdc_writeprotect(dev->fdc);
}
}
void
nsc366_lpt(nsc366_t *dev)
{
lpt1_remove();
int base = ((dev->io_base0[0][1] & 7) << 8) | (dev->io_base0[1][1] & 0xfc);
int irq = (dev->int_num_irq[1] & 0x0f);
if (dev->ld_activate[1]) {
nsc366_log("NSC 366 LPT: Reconfigured with Base 0x%04x IRQ: %d\n", base ,irq);
lpt1_init(base);
lpt1_irq(irq);
}
}
static void
nsc366_uart(int uart, nsc366_t *dev)
{
serial_remove(dev->uart[uart]);
int base = ((dev->io_base0[0][2 + uart] & 7) << 8) | (dev->io_base0[1][2 + uart] & 0xf8);
int irq = (dev->int_num_irq[2 + uart] & 0x0f);
if (dev->ld_activate[2 + uart]) {
nsc366_log("NSC 366 UART Serial %d: Reconfigured with Base 0x%04x IRQ: %d\n", uart, base ,irq);
serial_setup(dev->uart[uart], base, irq);
}
}
static void
nsc366_fscm(nsc366_t *dev)
{
uint16_t base = (dev->io_base0[0][9] << 8) | (dev->io_base0[1][9] & 0xf0);
if (dev->ld_activate[9])
nsc366_log("NSC 366 Fan Control: Reconfigured with Base 0x%04x\n", base);
nsc366_update_fscm_io(dev->ld_activate[9], base, dev->hwm);
}
static void
nsc366_vlm(nsc366_t *dev)
{
uint16_t base = (dev->io_base0[0][13] << 8) | (dev->io_base0[1][13] & 0xf0);
if (dev->ld_activate[13])
nsc366_log("NSC 366 Voltage Monitor: Reconfigured with Base 0x%04x\n", base);
nsc366_update_vlm_io(dev->ld_activate[13], base, dev->hwm);
}
static void
nsc366_tms(nsc366_t *dev)
{
uint16_t base = (dev->io_base0[0][14] << 8) | (dev->io_base0[1][14] & 0xf0);
if (dev->ld_activate[14])
nsc366_log("NSC 366 Temperature Monitor: Reconfigured with Base 0x%04x\n", base);
nsc366_update_tms_io(dev->ld_activate[14], base, dev->hwm);
}
static void
nsc366_ldn_redirect(nsc366_t *dev)
{
switch(dev->ldn) {
case 0:
nsc366_fdc(dev);
break;
case 1:
nsc366_lpt(dev);
break;
case 2 ... 3:
nsc366_uart(dev->ldn == 3, dev);
break;
case 9:
nsc366_fscm(dev);
break;
case 13:
nsc366_vlm(dev);
break;
case 14:
nsc366_tms(dev);
break;
}
}
static void
nsc366_write(uint16_t addr, uint8_t val, void *priv)
{
nsc366_t *dev = (nsc366_t *)priv;
if (addr & 1) switch(dev->index) {
/* LDN */
case 0x07:
if (val <= 0x0e)
dev->ldn = val;
break;
/* Super I/O Configuration */
case 0x21:
if (!dev->siofc_lock) {
if (val & 0x80) {
dev->sio_config[dev->index - 0x20] = val | 0x80;
dev->siofc_lock = 1;
} else
dev->sio_config[dev->index - 0x20] = val;
}
break;
case 0x22:
if (!dev->siofc_lock)
dev->sio_config[dev->index - 0x20] = val;
break;
case 0x23:
if (!dev->siofc_lock)
dev->sio_config[dev->index - 0x20] = val & 0xf7;
break;
case 0x24:
if (!dev->siofc_lock)
dev->sio_config[dev->index - 0x20] = val;
break;
case 0x25:
if (!dev->siofc_lock)
dev->sio_config[dev->index - 0x20] = val & 0xf3;
break;
case 0x28:
dev->sio_config[dev->index - 0x20] = val & 0xf3;
break;
case 0x2a:
if (!dev->siofc_lock)
dev->sio_config[dev->index - 0x20] = val;
break;
case 0x2b:
if (!dev->siofc_lock)
/* Force Case Intrusion to always off */
dev->sio_config[dev->index - 0x20] = val & 0x4f;
break;
case 0x2c ... 0x2d:
dev->sio_config[dev->index - 0x20] = val & 0xf3;
break;
/* Logical Devices */
case 0x30:
dev->ld_activate[dev->ldn] = (val & 1) && (dev->sio_config[0] & 1);
nsc366_ldn_redirect(dev);
break;
case 0x60 ... 0x61:
dev->io_base0[dev->index & 1][dev->ldn] = val;
nsc366_ldn_redirect(dev);
break;
case 0x62 ... 0x63:
dev->io_base1[dev->index & 1][dev->ldn] = val;
nsc366_ldn_redirect(dev);
break;
case 0x70:
dev->int_num_irq[dev->ldn] = val & 0x1f;
nsc366_ldn_redirect(dev);
break;
case 0x71:
dev->irq[dev->ldn] = val;
nsc366_ldn_redirect(dev);
break;
case 0x74:
dev->dma_select0[dev->ldn] = val & 0x1f;
nsc366_ldn_redirect(dev);
break;
case 0x75:
dev->dma_select1[dev->ldn] = val & 0x1f;
nsc366_ldn_redirect(dev);
break;
case 0xf0 ... 0xf2:
dev->dev_specific_config[dev->index - 0xf0][dev->ldn] = val;
nsc366_ldn_redirect(dev);
break;
} else
dev->index = val;
}
static uint8_t
nsc366_read(uint16_t addr, void *priv)
{
nsc366_t *dev = (nsc366_t *)priv;
uint8_t ret = 0x00;
if (addr & 1) {
switch (dev->index) {
case 0x07:
ret = dev->ldn;
break;
case 0x20 ... 0x2d:
ret = dev->sio_config[dev->index - 0x20];
break;
case 0x30:
ret = dev->ld_activate[dev->ldn];
break;
case 0x60 ... 0x61:
ret = dev->io_base0[dev->index & 1][dev->ldn];
break;
case 0x62 ... 0x63:
ret = dev->io_base1[dev->index & 1][dev->ldn];
break;
case 0x70:
ret = dev->int_num_irq[dev->ldn];
break;
case 0x71:
ret = dev->irq[dev->ldn];
break;
case 0x74:
ret = dev->dma_select0[dev->ldn];
break;
case 0x75:
ret = dev->dma_select1[dev->ldn];
break;
case 0xf0 ... 0xf2:
ret = dev->dev_specific_config[dev->index - 0xf0][dev->ldn];
break;
}
} else
ret = dev->index;
return ret;
}
static void
nsc366_reset(void *priv)
{
nsc366_t *dev = (nsc366_t *)priv;
/* Basic Configuration */
dev->ldn = 0;
dev->siofc_lock = 0;
memset(dev->sio_config, 0, sizeof(dev->sio_config));
memset(dev->ld_activate, 0, sizeof(dev->ld_activate));
memset(dev->io_base0, 0, sizeof(dev->io_base0));
memset(dev->io_base1, 0, sizeof(dev->io_base1));
memset(dev->int_num_irq, 0, sizeof(dev->int_num_irq));
memset(dev->irq, 0, sizeof(dev->irq));
memset(dev->dma_select0, 0, sizeof(dev->dma_select0));
memset(dev->dma_select1, 0, sizeof(dev->dma_select1));
memset(dev->dev_specific_config, 0, sizeof(dev->dev_specific_config));
/* SIO Config */
dev->sio_config[0x00] = 0xe9; /* National Semiconductor NSC366 */
dev->sio_config[0x07] = 0x01;
/* FDC */
fdc_reset(dev->fdc);
dev->io_base0[0][0] = 0x03;
dev->io_base0[1][0] = 0xf2;
dev->int_num_irq[0] = 0x06;
dev->irq[0] = 0x03;
dev->dma_select0[0] = 0x02;
dev->dma_select1[0] = 0x04;
dev->dev_specific_config[0][0] = 0x24;
nsc366_fdc(dev);
/* LPT */
dev->io_base0[0][1] = 0x02;
dev->io_base0[1][1] = 0x78;
dev->int_num_irq[1] = 0x07;
dev->irq[1] = 0x02;
dev->dma_select0[1] = 0x04;
dev->dma_select1[1] = 0x04;
dev->dev_specific_config[0][1] = 0xf2;
/* UART Serial 2 */
dev->io_base0[0][2] = 0x02;
dev->io_base0[1][2] = 0xf8;
dev->int_num_irq[2] = 0x03;
dev->irq[2] = 0x03;
dev->dma_select0[2] = 0x04;
dev->dma_select1[2] = 0x04;
dev->dev_specific_config[0][2] = 0x02;
nsc366_uart(1, dev);
/* UART Serial 1 */
dev->io_base0[0][3] = 0x03;
dev->io_base0[1][3] = 0xf8;
dev->int_num_irq[3] = 0x04;
dev->irq[3] = 0x03;
dev->dma_select0[3] = 0x04;
dev->dma_select1[3] = 0x04;
dev->dev_specific_config[0][3] = 0x02;
/* SWC */
dev->irq[4] = 0x03;
dev->dma_select0[4] = 0x04;
/* Keyboard Controller */
dev->int_num_irq[5] = 0x0c;
dev->irq[5] = 0x02;
/* Mouse Controller */
dev->io_base0[1][6] = 0x60;
dev->io_base1[1][6] = 0x64;
dev->int_num_irq[6] = 0x01;
dev->irq[6] = 0x02;
dev->dma_select0[6] = 0x04;
dev->dma_select1[6] = 0x04;
dev->dev_specific_config[0][6] = 0x40;
/* GPIO */
dev->irq[7] = 0x03;
dev->dma_select0[7] = 0x04;
dev->dma_select1[7] = 0x04;
/* ACB */
dev->irq[8] = 0x03;
dev->dma_select0[8] = 0x04;
dev->dma_select1[8] = 0x04;
/* Fan Speed Monitor & Control */
dev->irq[9] = 0x03;
dev->dma_select0[9] = 0x04;
dev->dma_select1[9] = 0x04;
nsc366_fscm(dev);
/* Voltage Level Monitor */
dev->irq[13] = 0x03;
dev->dma_select0[13] = 0x04;
dev->dma_select1[13] = 0x04;
nsc366_vlm(dev);
/* Temperature Monitor */
dev->irq[14] = 0x03;
dev->dma_select0[14] = 0x04;
dev->dma_select1[14] = 0x04;
nsc366_tms(dev);
}
static void
nsc366_close(void *priv)
{
nsc366_t *dev = (nsc366_t *)priv;
free(dev);
}
static void *
nsc366_init(const device_t *info)
{
nsc366_t *dev = (nsc366_t *)malloc(sizeof(nsc366_t));
memset(dev, 0, sizeof(nsc366_t));
io_sethandler(info->local, 2, nsc366_read, NULL, NULL, nsc366_write, NULL, NULL, dev); /* Ports 2E-2Fh(4E-4Fh if BADDR High): National Semiconductor NSC366 */
/* FDC */
dev->fdc = device_add(&fdc_at_nsc_device);
/* Hardware Monitor Setup */
dev->hwm = device_add(&nsc366_hwm_device);
/* Keyboard Controller */
device_add(&keyboard_ps2_ami_pci_device);
/* Port 92h */
device_add(&port_92_pci_device);
/* Serial */
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
nsc366_reset(dev);
return dev;
}
const device_t nsc366_device = {
.name = "National Semiconductor NSC366",
.internal_name = "nsc366",
.flags = 0,
.local = 0x2e,
.init = nsc366_init,
.close = nsc366_close,
.reset = nsc366_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t nsc366_4f_device = {
.name = "National Semiconductor NSC366 (With BADDR Pin High)",
.internal_name = "nsc366",
.flags = 0,
.local = 0x4e,
.init = nsc366_init,
.close = nsc366_close,
.reset = nsc366_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

962
src/sio/sio_w83627hf.c Normal file
View File

@@ -0,0 +1,962 @@
/*
* 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 Winbond W83627HF chipset.
*
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020,2021 Tiseno100.
* Copyright 2021,2021 Miran Grca.
*/
/*
Winbond W83627HF Register Summary for ISAPnP (potentially)
Found on: https://github.com/koitsu/bsdhwmon/issues/6
Register dump:
idx 02 20 21 22 23 24 25 26 28 29 2a 2b 2c 2e 2f
val ff 52 41 ff fe c4 00 00 00 50 fc 00 ff 00 ff
def 00 52 NA ff 00 MM 00 00 00 00 7c c0 00 00 00
LDN 0x00 (Floppy)
idx 30 60 61 70 74 f0 f1 f2 f4 f5
val 00 00 00 06 02 0e 00 ff 00 00
def 01 03 f0 06 02 0e 00 ff 00 00
LDN 0x01 (Parallel port)
idx 30 60 61 70 74 f0
val 00 00 00 07 03 3f
def 01 03 78 07 04 3f
LDN 0x02 (COM1)
idx 30 60 61 70 f0
val 01 03 f8 04 00
def 01 03 f8 04 00
LDN 0x03 (COM2)
idx 30 60 61 70 f0 f1
val 01 02 f8 03 00 40
def 01 02 f8 03 00 00
LDN 0x05 (Keyboard)
idx 30 60 61 62 63 70 72 f0
val 01 00 60 00 64 01 00 80
def 01 00 60 00 64 01 0c 80
LDN 0x06 (Consumer IR)
idx 30 60 61 70
val 00 00 00 00
def 00 00 00 00
LDN 0x07 (Game port, MIDI port, GPIO 1)
idx 30 60 61 62 63 70 f0 f1 f2
val 01 00 00 00 00 00 ff ff 00
def 00 02 01 03 30 09 ff 00 00
LDN 0x08 (GPIO 2, watchdog timer)
idx 30 f0 f1 f2 f3 f5 f6 f6 f7
val 00 ff ff ff 00 08 00 00 c0
def 00 ff 00 00 00 00 00 00 00
LDN 0x09 (GPIO 3)
idx 30 f0 f1 f2 f3
val 01 ff 14 00 40
def 00 ff 00 00 00
LDN 0x0a (ACPI)
idx 30 70 e0 e1 e2 e3 e4 e5 e6 e7 f0 f1 f3 f4 f6 f7 f9 fe ff
val 01 00 00 00 f2 00 40 00 00 00 00 af 32 00 00 00 00 00 00
def 00 00 00 00 NA NA 00 00 00 00 00 00 00 00 00 00 00 00 00
LDN 0x0b (Hardware monitor)
idx 30 60 61 70 f0
val 01 02 95 00 01
def 00 00 00 00 00
Hardware monitor (0x029a)
*/
/*
Notes : ISAPnP is missing and the Hardware Monitor I2C is not implemented.
*/
#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/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/i2c.h>
#include <86box/keyboard.h>
#include <86box/lpt.h>
#include <86box/port_92.h>
#include <86box/serial.h>
#include <86box/hwm.h>
#include <86box/sio.h>
#ifdef ENABLE_W83627HF_LOG
int w83627hf_do_log = ENABLE_W83627HF_LOG;
static void
w83627hf_log(const char *fmt, ...)
{
va_list ap;
if (w83627hf_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define w83627hf_log(fmt, ...)
#endif
typedef struct
{
uint8_t hwm_index, hwm_regs[256];
uint8_t index, cfg_unlocked,
regs[48], dev_regs[12][256];
int has_hwm;
fdc_t *fdc_controller;
port_92_t *port_92;
serial_t *uart[2];
} w83627hf_t;
/* These differ per board and must be programmed manually */
int fan1_rpm, fan2_rpm, fan3_rpm, vcorea_voltage, vcoreb_voltage;
void
w83627hf_stabilizer(int vcoreb, int fan1, int fan2, int fan3)
{
vcoreb_voltage = vcoreb;
fan1_rpm = fan1;
fan2_rpm = fan2;
fan3_rpm = fan3;
}
static void
w83627hf_hwm_write(uint16_t addr, uint8_t val, void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
switch(addr)
{
case 0x295:
dev->hwm_index = val;
break;
case 0x296:
w83627hf_log("W83627HF-HWM: dev->regs[%02x] = %02x\n", dev->hwm_index, val);
switch(dev->hwm_index)
{
case 0x2b ... 0x3f:
case 0x6b ... 0x7f:
dev->hwm_regs[dev->hwm_index & 0x1f] = val;
break;
case 0x40:
dev->hwm_regs[dev->hwm_index] = val & 0x8b;
break;
case 0x43:
dev->hwm_regs[dev->hwm_index] = val;
break;
case 0x44:
dev->hwm_regs[dev->hwm_index] = val & 0x3f;
break;
case 0x46:
dev->hwm_regs[dev->hwm_index] = val & 0x80;
if(val & 0x80)
dev->hwm_regs[dev->hwm_index] &= 0x10;
break;
case 0x47:
dev->hwm_regs[dev->hwm_index] = val & 0x3f;
break;
case 0x48: /* Serial Bus Address */
dev->hwm_regs[dev->hwm_index] = val & 0x7f;
break;
case 0x49:
dev->hwm_regs[dev->hwm_index] = val & 1;
break;
case 0x4a:
dev->hwm_regs[dev->hwm_index] = val;
break;
case 0x4b:
dev->hwm_regs[dev->hwm_index] = val & 0xfc;
break;
case 0x4c:
dev->hwm_regs[dev->hwm_index] = val & 0x5c;
break;
case 0x4d:
dev->hwm_regs[dev->hwm_index] = val & 0xbf;
break;
case 0x4e:
dev->hwm_regs[dev->hwm_index] = val;
break;
case 0x56:
dev->hwm_regs[dev->hwm_index] = val;
break;
case 0x57:
dev->hwm_regs[dev->hwm_index] = val & 0xbf;
break;
case 0x59:
dev->hwm_regs[dev->hwm_index] = val & 0x70;
break;
case 0x5a ... 0x5b:
dev->hwm_regs[dev->hwm_index] = val;
break;
case 0x5c:
dev->hwm_regs[dev->hwm_index] = val & 0x77;
break;
}
break;
}
}
static uint8_t
w83627hf_hwm_read(uint16_t addr, void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
switch(addr)
{
case 0x295:
return dev->hwm_index;
case 0x296:
switch(dev->hwm_index)
{
case 0x20 ... 0x3f:
case 0x60 ... 0x7f:
switch(dev->hwm_index & 0x1f)
{
case 0x00: /* VCOREA */
return hwm_get_vcore() + 0x78;
case 0x01: /* VCOREB */
return vcoreb_voltage;
case 0x02: /* +3.3V */
return 0xd0;
case 0x03: /* +5V */
return 0xb9;
case 0x04: /* +12V */
return 0xc4;
case 0x05: /* -12V */
return 0x23;
case 0x06: /* -5V */
return 0x34;
case 0x08: /* Fan 1 */
return fan1_rpm;
case 0x09: /* Fan 2 */
return fan2_rpm;
case 0x0a: /* Fan 3 */
return fan3_rpm;
case 0x0b ... 0x1f:
return dev->hwm_regs[dev->hwm_index & 0x1f];
}
case 0x4f:
if(dev->hwm_regs[0x4e] & 0x80)
return 0x5c;
else
return 0xa3;
case 0x40 ... 0x4e:
case 0x50 ... 0x5c:
return dev->hwm_regs[dev->hwm_index];
default:
return 0xff;
}
default:
return 0xff;
}
}
static void
w83627hf_fdc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
fdc_remove(dev->fdc_controller);
switch(cur_reg)
{
case 0x30:
dev->dev_regs[0][cur_reg] = val & 1;
break;
case 0x60 ... 0x61:
dev->dev_regs[0][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[0][cur_reg] = val & 0x0f;
break;
case 0x74:
dev->dev_regs[0][cur_reg] = val & 7;
break;
case 0xf0:
dev->dev_regs[0][cur_reg] = val;
break;
case 0xf1:
dev->dev_regs[0][cur_reg] = val;
fdc_update_boot_drive(dev->fdc_controller, (val & 0xc0) >> 6);
if(val & 2)
fdc_writeprotect(dev->fdc_controller);
fdc_set_swwp(dev->fdc_controller, val & 1);
break;
case 0xf2:
dev->dev_regs[0][cur_reg] = val;
break;
case 0xf4:
case 0xf5:
dev->dev_regs[0][cur_reg] = val & 0x5b;
fdc_update_drvrate(dev->fdc_controller, cur_reg & 1, (val & 0x18) >> 3);
break;
}
if(dev->dev_regs[0][0x30] & 1)
{
fdc_set_irq(dev->fdc_controller, dev->dev_regs[0][0x70]);
fdc_set_dma_ch(dev->fdc_controller, dev->dev_regs[0][0x74]);
fdc_set_base(dev->fdc_controller, (dev->dev_regs[0][0x60] << 8) | (dev->dev_regs[0][0x61]));
w83627hf_log("W83627HF-FDC: BASE: %04x IRQ: %d DMA: %d\n", (dev->dev_regs[0][0x60] << 8) | (dev->dev_regs[0][0x61]), dev->dev_regs[0][0x70], dev->dev_regs[0][0x74]);
}
}
static void
w83627hf_lpt_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
lpt1_remove();
switch(cur_reg)
{
case 0x30:
dev->dev_regs[1][cur_reg] = val & 1;
break;
case 0x60 ... 0x61:
dev->dev_regs[1][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[1][cur_reg] = val & 0x0f;
break;
case 0xf0:
dev->dev_regs[1][cur_reg] = val & 0x7f;
break;
}
if(dev->dev_regs[1][0x30] & 1)
{
lpt1_init((dev->dev_regs[1][0x60] << 8) | (dev->dev_regs[1][0x61]));
lpt1_irq(dev->dev_regs[1][0x70]);
w83627hf_log("W83627HF-LPT: BASE: %04x IRQ: %d\n", (dev->dev_regs[1][0x60] << 8) | (dev->dev_regs[1][0x61]), dev->dev_regs[1][0x70]);
}
}
static void
w83627hf_uart_write(int uart, uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
double uart_clock = 24000000.0 / 13.0;
serial_remove(dev->uart[uart]);
switch(cur_reg)
{
case 0x30:
dev->dev_regs[2 + uart][cur_reg] = val & 1;
break;
case 0x60 ... 0x61:
dev->dev_regs[2 + uart][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[2 + uart][cur_reg] = val & 0x0f;
break;
case 0xf0:
dev->dev_regs[2 + uart][cur_reg] = val & 3;
switch(val & 3)
{
case 0:
uart_clock = 24000000.0 / 13.0;
break;
case 1:
uart_clock = 24000000.0 / 12.0;
break;
case 2:
uart_clock = 24000000.0 / 1.625;
break;
case 3:
uart_clock = 24000000.0;
break;
}
break;
case 0xf1:
if(uart)
dev->dev_regs[2 + uart][cur_reg] = val & 0x7f;
break;
}
if(dev->dev_regs[2 + uart][0x30] & 1)
{
serial_setup(dev->uart[uart], (dev->dev_regs[2 + uart][0x60] << 8) | (dev->dev_regs[2 + uart][0x61]), dev->dev_regs[2 + uart][0x70]);
serial_set_clock_src(dev->uart[uart], uart_clock);
w83627hf_log("W83627HF-UART%s: BASE: %04x IRQ: %d\n", uart ? "B" : "A", (dev->dev_regs[2 + uart][0x60] << 8) | (dev->dev_regs[2 + uart][0x61]), dev->dev_regs[2 + uart][0x70]);
}
}
static void
w83627hf_kbc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[5][cur_reg] = val & 1;
break;
case 0x60 ... 0x61: /* See Notes on init */
dev->dev_regs[5][cur_reg] = val;
break;
case 0x62 ... 0x63: /* See Notes on init */
dev->dev_regs[5][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[5][cur_reg] = val & 0x0f;
break;
case 0x72:
dev->dev_regs[5][cur_reg] = val & 0x0f;
break;
case 0xf0:
dev->dev_regs[5][cur_reg] = val & 0xc7;
break;
}
if(dev->dev_regs[5][0x30] & 1)
{
/* We don't disable Port 92h as intended because the BIOSes never enable it back, causing issues. */
port_92_set_features(dev->port_92, !!(dev->dev_regs[5][0xf0] & 1), !!(dev->dev_regs[5][0xf0] & 2));
w83627hf_log("W83627HF-PORT92: FASTA20: %d FASTRESET: %d\n", !!(dev->dev_regs[5][0xf0] & 2), !!(dev->dev_regs[5][0xf0] & 1));
}
}
static void
w83627hf_cir_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
/* Unimplemented Functionality */
switch(cur_reg)
{
case 0x30:
dev->dev_regs[6][cur_reg] = val & 1;
break;
case 0x60 ... 0x61:
dev->dev_regs[6][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[6][cur_reg] = val & 0x0f;
break;
}
}
static void
w83627hf_gameport_midi_gpio1_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[7][cur_reg] = val & 7;
break;
case 0x60 ... 0x63:
dev->dev_regs[7][cur_reg] = val;
break;
case 0x70:
dev->dev_regs[7][cur_reg] = val & 0x0f;
break;
case 0xf0 ... 0xf2:
dev->dev_regs[7][cur_reg] = val;
break;
}
}
static void
w83627hf_watchdog_timer_gpio2_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[8][cur_reg] = val & 1;
break;
case 0xf0 ... 0xf2:
dev->dev_regs[8][cur_reg] = val;
break;
case 0xf5:
dev->dev_regs[8][cur_reg] = val & 0xcc;
break;
case 0xf6 ... 0xf7:
dev->dev_regs[8][cur_reg] = val;
break;
}
}
static void
w83627hf_gpio3_vsb_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[9][cur_reg] = val & 1;
break;
case 0xf0 ... 0xf2:
dev->dev_regs[9][cur_reg] = val;
break;
case 0xf3:
dev->dev_regs[9][cur_reg] = val & 0xc0;
break;
}
}
static void
w83627hf_acpi_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[0x0a][cur_reg] = val & 1;
break;
case 0x70:
dev->dev_regs[0x0a][cur_reg] = val & 0x0f;
break;
case 0xe0:
dev->dev_regs[0x0a][cur_reg] = val & 0xc0;
break;
case 0xe1 ... 0xe2:
dev->dev_regs[0x0a][cur_reg] = val;
break;
case 0xe4:
dev->dev_regs[0x0a][cur_reg] = val & 0xfc;
break;
case 0xe5 ... 0xe6:
dev->dev_regs[0x0a][cur_reg] = val & 0x7f;
if(cur_reg == 0xe6)
if(val & 0x40)
dev->hwm_regs[0x42] &= 0x10;
break;
case 0xe7:
dev->dev_regs[0x0a][cur_reg] = val & 0x0f;
break;
case 0xf0:
dev->dev_regs[0x0a][cur_reg] = val;
break;
case 0xf1:
dev->dev_regs[0x0a][cur_reg] = val & 0xef;
break;
case 0xf3 ... 0xf4:
dev->dev_regs[0x0a][cur_reg] &= val & 0x3f;
break;
case 0xf5:
case 0xf7:
dev->dev_regs[0x0a][cur_reg] = val & 0x3f;
break;
}
}
static void
w83627hf_hwm_lpc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev)
{
switch(cur_reg)
{
case 0x30:
dev->dev_regs[0x0b][cur_reg] = val & 1;
break;
case 0x70:
dev->dev_regs[0x0b][cur_reg] = val & 0x0f;
break;
case 0xf0:
dev->dev_regs[0x0b][cur_reg] = val & 1;
break;
}
}
static void
w83627hf_hwm_reset(w83627hf_t *dev)
{
/* W83627HF Hardware Monitor */
dev->hwm_regs[0x40] = 1;
dev->hwm_regs[0x47] = 0xa0;
dev->hwm_regs[0x48] = 0x2d;
dev->hwm_regs[0x49] = 1;
dev->hwm_regs[0x4a] = 1;
dev->hwm_regs[0x4b] = 0x44;
dev->hwm_regs[0x4d] = 0x15;
dev->hwm_regs[0x4e] = 0x80;
dev->hwm_regs[0x57] = 0x80;
dev->hwm_regs[0x58] = 0x21;
dev->hwm_regs[0x59] = 0x70;
dev->hwm_regs[0x5a] = 0xff;
dev->hwm_regs[0x5b] = 0xff;
dev->hwm_regs[0x5c] = 0x11;
}
static void
w83627hf_reset(void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
memset(dev->regs, 0, sizeof(dev->regs));
dev->cfg_unlocked = 0;
/* Proper W83627HF Registers */
dev->regs[0x20] = 0x52;
dev->regs[0x21] = 0x17;
/* FDC Registers */
dev->dev_regs[0][0x30] = 1;
dev->dev_regs[0][0x60] = 3;
dev->dev_regs[0][0x61] = 0xf0;
dev->dev_regs[0][0x70] = 6;
dev->dev_regs[0][0x74] = 2;
dev->dev_regs[0][0xf0] = 0x0e;
dev->dev_regs[0][0xf2] = 0xff;
fdc_reset(dev->fdc_controller);
w83627hf_fdc_write(0, 0, dev);
/* LPT Registers */
dev->dev_regs[1][0x30] = 1;
dev->dev_regs[1][0x60] = 3;
dev->dev_regs[1][0x61] = 0x78;
dev->dev_regs[1][0x70] = 7;
dev->dev_regs[1][0x74] = 4;
dev->dev_regs[1][0xf0] = 0x3f;
w83627hf_lpt_write(0, 0, dev);
/* UART A Registers */
dev->dev_regs[2][0x30] = 1;
dev->dev_regs[2][0x60] = 3;
dev->dev_regs[2][0x61] = 0xf8;
dev->dev_regs[2][0x70] = 4;
w83627hf_uart_write(0, 0, 0, dev);
/* UART B Registers */
dev->dev_regs[3][0x30] = 1;
dev->dev_regs[3][0x60] = 2;
dev->dev_regs[3][0x61] = 0xf8;
dev->dev_regs[3][0x70] = 3;
w83627hf_uart_write(0, 0, 0, dev);
/* Keyboard Controller */
dev->dev_regs[5][0x30] = 1;
dev->dev_regs[5][0x61] = 0x60;
dev->dev_regs[5][0x63] = 0x64;
dev->dev_regs[5][0x70] = 1;
dev->dev_regs[5][0x72] = 0x0c;
dev->dev_regs[5][0xf0] = 0x80;
w83627hf_kbc_write(0, 0, dev);
/* CIR */
dev->dev_regs[6][0x30] = 1;
w83627hf_cir_write(0, 0, dev);
/* Gameport, MIDI port and GPIO1 */
dev->dev_regs[7][0x60] = 2;
dev->dev_regs[7][0x61] = 1;
dev->dev_regs[7][0x62] = 3;
dev->dev_regs[7][0x63] = 0x30;
dev->dev_regs[7][0x70] = 9;
dev->dev_regs[7][0xf0] = 0xff;
/* GPIO3, VSB */
dev->dev_regs[9][0xf0] = 0xff;
/* W83627HF Hardware Monitor */
if(dev->has_hwm)
w83627hf_hwm_reset(dev);
}
static void
w83627hf_write(uint16_t addr, uint8_t val, void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
switch(addr & 0x0f)
{
case 0x0e:
if(!dev->cfg_unlocked)
{
dev->cfg_unlocked = (val == 0x87) && (dev->index == 0x87);
dev->index = val;
}
else dev->index = val;
break;
case 0x0f:
if(dev->cfg_unlocked)
switch(dev->index)
{
case 0x02: /* LDN */
if(val & 1)
w83627hf_reset(dev);
break;
case 0x07:
dev->regs[dev->index] = val;
break;
case 0x22: /* Manual Power Down */
dev->regs[dev->index] = val & 0x7f;
break;
case 0x23: /* Full Power Down */
dev->regs[dev->index] = val & 1;
break;
case 0x24:
dev->regs[dev->index] = val & 0xca;
break;
case 0x25:
dev->regs[dev->index] = val & 0x39;
break;
case 0x26:
dev->regs[dev->index] = val & 0xef;
break;
case 0x28:
dev->regs[dev->index] = val & 7;
break;
case 0x29:
dev->regs[dev->index] = val & 0xfc;
break;
case 0x2a:
case 0x2b:
dev->regs[dev->index] = val;
break;
case 0x30: /* Device Specific Registers */
case 0x60 ... 0x63:
case 0x70: case 0x72:case 0x74:
case 0xe0 ... 0xe7:
case 0xf0 ... 0xf6:
switch(dev->regs[7])
{
case 0: /* FDC */
w83627hf_fdc_write(dev->index, val, dev);
break;
case 1: /* LPT */
w83627hf_lpt_write(dev->index, val, dev);
break;
case 2: /* UART A */
case 3: /* UART B */
w83627hf_uart_write(dev->regs[7] & 1, dev->index, val, dev);
break;
case 5: /* KBC */
w83627hf_kbc_write(dev->index, val, dev);
break;
case 6: /* CIR */
w83627hf_cir_write(dev->index, val, dev);
break;
case 7: /* GAMEPORT, MIDI & GPIO1 */
w83627hf_gameport_midi_gpio1_write(dev->index, val, dev);
break;
case 8: /* WATCHDOG TIMER & GPIO2 */
w83627hf_watchdog_timer_gpio2_write(dev->index, val, dev);
break;
case 9: /* GPIO3 & VSB */
w83627hf_gpio3_vsb_write(dev->index, val, dev);
break;
case 0x0a: /* ACPI */
w83627hf_acpi_write(dev->index, val, dev);
break;
case 0x0b: /* HWM LPC */
w83627hf_hwm_lpc_write(dev->index, val, dev);
break;
default:
w83627hf_log("W83627HF: Writings to unknown LDN: %02x\n", dev->regs[7]);
break;
}
break;
}
break;
}
}
static uint8_t
w83627hf_read(uint16_t addr, void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
if((dev->index >= 0x00) && (dev->index <= 0x2f))
return dev->regs[dev->index];
else if((dev->index >= 0x30) && (dev->index <= 0xff) && (dev->regs[7] >= 0) && (dev->regs[7] <= 0x0b))
return dev->dev_regs[dev->regs[7]][dev->index];
else
return 0xff;
}
static void
w83627hf_close(void *priv)
{
w83627hf_t *dev = (w83627hf_t *)priv;
free(dev);
}
static void *
w83627hf_init(const device_t *info)
{
w83627hf_t *dev = (w83627hf_t *)malloc(sizeof(w83627hf_t));
memset(dev, 0, sizeof(w83627hf_t));
/* Knock out the Hardware Monitor if needed(Mainly for ASUS TUSL2-C) */
dev->has_hwm = info->local;
/* I/O Ports */
io_sethandler(0x002e, 2, w83627hf_read, NULL, NULL, w83627hf_write, NULL, NULL, dev);
io_sethandler(0x004e, 2, w83627hf_read, NULL, NULL, w83627hf_write, NULL, NULL, dev);
if(dev->has_hwm)
io_sethandler(0x0295, 2, w83627hf_hwm_read, NULL, NULL, w83627hf_hwm_write, NULL, NULL, dev);
/* Floppy Disk Controller */
dev->fdc_controller = device_add(&fdc_at_smc_device);
/* Hardware Monitor */
fan1_rpm = fan2_rpm = fan3_rpm = vcorea_voltage = vcoreb_voltage = 0;
/* Keyboard Controller (Based on AMIKEY-2) */
/* Note: The base addresses and IRQ's of the Keyboard & PS/2 Mouse are remappable. Due to 86Box limitations we can't do that just yet */
device_add(&keyboard_ps2_ami_pci_device);
/* Port 92h */
dev->port_92 = device_add(&port_92_device);
/* UART */
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
return dev;
}
const device_t w83627hf_device = {
.name = "Winbond W83627HF",
.internal_name = "w83627hf",
.flags = 0,
.local = 1,
.init = w83627hf_init,
.close = w83627hf_close,
.reset = w83627hf_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83627hf_no_hwm_device = {
.name = "Winbond W83627HF with no Hardware Monitor",
.internal_name = "w83627hf_nohwm",
.flags = 0,
.local = 0,
.init = w83627hf_init,
.close = w83627hf_close,
.reset = w83627hf_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -561,7 +561,8 @@ CHIPSETOBJ := 82c100.o acc2168.o \
wd76c10.o vl82c480.o \
umc_8886.o umc_hb4.o \
via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \
sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o
sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o \
intel_ich2.o intel_815ep.o
MCHOBJ := machine.o machine_table.o \
m_xt.o m_xt_compaq.o \
@@ -579,11 +580,11 @@ MCHOBJ := machine.o machine_table.o \
m_at_286_386sx.o m_at_386dx_486.o \
m_at_socket4.o m_at_socket5.o m_at_socket7_3v.o m_at_socket7.o m_at_sockets7.o \
m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \
m_at_misc.o
m_at_misc.o m_at_ich2.o
ifeq ($(NEW_KBC), y)
DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \
ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \
DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_nsc366.o hwm_vt82c686.o \
ibm_5161.o intel_ich2_gpio.o intel_ich2_trap.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \
clock_ics9xxx.o isapnp.o \
i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \
keyboard.o \
@@ -591,10 +592,11 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hw
mouse.o \
mouse_bus.o \
mouse_serial.o mouse_ps2.o \
phoenix_486_jumper.o
phoenix_486_jumper.o \
tco.o
else
DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \
ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \
DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_nsc366.o hwm_vt82c686.o \
ibm_5161.o intel_ich2_gpio.o intel_ich2_trap.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \
clock_ics9xxx.o isapnp.o \
i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \
keyboard.o \
@@ -602,7 +604,8 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hw
mouse.o \
mouse_bus.o \
mouse_serial.o mouse_ps2.o \
phoenix_486_jumper.o
phoenix_486_jumper.o \
tco.o
endif
SIOOBJ := sio_acc3221.o sio_ali5123.o \
@@ -611,10 +614,11 @@ SIOOBJ := sio_acc3221.o sio_ali5123.o \
sio_it8661f.o \
sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \
sio_prime3b.o sio_prime3c.o \
sio_w83787f.o \
sio_w83627hf.o sio_w83787f.o \
sio_w83877f.o sio_w83977f.o \
sio_um8669f.o \
sio_vt82c686.o
sio_vt82c686.o \
sio_nsc366.o
FDDOBJ := fdd.o fdc.o fdc_magitronic.o fdc_pii15xb.o \
fdi2raw.o \