2 * QEMU OpenRISC timer support
4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 #include "qemu/timer.h"
25 #define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */
27 /* The time when TTCR changes */
28 static uint64_t last_clk
;
29 static int is_counting
;
31 void cpu_openrisc_count_update(OpenRISCCPU
*cpu
)
38 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
39 cpu
->env
.ttcr
+= (uint32_t)muldiv64(now
- last_clk
, TIMER_FREQ
,
44 void cpu_openrisc_timer_update(OpenRISCCPU
*cpu
)
53 cpu_openrisc_count_update(cpu
);
56 if ((cpu
->env
.ttmr
& TTMR_TP
) <= (cpu
->env
.ttcr
& TTMR_TP
)) {
57 wait
= TTMR_TP
- (cpu
->env
.ttcr
& TTMR_TP
) + 1;
58 wait
+= cpu
->env
.ttmr
& TTMR_TP
;
60 wait
= (cpu
->env
.ttmr
& TTMR_TP
) - (cpu
->env
.ttcr
& TTMR_TP
);
62 next
= now
+ muldiv64(wait
, get_ticks_per_sec(), TIMER_FREQ
);
63 timer_mod(cpu
->env
.timer
, next
);
66 void cpu_openrisc_count_start(OpenRISCCPU
*cpu
)
69 cpu_openrisc_count_update(cpu
);
72 void cpu_openrisc_count_stop(OpenRISCCPU
*cpu
)
74 timer_del(cpu
->env
.timer
);
75 cpu_openrisc_count_update(cpu
);
79 static void openrisc_timer_cb(void *opaque
)
81 OpenRISCCPU
*cpu
= opaque
;
83 if ((cpu
->env
.ttmr
& TTMR_IE
) &&
84 timer_expired(cpu
->env
.timer
, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
))) {
85 CPUState
*cs
= CPU(cpu
);
87 cpu
->env
.ttmr
|= TTMR_IP
;
88 cs
->interrupt_request
|= CPU_INTERRUPT_TIMER
;
91 switch (cpu
->env
.ttmr
& TTMR_M
) {
98 cpu_openrisc_count_stop(cpu
);
104 cpu_openrisc_timer_update(cpu
);
107 void cpu_openrisc_clock_init(OpenRISCCPU
*cpu
)
109 cpu
->env
.timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, &openrisc_timer_cb
, cpu
);
110 cpu
->env
.ttmr
= 0x00000000;
111 cpu
->env
.ttcr
= 0x00000000;