ACPI: replace 3.58MHz timer with an overflow timer

This commit is contained in:
Adrien Moulin
2022-07-15 23:42:40 +02:00
parent 3b2b0b984a
commit 2ed8ad907c
4 changed files with 60 additions and 41 deletions

View File

@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdbool.h>
#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);

View File

@@ -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;

View File

@@ -70,7 +70,7 @@ extern uint64_t PITCONST, ISACONST,
HERCCONST,
VGACONST1,
VGACONST2,
RTCCONST, ACPICONST;
RTCCONST;
extern int refresh_at_enable;

View File

@@ -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));