Current WIP ALi work.

This commit is contained in:
OBattler
2021-07-04 18:16:35 +02:00
parent 4f6df76f10
commit a896953dd5
18 changed files with 2190 additions and 88 deletions

View File

@@ -16,8 +16,8 @@
add_library(dev OBJECT bugger.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
postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c
smbus_piix4.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c
mouse_serial.c mouse_ps2.c phoenix_486_jumper.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)
if(LASERXT)
target_compile_definitions(dev PRIVATE USE_LASERXT)

View File

@@ -33,6 +33,7 @@
#define PCI_BRIDGE_DEC_21150 0x10110022
#define AGP_BRIDGE_ALI_M5243 0x10b95243
#define AGP_BRIDGE_INTEL_440LX 0x80867181
#define AGP_BRIDGE_INTEL_440BX 0x80867191
#define AGP_BRIDGE_INTEL_440GX 0x808671a1
@@ -41,15 +42,16 @@
#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_VIA(x) (((x) >> 16) == 0x1106)
#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_VIA_597)
#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_ALI_M5243)
typedef struct
{
uint32_t local;
uint8_t type;
uint8_t type, ctl;
uint8_t regs[256];
uint8_t bus_index;
@@ -77,6 +79,15 @@ pci_bridge_log(const char *fmt, ...)
#endif
void
pci_bridge_set_ctl(void *priv, uint8_t ctl)
{
pci_bridge_t *dev = (pci_bridge_t *) priv;
dev->ctl = ctl;
}
static void
pci_bridge_write(int func, int addr, uint8_t val, void *priv)
{
@@ -94,21 +105,24 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
case 0x11: case 0x12: case 0x13: case 0x14:
case 0x15: case 0x16: case 0x17: case 0x1e:
case 0x34: case 0x3d: case 0x67: case 0xdc:
case 0xdd: case 0xde: case 0xdf: case 0xe0:
case 0xe1: case 0xe2: case 0xe3:
case 0xdd: case 0xde: case 0xdf:
return;
case 0x04:
if (AGP_BRIDGE_INTEL(dev->local)) {
if (dev->local == AGP_BRIDGE_INTEL_440BX)
val &= 0x1f;
} else
} else if (AGP_BRIDGE_ALI(dev->local))
val |= 0x02;
else
val &= 0x67;
break;
case 0x05:
if (AGP_BRIDGE_INTEL(dev->local))
val &= 0x01;
else if (AGP_BRIDGE_ALI(dev->local))
val &= 0x01;
else
val &= 0x03;
break;
@@ -116,6 +130,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
case 0x07:
if (dev->local == AGP_BRIDGE_INTEL_440LX)
dev->regs[addr] &= ~(val & 0x40);
else if (AGP_BRIDGE_ALI(dev->local))
dev->regs[addr] &= ~(val & 0xf8);
return;
case 0x0c: case 0x18:
@@ -129,6 +145,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
return;
else if (AGP_BRIDGE_INTEL(dev->local))
val &= 0xf8;
else if (AGP_BRIDGE_ALI(dev->local))
val &= 0xf8;
break;
case 0x19:
@@ -144,7 +162,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
else if ((dev->local == AGP_BRIDGE_INTEL_440BX) ||
(dev->local == AGP_BRIDGE_INTEL_440GX))
dev->regs[addr] &= ~(val & 0xf0);
}
} else if (AGP_BRIDGE_ALI(dev->local))
dev->regs[addr] &= ~(val & 0xf0);
return;
case 0x1c: case 0x1d: case 0x20: case 0x22:
@@ -152,6 +171,11 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
val &= 0xf0;
break;
case 0x3c:
if (!(dev->ctl & 0x80))
return;
break;
case 0x3e:
if (AGP_BRIDGE_VIA(dev->local))
val &= 0x0c;
@@ -170,7 +194,9 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
if (dev->local == AGP_BRIDGE_INTEL_440LX) {
dev->regs[addr] = ((dev->regs[addr] & 0x04) | (val & 0x02)) & ~(val & 0x04);
return;
} else if (AGP_BRIDGE(dev->local))
} else if (AGP_BRIDGE_ALI(dev->local))
val &= 0x06;
else if (AGP_BRIDGE(dev->local))
return;
else if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x0f;
@@ -207,6 +233,94 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x3f;
break;
case 0x86:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x3f;
break;
case 0x87:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x60;
break;
case 0x88:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x8c;
break;
case 0x8b:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x0f;
break;
case 0x8c:
if (AGP_BRIDGE_ALI(dev->local))
val &= 0x83;
break;
case 0x8d:
if (AGP_BRIDGE_ALI(dev->local))
return;
break;
case 0xe0: case 0xe1:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
return;
} else
return;
break;
case 0xe2:
if (AGP_BRIDGE_ALI(dev->local)) {
if (dev->ctl & 0x20)
val &= 0x3f;
else
return;
} else
return;
break;
case 0xe3:
if (AGP_BRIDGE_ALI(dev->local)) {
if (dev->ctl & 0x20)
val &= 0xfe;
else
return;
} else
return;
break;
case 0xe4:
if (AGP_BRIDGE_ALI(dev->local)) {
if (dev->ctl & 0x20)
val &= 0x03;
else
return;
}
break;
case 0xe5:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
return;
}
break;
case 0xe6:
if (AGP_BRIDGE_ALI(dev->local)) {
if (dev->ctl & 0x20)
val &= 0xc0;
else
return;
}
break;
case 0xe7:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
return;
}
break;
}
dev->regs[addr] = val;
@@ -251,6 +365,21 @@ pci_bridge_reset(void *priv)
dev->regs[0x07] = 0x02;
break;
case AGP_BRIDGE_ALI_M5243:
dev->regs[0x04] = 0x06;
dev->regs[0x07] = 0x04;
dev->regs[0x0d] = 0x20;
dev->regs[0x19] = 0x01;
dev->regs[0x1b] = 0x20;
dev->regs[0x34] = 0xe0;
dev->regs[0x89] = 0x20;
dev->regs[0x8a] = 0xa0;
dev->regs[0x8e] = 0x20;
dev->regs[0x8f] = 0x20;
dev->regs[0xe0] = 0x01;
pci_remap_bus(dev->bus_index, 0x01);
break;
case AGP_BRIDGE_INTEL_440LX:
dev->regs[0x06] = 0xa0;
dev->regs[0x07] = 0x02;
@@ -362,6 +491,20 @@ const device_t dec21150_device =
};
/* AGP bridges */
const device_t ali5243_agp_device =
{
"ALi M5243 AGP Bridge",
DEVICE_PCI,
AGP_BRIDGE_ALI_M5243,
pci_bridge_init,
NULL,
pci_bridge_reset,
{ NULL },
NULL,
NULL,
NULL
};
const device_t i440lx_agp_device =
{
"Intel 82443LX/EX AGP Bridge",

312
src/device/smbus_ali7101.c Normal file
View File

@@ -0,0 +1,312 @@
/*
* 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 a generic ALi M7101-compatible SMBus host
* controller.
*
* Authors: RichardG, <richardg867@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020,2021 RichardG.
* Copyright 2021 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/i2c.h>
#include <86box/smbus.h>
#ifdef ENABLE_SMBUS_ALI7101_LOG
int smbus_ali7101_do_log = ENABLE_SMBUS_ALI7101_LOG;
static void
smbus_ali7101_log(const char *fmt, ...)
{
va_list ap;
if (smbus_ali7101_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define smbus_ali7101_log(fmt, ...)
#endif
static uint8_t
smbus_ali7101_read(uint16_t addr, void *priv)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) priv;
uint8_t ret = 0x00;
switch (addr - dev->io_base) {
case 0x00:
ret = dev->stat;
break;
case 0x02:
dev->index = 0; /* reading from this resets the block data index */
ret = dev->ctl;
break;
case 0x03:
ret = dev->addr;
break;
case 0x04:
ret = dev->data0;
break;
case 0x05:
ret = dev->data1;
break;
case 0x06:
ret = dev->data[dev->index++];
if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE)
dev->index = 0;
break;
case 0x07:
ret = dev->cmd;
break;
}
smbus_ali7101_log("SMBus ALI7101: read(%02X) = %02x\n", addr, ret);
return ret;
}
static void
smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) priv;
uint8_t smbus_addr, cmd, read, prev_stat;
uint16_t timer_bytes = 0;
smbus_ali7101_log("SMBus ALI7101: write(%02X, %02X)\n", addr, val);
prev_stat = dev->next_stat;
dev->next_stat = 0x04;
switch (addr - dev->io_base) {
case 0x00:
dev->stat &= ~(val & 0xe2);
/* Make sure IDLE is set if we're not busy or errored. */
if (dev->stat == 0x00)
dev->stat = 0x04;
break;
case 0x01:
dev->ctl = val & 0xfc;
if (val & 0x04) { /* cancel an in-progress command if KILL is set */
if (prev_stat) { /* cancel only if a command is in progress */
timer_disable(&dev->response_timer);
dev->stat = 0x80; /* raise FAILED */
}
} else if (val & 0x08) { /* T_OUT_CMD */
if (prev_stat) { /* cancel only if a command is in progress */
timer_disable(&dev->response_timer);
dev->stat = 0x20; /* raise DEVICE_ERR */
}
}
break;
case 0x02:
/* dispatch command if START is set */
timer_bytes++; /* address */
smbus_addr = (dev->addr >> 1);
read = dev->addr & 0x01;
cmd = (dev->ctl >> 4) & 0x7;
smbus_ali7101_log("SMBus ALI7101: addr=%02X read=%d protocol=%X cmd=%02X data0=%02X data1=%02X\n", smbus_addr, read, cmd, dev->cmd, dev->data0, dev->data1);
/* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */
if (!i2c_start(i2c_smbus, smbus_addr, read)) {
dev->next_stat = 0x20;
break;
}
dev->next_stat = 0x10; /* raise INTER (command completed) by default */
/* Decode the command protocol. */
switch (cmd) {
case 0x0: /* quick R/W */
break;
case 0x1: /* byte R/W */
if (read) /* byte read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else /* byte write */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
timer_bytes++;
break;
case 0x2: /* byte data R/W */
/* command write */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
timer_bytes++;
if (read) /* byte read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else /* byte write */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
timer_bytes++;
break;
case 0x3: /* word data R/W */
/* command write */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
timer_bytes++;
if (read) { /* word read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
dev->data1 = i2c_read(i2c_smbus, smbus_addr);
} else { /* word write */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data1);
}
timer_bytes += 2;
break;
case 0x4: /* block R/W */
timer_bytes++; /* count the SMBus length byte now */
/* fall-through */
default: /* unknown */
dev->next_stat = 0x20; /* raise DEV_ERR */
timer_bytes = 0;
break;
}
/* Finish transfer. */
i2c_stop(i2c_smbus, smbus_addr);
break;
case 0x03:
dev->addr = val;
break;
case 0x04:
dev->data0 = val;
break;
case 0x05:
dev->data1 = val;
break;
case 0x06:
dev->data[dev->index++] = val;
if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE)
dev->index = 0;
break;
case 0x07:
dev->cmd = val;
break;
}
if (dev->next_stat != 0x04) { /* schedule dispatch of any pending status register update */
dev->stat = 0x08; /* raise HOST_BUSY while waiting */
timer_disable(&dev->response_timer);
/* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */
timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC);
}
}
static void
smbus_ali7101_response(void *priv)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) priv;
/* Dispatch the status register update. */
dev->stat = dev->next_stat;
}
void
smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable)
{
if (dev->io_base)
io_removehandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev);
dev->io_base = new_io_base;
smbus_ali7101_log("SMBus ALI7101: remap to %04Xh (%sabled)\n", dev->io_base, enable ? "en" : "dis");
if (enable && dev->io_base)
io_sethandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev);
}
static void
smbus_ali7101_reset(void *priv)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) priv;
timer_disable(&dev->response_timer);
dev->stat = 0x04;
}
static void *
smbus_ali7101_init(const device_t *info)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) malloc(sizeof(smbus_ali7101_t));
memset(dev, 0, sizeof(smbus_ali7101_t));
dev->local = info->local;
dev->stat = 0x04;
/* 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("smbus_ali7101");
timer_add(&dev->response_timer, smbus_ali7101_response, dev, 0);
return dev;
}
static void
smbus_ali7101_close(void *priv)
{
smbus_ali7101_t *dev = (smbus_ali7101_t *) priv;
if (i2c_smbus == dev->i2c)
i2c_smbus = NULL;
i2c_removebus(dev->i2c);
free(dev);
}
const device_t ali7101_smbus_device = {
"ALi M7101-compatible SMBus Host Controller",
DEVICE_AT,
0,
smbus_ali7101_init, smbus_ali7101_close, smbus_ali7101_reset,
{ NULL }, NULL, NULL,
NULL
};

View File

@@ -26,7 +26,7 @@
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/i2c.h>
#include <86box/smbus_piix4.h>
#include <86box/smbus.h>
#ifdef ENABLE_SMBUS_PIIX4_LOG