|
@@ -29,7 +29,8 @@
|
|
|
/* Tick Timer global state to allow all cores to be in sync */
|
|
|
typedef struct OR1KTimerState {
|
|
|
uint32_t ttcr;
|
|
|
- uint64_t last_clk;
|
|
|
+ uint32_t ttcr_offset;
|
|
|
+ uint64_t clk_offset;
|
|
|
} OR1KTimerState;
|
|
|
|
|
|
static OR1KTimerState *or1k_timer;
|
|
@@ -37,6 +38,8 @@ static OR1KTimerState *or1k_timer;
|
|
|
void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val)
|
|
|
{
|
|
|
or1k_timer->ttcr = val;
|
|
|
+ or1k_timer->ttcr_offset = val;
|
|
|
+ or1k_timer->clk_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
|
|
}
|
|
|
|
|
|
uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu)
|
|
@@ -53,9 +56,8 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu)
|
|
|
return;
|
|
|
}
|
|
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
|
|
- or1k_timer->ttcr += (uint32_t)((now - or1k_timer->last_clk)
|
|
|
- / TIMER_PERIOD);
|
|
|
- or1k_timer->last_clk = now;
|
|
|
+ or1k_timer->ttcr = or1k_timer->ttcr_offset +
|
|
|
+ DIV_ROUND_UP(now - or1k_timer->clk_offset, TIMER_PERIOD);
|
|
|
}
|
|
|
|
|
|
/* Update the next timeout time as difference between ttmr and ttcr */
|
|
@@ -69,7 +71,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
|
|
|
}
|
|
|
|
|
|
cpu_openrisc_count_update(cpu);
|
|
|
- now = or1k_timer->last_clk;
|
|
|
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
|
|
|
|
|
if ((cpu->env.ttmr & TTMR_TP) <= (or1k_timer->ttcr & TTMR_TP)) {
|
|
|
wait = TTMR_TP - (or1k_timer->ttcr & TTMR_TP) + 1;
|
|
@@ -110,7 +112,8 @@ static void openrisc_timer_cb(void *opaque)
|
|
|
case TIMER_NONE:
|
|
|
break;
|
|
|
case TIMER_INTR:
|
|
|
- or1k_timer->ttcr = 0;
|
|
|
+ /* Zero the count by applying a negative offset to the counter */
|
|
|
+ or1k_timer->ttcr_offset -= (cpu->env.ttmr & TTMR_TP);
|
|
|
break;
|
|
|
case TIMER_SHOT:
|
|
|
cpu_openrisc_count_stop(cpu);
|
|
@@ -137,17 +140,18 @@ static void openrisc_count_reset(void *opaque)
|
|
|
/* Reset the global timer state. */
|
|
|
static void openrisc_timer_reset(void *opaque)
|
|
|
{
|
|
|
- or1k_timer->ttcr = 0x00000000;
|
|
|
- or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
|
|
+ OpenRISCCPU *cpu = opaque;
|
|
|
+ cpu_openrisc_count_set(cpu, 0);
|
|
|
}
|
|
|
|
|
|
static const VMStateDescription vmstate_or1k_timer = {
|
|
|
.name = "or1k_timer",
|
|
|
- .version_id = 1,
|
|
|
- .minimum_version_id = 1,
|
|
|
+ .version_id = 2,
|
|
|
+ .minimum_version_id = 2,
|
|
|
.fields = (const VMStateField[]) {
|
|
|
VMSTATE_UINT32(ttcr, OR1KTimerState),
|
|
|
- VMSTATE_UINT64(last_clk, OR1KTimerState),
|
|
|
+ VMSTATE_UINT32(ttcr_offset, OR1KTimerState),
|
|
|
+ VMSTATE_UINT64(clk_offset, OR1KTimerState),
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
}
|
|
|
};
|