From b043f1867b653586fcf0bf374883ea741b7a423a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 2 Jul 2020 21:42:31 -0300 Subject: [PATCH] Genesys Logic GL518SM hardware monitor --- src/cpu/cpu.c | 6 +- src/device/hwm_gl518sm.c | 278 +++++++++++++++++++++++++++++++++++ src/device/hwm_lm75.c | 20 ++- src/device/hwm_lm78.c | 31 ++-- src/device/serial.c | 8 + src/include/86box/hwm.h | 5 +- src/machine/m_at_slot1.c | 21 ++- src/machine/m_at_socket370.c | 2 +- src/win/Makefile.mingw | 2 +- 9 files changed, 339 insertions(+), 34 deletions(-) create mode 100644 src/device/hwm_gl518sm.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c958158fc..6e11e85cb 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -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; diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c new file mode 100644 index 000000000..250c34a42 --- /dev/null +++ b/src/device/hwm_gl518sm.c @@ -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, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#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 +}; diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 097b62e8e..c7a057ff4 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -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); diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index bf474db9e..829e323ce 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -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); } diff --git a/src/device/serial.c b/src/device/serial.c index e5490d763..2d1aad6b3 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -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); + } } diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 0cae77dbb..53d69500b 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -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*/ diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 3ddc77186..9236b459e 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -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; } diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index c41737b5e..f555de30c 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -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) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 2334fa603..84c31fb99 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -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 \