diff --git a/src/acpi.c b/src/acpi.c index 11d991f63..c73440fa5 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -20,6 +20,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -37,10 +38,11 @@ #include <86box/acpi.h> #include <86box/machine.h> #include <86box/i2c.h> - +#include <86box/video.h> int acpi_rtc_status = 0; +static double cpu_to_acpi; #ifdef ENABLE_ACPI_LOG int acpi_do_log = ENABLE_ACPI_LOG; @@ -61,6 +63,50 @@ acpi_log(const char *fmt, ...) #define acpi_log(fmt, ...) #endif +static uint64_t acpi_clock_get() { + return tsc * cpu_to_acpi; +} + +static uint32_t acpi_timer_get(acpi_t *dev) { + uint64_t clock = acpi_clock_get(); + if (dev->regs.timer32) + return clock & 0xffffffff; + else + return clock & 0xffffff; +} + +static double acpi_get_overflow_period(acpi_t *dev) { + uint64_t timer = acpi_clock_get(); + uint64_t overflow_time; + + if (dev->regs.timer32) { + overflow_time = (timer + 0x80000000LL) & ~0x7fffffffLL; + } else { + overflow_time = (timer + 0x800000LL) & ~0x7fffffLL; + } + + uint64_t time_to_overflow = overflow_time - timer; + + return ((double)time_to_overflow / (double)ACPI_TIMER_FREQ) * 1000000.0; +} + +static void +acpi_timer_overflow(void *priv) +{ + acpi_t *dev = (acpi_t *) priv; + dev->regs.pmsts |= TMROF_STS; + acpi_update_irq(dev); +} + +static void +acpi_timer_update(acpi_t *dev, bool enable) +{ + if (enable) { + timer_on_auto(&dev->timer, acpi_get_overflow_period(dev)); + } else { + timer_stop(&dev->timer); + } +} void acpi_update_irq(acpi_t *dev) @@ -84,6 +130,8 @@ acpi_update_irq(acpi_t *dev) else pci_clear_mirq(0xf0 | dev->irq_line, 1); } + + acpi_timer_update(dev, (dev->regs.pmen & TMROF_EN) && !(dev->regs.pmsts & TMROF_STS)); } @@ -145,7 +193,7 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p) break; case 0x08: case 0x09: case 0x0a: case 0x0b: /* PMTMR - Power Management Timer Register (IO) */ - ret = (dev->regs.timer_val >> shift32) & 0xff; + ret = (acpi_timer_get(dev) >> shift32) & 0xff; #ifdef USE_DYNAREC if (cpu_use_dynarec) update_tsc(); @@ -1282,33 +1330,6 @@ acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) } } - -static void -acpi_timer_count(void *priv) -{ - acpi_t *dev = (acpi_t *) priv; - int overflow; - uint32_t old; - - old = dev->regs.timer_val; - dev->regs.timer_val++; - - if (dev->regs.timer32) - overflow = (old ^ dev->regs.timer_val) & 0x80000000; - else { - dev->regs.timer_val &= 0x00ffffff; - overflow = (old ^ dev->regs.timer_val) & 0x00800000; - } - - if (overflow) { - dev->regs.pmsts |= TMROF_EN; - acpi_update_irq(dev); - } - - timer_advance_u64(&dev->timer, ACPICONST); -} - - static void acpi_timer_resume(void *priv) { @@ -1338,9 +1359,6 @@ void acpi_set_timer32(acpi_t *dev, uint8_t timer32) { dev->regs.timer32 = timer32; - - if (!dev->regs.timer32) - dev->regs.timer_val &= 0x00ffffff; } @@ -1524,9 +1542,12 @@ static void acpi_speed_changed(void *priv) { acpi_t *dev = (acpi_t *) priv; + cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock; + bool timer_enabled = timer_is_enabled(&dev->timer); + timer_stop(&dev->timer); - timer_disable(&dev->timer); - timer_set_delay_u64(&dev->timer, ACPICONST); + if (timer_enabled) + timer_on_auto(&dev->timer, acpi_get_overflow_period(dev)); } @@ -1541,7 +1562,7 @@ acpi_close(void *priv) i2c_gpio_close(dev->i2c); } - timer_disable(&dev->timer); + timer_stop(&dev->timer); free(dev); } @@ -1556,6 +1577,7 @@ acpi_init(const device_t *info) if (dev == NULL) return(NULL); memset(dev, 0x00, sizeof(acpi_t)); + cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock; dev->vendor = info->local; dev->irq_line = 9; @@ -1604,8 +1626,7 @@ acpi_init(const device_t *info) break; } - timer_add(&dev->timer, acpi_timer_count, dev, 0); - timer_set_delay_u64(&dev->timer, ACPICONST); + timer_add(&dev->timer, acpi_timer_overflow, dev, 0); timer_add(&dev->resume_timer, acpi_timer_resume, dev, 0); acpi_reset(dev); diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 999909f1d..d12b45507 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -76,10 +76,9 @@ typedef struct devsts, glben, glbctl, devctl, padsts, paden, - gptren, gptimer, timer_val, + gptren, gptimer, gpo_val, gpi_val, extsmi_val, pad0; - uint64_t tmr_overflow_time; } acpi_regs_t; diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index c560fae12..e823794df 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -70,7 +70,7 @@ extern uint64_t PITCONST, ISACONST, HERCCONST, VGACONST1, VGACONST2, - RTCCONST, ACPICONST; + RTCCONST; extern int refresh_at_enable; diff --git a/src/pit.c b/src/pit.c index 28fc9b3c2..f19a1acf7 100644 --- a/src/pit.c +++ b/src/pit.c @@ -1039,7 +1039,6 @@ pit_set_clock(int clock) VGACONST1 = (uint64_t) (cpuclock / 25175000.0 * (double)(1ull << 32)); VGACONST2 = (uint64_t) (cpuclock / 28322000.0 * (double)(1ull << 32)); RTCCONST = (uint64_t) (cpuclock / 32768.0 * (double)(1ull << 32)); - ACPICONST = (uint64_t) (cpuclock / 3579545.0 * (double)(1ull << 32)); TIMER_USEC = (uint64_t)((cpuclock / 1000000.0) * (double)(1ull << 32));