diff options
Diffstat (limited to 'hw/openrisc/cputimer.c')
-rw-r--r-- | hw/openrisc/cputimer.c | 62 |
1 files changed, 47 insertions, 15 deletions
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index febc469170..4c5415ff75 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -25,39 +25,56 @@ #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ -/* The time when TTCR changes */ -static uint64_t last_clk; -static int is_counting; +/* Tick Timer global state to allow all cores to be in sync */ +typedef struct OR1KTimerState { + uint32_t ttcr; + uint64_t last_clk; +} OR1KTimerState; +static OR1KTimerState *or1k_timer; + +void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val) +{ + or1k_timer->ttcr = val; +} + +uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu) +{ + return or1k_timer->ttcr; +} + +/* Add elapsed ticks to ttcr */ void cpu_openrisc_count_update(OpenRISCCPU *cpu) { uint64_t now; - if (!is_counting) { + if (!cpu->env.is_counting) { return; } now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - cpu->env.ttcr += (uint32_t)((now - last_clk) / TIMER_PERIOD); - last_clk = now; + or1k_timer->ttcr += (uint32_t)((now - or1k_timer->last_clk) + / TIMER_PERIOD); + or1k_timer->last_clk = now; } +/* Update the next timeout time as difference between ttmr and ttcr */ void cpu_openrisc_timer_update(OpenRISCCPU *cpu) { uint32_t wait; uint64_t now, next; - if (!is_counting) { + if (!cpu->env.is_counting) { return; } cpu_openrisc_count_update(cpu); - now = last_clk; + now = or1k_timer->last_clk; - if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { - wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; + if ((cpu->env.ttmr & TTMR_TP) <= (or1k_timer->ttcr & TTMR_TP)) { + wait = TTMR_TP - (or1k_timer->ttcr & TTMR_TP) + 1; wait += cpu->env.ttmr & TTMR_TP; } else { - wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); + wait = (cpu->env.ttmr & TTMR_TP) - (or1k_timer->ttcr & TTMR_TP); } next = now + (uint64_t)wait * TIMER_PERIOD; timer_mod(cpu->env.timer, next); @@ -66,7 +83,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu) void cpu_openrisc_count_start(OpenRISCCPU *cpu) { - is_counting = 1; + cpu->env.is_counting = 1; cpu_openrisc_count_update(cpu); } @@ -74,7 +91,7 @@ void cpu_openrisc_count_stop(OpenRISCCPU *cpu) { timer_del(cpu->env.timer); cpu_openrisc_count_update(cpu); - is_counting = 0; + cpu->env.is_counting = 0; } static void openrisc_timer_cb(void *opaque) @@ -93,7 +110,7 @@ static void openrisc_timer_cb(void *opaque) case TIMER_NONE: break; case TIMER_INTR: - cpu->env.ttcr = 0; + or1k_timer->ttcr = 0; break; case TIMER_SHOT: cpu_openrisc_count_stop(cpu); @@ -105,9 +122,24 @@ static void openrisc_timer_cb(void *opaque) cpu_openrisc_timer_update(cpu); } +static const VMStateDescription vmstate_or1k_timer = { + .name = "or1k_timer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ttcr, OR1KTimerState), + VMSTATE_UINT64(last_clk, OR1KTimerState), + VMSTATE_END_OF_LIST() + } +}; + void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu); cpu->env.ttmr = 0x00000000; - cpu->env.ttcr = 0x00000000; + + if (or1k_timer == NULL) { + or1k_timer = g_new0(OR1KTimerState, 1); + vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); + } } |