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_PERIOD 50 /* 50 ns period for 20 MHz timer */
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)((now
- last_clk
) / TIMER_PERIOD
);
43 void cpu_openrisc_timer_update(OpenRISCCPU
*cpu
)
52 cpu_openrisc_count_update(cpu
);
55 if ((cpu
->env
.ttmr
& TTMR_TP
) <= (cpu
->env
.ttcr
& TTMR_TP
)) {
56 wait
= TTMR_TP
- (cpu
->env
.ttcr
& TTMR_TP
) + 1;
57 wait
+= cpu
->env
.ttmr
& TTMR_TP
;
59 wait
= (cpu
->env
.ttmr
& TTMR_TP
) - (cpu
->env
.ttcr
& TTMR_TP
);
61 next
= now
+ (uint64_t)wait
* TIMER_PERIOD
;
62 timer_mod(cpu
->env
.timer
, next
);
65 void cpu_openrisc_count_start(OpenRISCCPU
*cpu
)
68 cpu_openrisc_count_update(cpu
);
71 void cpu_openrisc_count_stop(OpenRISCCPU
*cpu
)
73 timer_del(cpu
->env
.timer
);
74 cpu_openrisc_count_update(cpu
);
78 static void openrisc_timer_cb(void *opaque
)
80 OpenRISCCPU
*cpu
= opaque
;
82 if ((cpu
->env
.ttmr
& TTMR_IE
) &&
83 timer_expired(cpu
->env
.timer
, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
))) {
84 CPUState
*cs
= CPU(cpu
);
86 cpu
->env
.ttmr
|= TTMR_IP
;
87 cs
->interrupt_request
|= CPU_INTERRUPT_TIMER
;
90 switch (cpu
->env
.ttmr
& TTMR_M
) {
97 cpu_openrisc_count_stop(cpu
);
103 cpu_openrisc_timer_update(cpu
);
106 void cpu_openrisc_clock_init(OpenRISCCPU
*cpu
)
108 cpu
->env
.timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, &openrisc_timer_cb
, cpu
);
109 cpu
->env
.ttmr
= 0x00000000;
110 cpu
->env
.ttcr
= 0x00000000;