diff --git a/src/hwm.c b/src/hwm.c index cac194d98..7ef55b3ef 100644 --- a/src/hwm.c +++ b/src/hwm.c @@ -11,6 +11,7 @@ * * * Author: RichardG, + * * Copyright 2020 RichardG. */ diff --git a/src/hwm_lm75.c b/src/hwm_lm75.c new file mode 100644 index 000000000..1b6431395 --- /dev/null +++ b/src/hwm_lm75.c @@ -0,0 +1,269 @@ +/* + * 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 LM75 temperature sensor 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/smbus.h> +#include <86box/hwm.h> + + +#define LM75_TEMP_TO_REG(t) ((t) << 8) + + +static uint8_t lm75_smbus_read_byte(uint8_t addr, void *priv); +static uint8_t lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); +static uint16_t lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); +static void lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); +static void lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); +static void lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static void lm75_reset(lm75_t *dev); + + +#ifdef ENABLE_LM75_LOG +int lm75_do_log = ENABLE_LM75_LOG; + + +static void +lm75_log(const char *fmt, ...) +{ + va_list ap; + + if (lm75_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define lm75_log(fmt, ...) +#endif + + +void +lm75_remap(lm75_t *dev) +{ + lm75_log("LM75: remapping to SMBus %02Xh\n", dev->smbus_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, + 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); +} + + +static uint8_t +lm75_smbus_read_byte(uint8_t addr, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + return lm75_read(dev, dev->addr_register); +} + + +static uint8_t +lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + return lm75_read(dev, cmd); +} + +static uint16_t +lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + uint8_t rethi = 0; + uint8_t retlo = 0; + + switch (cmd & 0x3) { + case 0x0: /* temperature */ + rethi = lm75_read(dev, 0x0); + retlo = lm75_read(dev, 0x1); + break; + case 0x1: /* configuration */ + rethi = retlo = lm75_read(dev, 0x2); + break; + case 0x2: /* Thyst */ + rethi = lm75_read(dev, 0x3); + retlo = lm75_read(dev, 0x4); + break; + case 0x3: /* Tos */ + rethi = lm75_read(dev, 0x5); + retlo = lm75_read(dev, 0x6); + break; + } + + return (retlo << 8) | rethi; /* byte-swapped for some reason */ +} + + +uint8_t +lm75_read(lm75_t *dev, uint8_t reg) +{ + uint8_t ret; + + /* 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 >= 0x80) && (dev->as99127f_smbus_addr)) + ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg); + else + ret = dev->regs[reg & 0x7]; + + lm75_log("LM75: read(%x) = %02x\n", reg, ret); + + return ret; +} + + +static void +lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + dev->addr_register = val; +} + + +static void +lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + lm75_write(dev, cmd, val); +} + + +static void +lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + uint8_t valhi = (val >> 8); + uint8_t vallo = (val & 0xff); + + switch (cmd & 0x3) { + case 0x0: /* temperature */ + lm75_write(dev, 0x0, valhi); + lm75_write(dev, 0x1, vallo); + break; + case 0x1: /* configuration */ + lm75_write(dev, 0x2, vallo); + break; + case 0x2: /* Thyst */ + lm75_write(dev, 0x3, valhi); + lm75_write(dev, 0x4, vallo); + break; + case 0x3: /* Tos */ + lm75_write(dev, 0x5, valhi); + lm75_write(dev, 0x6, vallo); + break; + break; + } +} + + +uint8_t +lm75_write(lm75_t *dev, uint8_t reg, uint8_t val) +{ + lm75_log("LM75: write(%x, %02x)\n", reg, 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 >= 0x80) && (dev->as99127f_smbus_addr)) { + smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val); + return 1; + } + + uint8_t reg_idx = (reg & 0x7); + + if ((reg_idx <= 0x1) || (reg_idx == 0x7)) + return 0; /* read-only registers */ + + dev->regs[reg_idx] = val; + + return 1; +} + + +static void +lm75_reset(lm75_t *dev) +{ + uint16_t temp = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]); + dev->regs[0x0] = (temp >> 8); + dev->regs[0x1] = temp; + dev->regs[0x3] = 0x4b; + dev->regs[0x5] = 0x50; + + lm75_remap(dev); +} + + +static void +lm75_close(void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + free(dev); +} + + +static void * +lm75_init(const device_t *info) +{ + lm75_t *dev = (lm75_t *) malloc(sizeof(lm75_t)); + memset(dev, 0, sizeof(lm75_t)); + + dev->local = info->local; + dev->values = hwm_get_values(); + + dev->smbus_addr = dev->local; + dev->as99127f_smbus_addr = 0x00; + + lm75_reset(dev); + + return dev; +} + + +/* LM75 on SMBus address 4Ah, reporting temperatures[1]. */ +const device_t lm75_1_4a_device = { + "National Semiconductor LM75 Temperature Sensor", + DEVICE_AT, + 0x14a, + lm75_init, lm75_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +/* LM75 secondary/tertiary temperature sensors built into + the Winbond W83781D family. Not to be used stand-alone. */ +const device_t lm75_w83781d_device = { + "Winbond W83781D Secondary Temperature Sensor", + DEVICE_AT, + 0, + lm75_init, lm75_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/hwm_lm78.c b/src/hwm_lm78.c index 27c15fe8f..2ecc36f14 100644 --- a/src/hwm_lm78.c +++ b/src/hwm_lm78.c @@ -39,23 +39,19 @@ #define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a))) #define LM78_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0) -#define LM78_TEMP_TO_REG(t) ((t) << 8) #define LM78_VOLTAGE_TO_REG(v) ((v) >> 4) typedef struct { uint32_t local; - hwm_values_t* values; + hwm_values_t *values; + device_t *lm75[2]; uint8_t regs[256]; - uint8_t regs_bank1[7]; - uint8_t regs_bank2[7]; uint8_t addr_register; uint8_t data_register; - uint8_t smbus_addr_main; - uint8_t smbus_addr_temp2; - uint8_t smbus_addr_temp3; + uint8_t smbus_addr; uint8_t hbacs; uint8_t active_bank; } lm78_t; @@ -97,29 +93,31 @@ lm78_log(const char *fmt, ...) static void lm78_remap(lm78_t *dev) { + lm75_t *lm75; + if (!(dev->local & LM78_SMBUS)) return; - lm78_log("LM78: SMBus remap: main = %02Xh; temp2 = %02Xh; temp3 = %02Xh\n", dev->smbus_addr_main, dev->smbus_addr_temp2, dev->smbus_addr_temp3); + lm78_log("LM78: remapping to SMBus %02Xh\n", dev->smbus_addr); - smbus_removehandler(0x00, 0x80, + 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_main) smbus_sethandler(dev->smbus_addr_main, 1, + if (dev->smbus_addr) smbus_sethandler(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_temp2) smbus_sethandler(dev->smbus_addr_temp2, 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_temp3) smbus_sethandler(dev->smbus_addr_temp3, 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->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. */ + for (uint8_t i = 0; i <= 1; i++) { + lm75 = device_get_priv(dev->lm75[i]); + if (lm75) + lm75->as99127f_smbus_addr = dev->smbus_addr; + } + } } @@ -127,9 +125,9 @@ static uint8_t lm78_isa_read(uint16_t port, void *priv) { lm78_t *dev = (lm78_t *) priv; - uint8_t ret = 0xFF; + uint8_t ret = 0xff; - switch (port & 0xf) { + switch (port & 0x7) { case 0x5: ret = (dev->addr_register & 0x7f); break; @@ -143,6 +141,9 @@ lm78_isa_read(uint16_t port, void *priv) dev->addr_register++; } break; + default: + lm78_log("LM78: Read from unknown ISA port %x\n", port & 0x7); + break; } return ret; @@ -153,7 +154,7 @@ static uint8_t lm78_smbus_read_byte(uint8_t addr, void *priv) { lm78_t *dev = (lm78_t *) priv; - return lm78_smbus_read_byte_cmd(addr, dev->addr_register, priv); + return lm78_read(dev, dev->addr_register, dev->active_bank); } @@ -161,14 +162,7 @@ static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; - - uint8_t bank = 0; - if (addr == dev->smbus_addr_temp2) - bank = 1; - else if (addr == dev->smbus_addr_temp3) - bank = 2; - - return lm78_read(dev, cmd, bank); + return lm78_read(dev, cmd, dev->active_bank); } @@ -176,38 +170,7 @@ static uint16_t lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; - uint8_t rethi = 0; - uint8_t retlo = 0; - uint8_t bank = 0; - - if ((dev->local & LM78_WINBOND) && ((addr == dev->smbus_addr_temp2) || (addr == dev->smbus_addr_temp3))) { - if (addr == dev->smbus_addr_temp2) - bank = 2; - else - bank = 3; - - switch (cmd & 0x3) { - case 0x0: /* temperature */ - rethi = lm78_read(dev, 0x50, bank); - retlo = lm78_read(dev, 0x51, bank); - break; - case 0x1: /* configuration */ - rethi = retlo = lm78_read(dev, 0x52, bank); - break; - case 0x2: /* Thyst */ - rethi = lm78_read(dev, 0x53, bank); - retlo = lm78_read(dev, 0x54, bank); - break; - case 0x3: /* Tos */ - rethi = lm78_read(dev, 0x55, bank); - retlo = lm78_read(dev, 0x56, bank); - break; - } - } else { - rethi = retlo = lm78_read(dev, cmd, bank); - } - - return (retlo << 8) | rethi; /* byte-swapped for some reason */ + return (lm78_read(dev, cmd, dev->active_bank) << 8) | lm78_read(dev, cmd, dev->active_bank); } @@ -215,20 +178,20 @@ static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank) { uint8_t ret = 0; + lm75_t *lm75; - if ((dev->local & LM78_WINBOND) && ((reg >> 4) == 0x5) && (bank != 0)) { - /* bank-switched temperature registers */ - if (bank == 1) - ret = dev->regs_bank1[reg & 0x7]; - else - ret = dev->regs_bank2[reg & 0x7]; + if (((reg >> 4) == 0x5) && (bank != 0)) { + /* LM75 registers */ + lm75 = device_get_priv(dev->lm75[bank - 1]); + if (lm75) + ret = lm75_read(lm75, reg & 0x7); } else { /* regular registers */ if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* special case for two-byte vendor ID register */ ret = (dev->hbacs ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID); else if ((reg >= 0x60) && (reg <= 0x7f)) /* read auto-increment value RAM registers from their non-auto-increment locations */ ret = dev->regs[reg & 0x3f]; - else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors POST RAM to 80-92 */ + else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */ ret = dev->regs[reg - 0x7f]; else ret = dev->regs[reg]; @@ -245,7 +208,7 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - switch (port & 0xf) { + switch (port & 0x7) { case 0x5: dev->addr_register = (val & 0x7f); break; @@ -259,6 +222,9 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv) dev->addr_register++; } break; + default: + lm78_log("LM78: Write %02x to unknown ISA port %x\n", val, port & 0x7); + break; } } @@ -267,7 +233,6 @@ static void lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - dev->addr_register = val; } @@ -276,8 +241,7 @@ static void lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - - lm78_write(dev, cmd, val, 0); + lm78_write(dev, cmd, val, dev->active_bank); } @@ -285,60 +249,23 @@ static void lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - uint8_t valhi = (val >> 8); - uint8_t vallo = (val & 0xff); - uint8_t bank = 0; - - if ((dev->local & LM78_WINBOND) && ((addr == dev->smbus_addr_temp2) || (addr == dev->smbus_addr_temp3))) { - if (addr == dev->smbus_addr_temp2) - bank = 2; - else - bank = 3; - - switch (cmd & 0x3) { - case 0x0: /* temperature */ - lm78_write(dev, 0x50, valhi, bank); - lm78_write(dev, 0x51, vallo, bank); - break; - case 0x1: /* configuration */ - lm78_write(dev, 0x52, vallo, bank); - break; - case 0x2: /* Thyst */ - lm78_write(dev, 0x53, valhi, bank); - lm78_write(dev, 0x54, vallo, bank); - break; - case 0x3: /* Tos */ - lm78_write(dev, 0x55, valhi, bank); - lm78_write(dev, 0x56, vallo, bank); - break; - break; - } - return; - } - - lm78_write(dev, cmd, vallo, bank); + lm78_write(dev, cmd, val, dev->active_bank); } static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) { - uint8_t remap = 0; + lm75_t *lm75; - if ((dev->local & LM78_WINBOND) && ((reg >> 4) == 0x5) && (bank != 0)) { - /* bank-switched temperature registers */ - switch (reg) { - case 0x50: case 0x51: - /* read-only registers */ - return 0; - } + lm78_log("LM78: write(%02x, %d, %02x)\n", reg, bank, val); - if (bank == 1) - dev->regs_bank1[reg & 0x7] = val; - else - dev->regs_bank2[reg & 0x7] = val; - - goto end; + if (((reg >> 4) == 0x5) && (bank != 0)) { + /* LM75 registers */ + lm75 = device_get_priv(dev->lm75[bank - 1]); + if (lm75) + lm75_write(lm75, reg & 0x7, val); + return 1; } /* regular registers */ @@ -357,7 +284,7 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) if ((reg >= 0x60) && (reg <= 0x7f)) /* write auto-increment value RAM registers to their non-auto-increment locations */ dev->regs[reg & 0x3f] = val; - else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors POST RAM to 80-92 */ + else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */ dev->regs[reg & 0x7f] = val; else dev->regs[reg] = val; @@ -377,8 +304,8 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) case 0x48: /* set main SMBus address */ if (dev->local & LM78_SMBUS) { - dev->smbus_addr_main = (dev->regs[0x48] & 0x7f); - remap = 1; + dev->smbus_addr = (dev->regs[0x48] & 0x7f); + lm78_remap(dev); } break; case 0x49: @@ -394,18 +321,16 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) } break; case 0x4a: - /* set TEMP2 and TEMP3 SMBus addresses (Winbond only) */ + /* set LM75 SMBus addresses (Winbond only) */ if (dev->local & LM78_SMBUS) { - /* DIS_T2 and DIS_T3 bit disable those interfaces */ - if (dev->regs[0x4a] & 0x08) - dev->smbus_addr_temp2 = 0x00; - else - dev->smbus_addr_temp2 = (0x48 + (dev->regs[0x4a] & 0x7)); - if (dev->regs[0x4a] & 0x80) - dev->smbus_addr_temp3 = 0x00; - else - dev->smbus_addr_temp3 = (0x48 + ((dev->regs[0x4a] >> 4) & 0x7)); - remap = 1; + for (uint8_t i = 0; i <= 1; i++) { + lm75 = device_get_priv(dev->lm75[i]); + if (dev->regs[0x4a] & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */ + lm75->smbus_addr = 0x00; + else + lm75->smbus_addr = (0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7)); + lm75_remap(lm75); + } } break; case 0x4b: @@ -426,12 +351,6 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) break; } - if (remap) - lm78_remap(dev); - -end: - lm78_log("LM78: write(%02x, %d) = %02x\n", reg, bank, val); - return 1; } @@ -441,8 +360,6 @@ lm78_reset(lm78_t *dev, uint8_t initialization) { memset(dev->regs, 0, 256); memset(dev->regs + 0xc0, 0xff, 32); /* C0-DF are 0xFF at least on the AS99127F */ - memset(dev->regs_bank1, 0, 6); - memset(dev->regs_bank2, 0, 6); uint8_t i; for (i = 0; i <= 6; i++) @@ -455,20 +372,14 @@ lm78_reset(lm78_t *dev, uint8_t initialization) dev->regs[0x47] = 0x50; if (dev->local & LM78_SMBUS) { if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */ - dev->smbus_addr_main = 0x2d; - dev->regs[0x48] = dev->smbus_addr_main; - if (dev->local & LM78_WINBOND) { + dev->smbus_addr = 0x2d; + dev->regs[0x48] = dev->smbus_addr; + if (dev->local & LM78_WINBOND) dev->regs[0x4a] = 0x01; - dev->smbus_addr_temp2 = (0x48 + (dev->regs[0x4a] & 0x7)); - dev->smbus_addr_temp3 = (0x48 + ((dev->regs[0x4a] >> 4) & 0x7)); - } else { - dev->smbus_addr_temp2 = dev->smbus_addr_temp3 = 0x00; - } } else { dev->regs[0x48] = 0x00; if (dev->local & LM78_WINBOND) dev->regs[0x4a] = 0x88; - dev->smbus_addr_temp2 = dev->smbus_addr_temp3 = 0x00; } if (dev->local & LM78_WINBOND) { dev->regs[0x49] = 0x02; @@ -480,17 +391,15 @@ lm78_reset(lm78_t *dev, uint8_t initialization) dev->regs[0x4f] = (LM78_WINBOND_VENDOR_ID >> 8); dev->regs[0x57] = 0x80; - /* - * Initialize proprietary registers on the AS99127F. The BIOS accesses some - * of these on boot through read_byte_cmd on the TEMP2 address, hanging on - * POST code C1 if they're set to 0. There's no documentation on what these - * are for. The following values were dumped from a live, initialized - * AS99127F Rev. 2 on a P4B motherboard, and they seem to work well enough. - */ + /* Initialize proprietary registers on the AS99127F. The BIOS accesses some + of these on boot through read_byte_cmd on the TEMP2 address, hanging on + POST code C1 if they're defaulted to 0. There's no documentation on what + these are for. The following values were dumped from a live, initialized + AS99127F Rev. 2 on a P4B motherboard, and they seem to work well enough. */ if (dev->local & LM78_AS99127F) { /* 0x00 appears to mirror IN2 Low Limit */ dev->regs[0x01] = dev->regs[0x23]; /* appears to mirror IN3 */ - dev->regs[0x02] = LM78_VOLTAGE_TO_REG(2800); /* appears to be a "maximum VCORE" of some kind; mirrors VCORE on the P4 board, but the P3 boards require this to read 2.8V */ + dev->regs[0x02] = LM78_VOLTAGE_TO_REG(2800); /* appears to be a "maximum VCORE" of some kind; must read 2.8V on P3 boards */ dev->regs[0x03] = 0x60; dev->regs[0x04] = dev->regs[0x23]; /* appears to mirror IN3 */ dev->regs[0x05] = dev->regs[0x22]; /* appears to mirror IN2 */ @@ -513,19 +422,6 @@ lm78_reset(lm78_t *dev, uint8_t initialization) } else { dev->regs[0x58] = 0x10; } - - /* WARNING: Array elements are register - 0x50. */ - uint16_t temp; - temp = LM78_TEMP_TO_REG(dev->values->temperatures[1]); - dev->regs_bank1[0x0] = (temp >> 8); - dev->regs_bank1[0x1] = (temp & 0xff); - dev->regs_bank1[0x3] = 0x4b; - dev->regs_bank1[0x5] = 0x50; - temp = LM78_TEMP_TO_REG(dev->values->temperatures[2]); - dev->regs_bank2[0x0] = (temp >> 8); - dev->regs_bank2[0x1] = (temp & 0xff); - dev->regs_bank2[0x3] = 0x4b; - dev->regs_bank2[0x5] = 0x50; } else { dev->regs[0x49] = 0x40; } @@ -541,7 +437,7 @@ lm78_close(void *priv) uint16_t isa_io = (dev->local & 0xffff); if (isa_io) - io_removehandler(isa_io, 2, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); + io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); free(dev); } @@ -555,11 +451,26 @@ lm78_init(const device_t *info) dev->local = info->local; dev->values = hwm_get_values(); + + /* initialize secondary/tertiary LM75 sensors on Winbond */ + for (uint8_t i = 0; i <= 1; i++) { + if (dev->local & LM78_WINBOND) { + dev->lm75[i] = (device_t *) malloc(sizeof(device_t)); + memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t)); + dev->lm75[i]->local = ((i + 1) << 8); + if (dev->local & LM78_SMBUS) + dev->lm75[i]->local |= (0x48 + i); + device_add(dev->lm75[i]); + } else { + dev->lm75[i] = NULL; + } + } + lm78_reset(dev, 0); uint16_t isa_io = (dev->local & 0xffff); if (isa_io) - io_sethandler(isa_io, 2, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); + io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); return dev; } @@ -569,7 +480,7 @@ lm78_init(const device_t *info) const device_t lm78_device = { "National Semiconductor LM78 Hardware Monitor", DEVICE_ISA, - 0x295 | LM78_SMBUS, + 0x290 | LM78_SMBUS, lm78_init, lm78_close, NULL, NULL, NULL, NULL, NULL @@ -580,7 +491,7 @@ const device_t lm78_device = { const device_t w83781d_device = { "Winbond W83781D Hardware Monitor", DEVICE_ISA, - 0x295 | LM78_SMBUS | LM78_W83781D, + 0x290 | LM78_SMBUS | LM78_W83781D, lm78_init, lm78_close, NULL, NULL, NULL, NULL, NULL diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index efde01767..0cae77dbb 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -27,10 +27,29 @@ typedef struct _hwm_values_ { uint16_t voltages[8]; } hwm_values_t; +typedef struct { + uint32_t local; + hwm_values_t *values; + + uint8_t regs[8]; + uint8_t addr_register; + uint8_t temp_idx; + uint8_t smbus_addr; + + uint8_t as99127f_smbus_addr; +} lm75_t; + 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 uint8_t lm75_read(lm75_t *dev, uint8_t reg); +extern uint8_t lm75_write(lm75_t *dev, uint8_t reg, uint8_t val); + + +extern const device_t lm75_1_4a_device; +extern const device_t lm75_w83781d_device; extern const device_t lm78_device; extern const device_t w83781d_device; diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 65838fd21..436a522f5 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -214,7 +214,7 @@ machine_at_p3bf_init(const machine_t *model) 3000 /* Power */ }, { /* temperatures */ 30, /* MB */ - 0, /* unused */ + 30, /* JTPWR */ 30 /* CPU */ }, { /* voltages */ 2050, /* VCORE (2.05V by default) */ diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index b0c75f80a..8852ee804 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -135,7 +135,7 @@ machine_at_cubx_init(const machine_t *model) 3000 /* Power */ }, { /* temperatures */ 30, /* MB */ - 0, /* unused */ + 30, /* JTPWR */ 30 /* CPU */ }, { /* voltages */ 2050, /* VCORE (2.05V by default) */ diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c index c38fecbd4..c4792518c 100644 --- a/src/machine/m_at_socket7_s7.c +++ b/src/machine/m_at_socket7_s7.c @@ -847,7 +847,8 @@ machine_at_p5mms98_init(const machine_t *model) 3000, /* CPU */ 3000 /* Chassis */ }, { /* temperatures */ - 28 /* CPU (locked at 28?) */ + 0, /* unused */ + 30 /* CPU */ }, { /* voltages */ 3300, /* VCORE (3.3V by default) */ 3300, /* VIO (3.3V) */ @@ -873,6 +874,7 @@ machine_at_p5mms98_init(const machine_t *model) } hwm_set_values(machine_hwm); device_add(&lm78_device); + device_add(&lm75_1_4a_device); return ret; } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9ef6f013f..9e2ad81d9 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -535,7 +535,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket4_5.o m_at_socket7_s7.o m_at_super7_ss7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o -DEVOBJ := bugger.o hwm.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o $(SERIAL) \ +DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o $(SERIAL) \ sio_detect.o sio_acc3221.o \ sio_f82c710.o \ sio_fdc37c66x.o sio_fdc37c669.o \ diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw index f454ce035..29ff11093 100644 --- a/src/win/Makefile_ndr.mingw +++ b/src/win/Makefile_ndr.mingw @@ -539,7 +539,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket4_5.o m_at_socket7_s7.o m_at_super7_ss7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o -DEVOBJ := bugger.o hwm.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o $(SERIAL) \ +DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o $(SERIAL) \ sio_acc3221.o \ sio_f82c710.o \ sio_fdc37c66x.o sio_fdc37c669.o \