Genesys Logic GL518SM hardware monitor

This commit is contained in:
RichardG867
2020-07-02 21:42:31 -03:00
parent e3d7c07aa9
commit b043f1867b
9 changed files with 339 additions and 34 deletions

View File

@@ -61,7 +61,7 @@
#endif
#include "x87_timings.h"
/*#define ENABLE_CPU_LOG 1*/
#define ENABLE_CPU_LOG 1
static void cpu_write(uint16_t addr, uint8_t val, void *priv);
static uint8_t cpu_read(uint16_t addr, void *priv);
@@ -3334,7 +3334,7 @@ void cpu_WRMSR()
break;
case 0x8B:
cpu_log("WRMSR: Invalid MSR: 0x8B\n");
x86gpf(NULL, 0); /*Needed for Vista to correctly break on Pentium*/
//x86gpf(NULL, 0); /*Needed for Vista to correctly break on Pentium*/
break;
}
break;
@@ -3467,7 +3467,7 @@ void cpu_WRMSR()
default:
i686_invalid_wrmsr:
cpu_log("WRMSR: Invalid MSR: %08X\n", ECX);
x86gpf(NULL, 0);
//x86gpf(NULL, 0);
break;
}
break;

278
src/device/hwm_gl518sm.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* 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 Genesys Logic GL518SM hardware monitoring chip.
*
*
*
* Author: RichardG, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define HAVE_STDARG_H
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include "cpu.h"
#include <86box/smbus.h>
#include <86box/hwm.h>
#define CLAMP(a, min, max) (((a)< (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
#define GL518SM_RPM_TO_REG(r, d) ((r) ? CLAMP(480000 / (r * d), 1, 255) : 0)
#define GL518SM_VOLTAGE_TO_REG(v) (((v) / 19) & 0xff)
#define GL518SM_VDD_TO_REG(v) ((((v) * 4) / 95) & 0xff)
typedef struct {
uint32_t local;
hwm_values_t *values;
uint16_t regs[32];
uint8_t addr_register;
uint8_t smbus_addr;
} gl518sm_t;
static uint8_t gl518sm_smbus_read_byte(uint8_t addr, void *priv);
static uint8_t gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
static uint16_t gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv);
static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg);
static void gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv);
static void gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
static void gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val);
static void gl518sm_reset(gl518sm_t *dev);
#define ENABLE_GL518SM_LOG 1
#ifdef ENABLE_GL518SM_LOG
int gl518sm_do_log = ENABLE_GL518SM_LOG;
static void
gl518sm_log(const char *fmt, ...)
{
va_list ap;
if (gl518sm_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define gl518sm_log(fmt, ...)
#endif
static void
gl518sm_remap(gl518sm_t *dev, uint8_t addr)
{
gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr);
smbus_removehandler(dev->smbus_addr, 1,
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
if (addr < 0x80) smbus_sethandler(addr, 1,
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
}
static uint8_t
gl518sm_smbus_read_byte(uint8_t addr, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, dev->addr_register);
}
static uint8_t
gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, cmd);
}
static uint16_t
gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, cmd);
}
static uint16_t
gl518sm_read(gl518sm_t *dev, uint8_t reg)
{
uint16_t ret = dev->regs[reg & 0x1f];
switch (reg) {
case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c:
/* two-byte registers: leave as-is */
break;
default:
/* single-byte registers: duplicate low byte to high byte (real hardware behavior unknown) */
ret |= (ret << 8);
break;
}
gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret);
return ret;
}
static void
gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
dev->addr_register = val;
}
static void
gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
gl518sm_write(dev, cmd, val);
}
static void
gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
gl518sm_write(dev, cmd, val);
}
static uint8_t
gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val)
{
gl518sm_log("GL518SM: write(%02X, %04X)\n", reg, val);
switch (reg) {
case 0x00: case 0x01: case 0x04: case 0x07: case 0x0d: case 0x12: case 0x13: case 0x14: case 0x15:
/* read-only registers */
return 0;
case 0x0a:
dev->regs[0x13] = (val & 0xff);
break;
case 0x03:
dev->regs[reg] = (val & 0xfc);
if (val & 0x80) /* Init */
gl518sm_reset(dev);
break;
case 0x0f:
dev->regs[reg] = (val & 0xf8);
/* update fan values to match the new divisor */
dev->regs[0x07] = (GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8);
dev->regs[0x07] |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3));
break;
case 0x11:
dev->regs[reg] = (val & 0x7f);
break;
default:
dev->regs[reg] = val;
break;
}
return 1;
}
static void
gl518sm_reset(gl518sm_t *dev)
{
memset(dev->regs, 0, sizeof(dev->regs));
dev->regs[0x00] = 0x80;
dev->regs[0x01] = 0x80; /* revision 0x80 can read all voltages */
dev->regs[0x04] = ((dev->values->temperatures[0] + 119) & 0xff);
dev->regs[0x05] = 0xc7;
dev->regs[0x06] = 0xc2;
dev->regs[0x07] = ((GL518SM_RPM_TO_REG(dev->values->fans[0], 8) << 8) | GL518SM_RPM_TO_REG(dev->values->fans[1], 8));
dev->regs[0x08] = 0x6464;
dev->regs[0x09] = 0xdac5;
dev->regs[0x0a] = 0xdac5;
dev->regs[0x0b] = 0xdac5;
dev->regs[0x0c] = 0xdac5;
/* AOpen System Monitor requires an approximate voltage offset of 13 at least on 3.3V (voltages[2]) */
dev->regs[0x0d] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[2]);
dev->regs[0x0f] = 0xf8;
dev->regs[0x13] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[1]);
dev->regs[0x14] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[0]);
dev->regs[0x15] = 13 + GL518SM_VDD_TO_REG(5000);
}
static void
gl518sm_close(void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
gl518sm_remap(dev, 0);
free(dev);
}
static void *
gl518sm_init(const device_t *info)
{
gl518sm_t *dev = (gl518sm_t *) malloc(sizeof(gl518sm_t));
memset(dev, 0, sizeof(gl518sm_t));
dev->local = info->local;
dev->values = hwm_get_values();
gl518sm_reset(dev);
gl518sm_remap(dev, dev->local & 0x7f);
return dev;
}
const device_t gl518sm_2c_device = {
"Genesys Logic GL518SM Hardware Monitor",
DEVICE_ISA,
0x2c,
gl518sm_init, gl518sm_close, NULL,
NULL, NULL, NULL,
NULL
};
const device_t gl518sm_2d_device = {
"Genesys Logic GL518SM Hardware Monitor",
DEVICE_ISA,
0x2d,
gl518sm_init, gl518sm_close, NULL,
NULL, NULL, NULL,
NULL
};

View File

@@ -60,19 +60,21 @@ lm75_log(const char *fmt, ...)
void
lm75_remap(lm75_t *dev)
lm75_remap(lm75_t *dev, uint8_t addr)
{
lm75_log("LM75: remapping to SMBus %02Xh\n", dev->smbus_addr);
lm75_log("LM75: remapping to SMBus %02Xh\n", addr);
smbus_removehandler(dev->smbus_addr, 1,
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
if (dev->smbus_addr) smbus_sethandler(dev->smbus_addr, 1,
if (addr < 0x80) smbus_sethandler(addr, 1,
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
}
@@ -128,7 +130,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal SMBus call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr))
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80))
ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg);
else
ret = dev->regs[reg & 0x7];
@@ -191,7 +193,7 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal SMBus call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr)) {
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80)) {
smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val);
return 1;
}
@@ -216,7 +218,7 @@ lm75_reset(lm75_t *dev)
dev->regs[0x3] = 0x4b;
dev->regs[0x5] = 0x50;
lm75_remap(dev);
lm75_remap(dev, dev->local & 0x7f);
}
@@ -224,6 +226,9 @@ static void
lm75_close(void *priv)
{
lm75_t *dev = (lm75_t *) priv;
lm75_remap(dev, 0);
free(dev);
}
@@ -237,8 +242,7 @@ lm75_init(const device_t *info)
dev->local = info->local;
dev->values = hwm_get_values();
dev->smbus_addr = dev->local;
dev->as99127f_smbus_addr = 0x00;
dev->as99127f_smbus_addr = 0x80;
lm75_reset(dev);

View File

@@ -91,24 +91,26 @@ lm78_log(const char *fmt, ...)
static void
lm78_remap(lm78_t *dev)
lm78_remap(lm78_t *dev, uint8_t addr)
{
lm75_t *lm75;
if (!(dev->local & LM78_SMBUS)) return;
lm78_log("LM78: remapping to SMBus %02Xh\n", dev->smbus_addr);
lm78_log("LM78: remapping to SMBus %02Xh\n", addr);
smbus_removehandler(dev->smbus_addr, 1,
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
if (dev->smbus_addr) smbus_sethandler(dev->smbus_addr, 1,
if (addr < 0x80) smbus_sethandler(addr, 1,
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
if (dev->local & LM78_AS99127F) {
/* Store the main SMBus address on the LM75 devices to ensure reads/writes
to the AS99127F's proprietary registers are passed through to this side. */
@@ -291,10 +293,8 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
switch (reg) {
case 0x40:
if (val & 0x80) {
/* INITIALIZATION bit resets all registers except main SMBus address */
if (val & 0x80) /* INITIALIZATION bit resets all registers except main SMBus address */
lm78_reset(dev, 1);
}
break;
case 0x47:
/* update FAN1/FAN2 values to match the new divisor */
@@ -303,19 +303,15 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
break;
case 0x48:
/* set main SMBus address */
if (dev->local & LM78_SMBUS) {
dev->smbus_addr = (dev->regs[0x48] & 0x7f);
lm78_remap(dev);
}
if (dev->local & LM78_SMBUS)
lm78_remap(dev, dev->regs[0x48] & 0x7f);
break;
case 0x49:
if (!(dev->local & LM78_WINBOND)) {
if (val & 0x20) {
/* Chip Reset bit (LM78 only) resets all registers */
if (val & 0x20) /* Chip Reset bit (LM78 only) resets all registers */
lm78_reset(dev, 0);
} else {
else
dev->regs[0x49] = 0x40;
}
} else {
dev->regs[0x49] &= 0x01;
}
@@ -328,10 +324,9 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
if (!lm75)
continue;
if (dev->regs[0x4a] & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */
lm75->smbus_addr = 0x00;
lm75_remap(lm75, 0x80);
else
lm75->smbus_addr = (0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7));
lm75_remap(lm75);
lm75_remap(lm75, 0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7));
}
}
break;
@@ -428,7 +423,7 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
dev->regs[0x49] = 0x40;
}
lm78_remap(dev);
lm78_remap(dev, dev->smbus_addr);
}

View File

@@ -203,6 +203,14 @@ serial_transmit(serial_t *dev, uint8_t val)
write_fifo(dev, val);
else if (dev->sd->dev_write)
dev->sd->dev_write(dev, dev->sd->priv, val);
if ((val >= ' ' && val <= '~') || val == '\r' || val == '\n') {
fputc(val, stdout);
if (val == '\n')
fflush(stdout);
} else {
fprintf(stdout, "[%02X]", val);
}
}

View File

@@ -43,7 +43,7 @@ typedef struct {
extern void hwm_set_values(hwm_values_t new_values);
extern hwm_values_t* hwm_get_values();
extern void lm75_remap(lm75_t *dev);
extern void lm75_remap(lm75_t *dev, uint8_t addr);
extern uint8_t lm75_read(lm75_t *dev, uint8_t reg);
extern uint8_t lm75_write(lm75_t *dev, uint8_t reg, uint8_t val);
@@ -56,5 +56,8 @@ extern const device_t w83781d_device;
extern const device_t as99127f_device;
extern const device_t as99127f_rev2_device;
extern const device_t gl518sm_2c_device;
extern const device_t gl518sm_2d_device;
#endif /*EMU_HWM_H*/

View File

@@ -365,13 +365,30 @@ machine_at_ax6bc_init(const machine_t *model)
pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4);
pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4);
device_add(&i440bx_device);
device_add(&piix4e_device);
device_add(&keyboard_ps2_pci_device);
device_add(&w83977tf_device);
device_add(&sst_flash_29ee020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* System */
3000 /* CPU */
}, { /* temperatures */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the GL518SM datasheet) */
3300 /* +3.3V */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&gl518sm_2d_device);
return ret;
}

View File

@@ -217,7 +217,7 @@ machine_at_63a_init(const machine_t *model)
{
int ret;
ret = bios_load_linear(L"roms/machines/63a1/63a-q3.bin",
ret = bios_load_linear(L"roms/machines/63a1/6ZX82.BIN",
0x000c0000, 262144, 0);
if (bios_only || !ret)

View File

@@ -582,7 +582,7 @@ MCHOBJ := machine.o machine_table.o \
m_at_socket4_5.o m_at_socket7_s7.o m_at_sockets7.o \
m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o
DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o serial.o \
DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o serial.o \
smbus.o smbus_piix4.o \
keyboard.o \
keyboard_xt.o keyboard_at.o \