summaryrefslogtreecommitdiffstats
path: root/target-openrisc
diff options
context:
space:
mode:
authorSebastian Macke2013-10-22 02:12:41 +0200
committerJia Liu2013-11-20 14:46:45 +0100
commitd51552176a2ab5e80a211514aa1339fe2575ec2a (patch)
treef272c169ec8acfdd998b69d7d4eb1ab9af58708d /target-openrisc
parenttarget-openrisc: Correct wrong epcr register in interrupt handler (diff)
downloadqemu-d51552176a2ab5e80a211514aa1339fe2575ec2a.tar.gz
qemu-d51552176a2ab5e80a211514aa1339fe2575ec2a.tar.xz
qemu-d51552176a2ab5e80a211514aa1339fe2575ec2a.zip
openrisc-timer: Reduce overhead, Separate clock update functions
The clock value is only evaluated when really necessary reducing the overhead of the timer handling. This also solves a problem in the way the Linux kernel handles the timer and the expected accuracy. The old version could lead to inaccurate timings. Signed-off-by: Sebastian Macke <sebastian@macke.de> Reviewed-by: Jia Liu <proljc@gmail.com> Signed-off-by: Jia Liu <proljc@gmail.com>
Diffstat (limited to 'target-openrisc')
-rw-r--r--target-openrisc/cpu.h1
-rw-r--r--target-openrisc/sys_helper.c38
2 files changed, 19 insertions, 20 deletions
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 8fd0bc0bf0..0f9efdf6de 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -373,6 +373,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu);
/* hw/openrisc_timer.c */
void cpu_openrisc_clock_init(OpenRISCCPU *cpu);
void cpu_openrisc_count_update(OpenRISCCPU *cpu);
+void cpu_openrisc_timer_update(OpenRISCCPU *cpu);
void cpu_openrisc_count_start(OpenRISCCPU *cpu);
void cpu_openrisc_count_stop(OpenRISCCPU *cpu);
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
index cccbc0e939..f1165885d9 100644
--- a/target-openrisc/sys_helper.c
+++ b/target-openrisc/sys_helper.c
@@ -127,33 +127,31 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
break;
case TO_SPR(10, 0): /* TTMR */
{
+ if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) {
+ switch (rb & TTMR_M) {
+ case TIMER_NONE:
+ cpu_openrisc_count_stop(cpu);
+ break;
+ case TIMER_INTR:
+ case TIMER_SHOT:
+ case TIMER_CONT:
+ cpu_openrisc_count_start(cpu);
+ break;
+ default:
+ break;
+ }
+ }
+
int ip = env->ttmr & TTMR_IP;
if (rb & TTMR_IP) { /* Keep IP bit. */
- env->ttmr = (rb & ~TTMR_IP) + ip;
+ env->ttmr = (rb & ~TTMR_IP) | ip;
} else { /* Clear IP bit. */
env->ttmr = rb & ~TTMR_IP;
cs->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
- cpu_openrisc_count_update(cpu);
-
- switch (env->ttmr & TTMR_M) {
- case TIMER_NONE:
- cpu_openrisc_count_stop(cpu);
- break;
- case TIMER_INTR:
- cpu_openrisc_count_start(cpu);
- break;
- case TIMER_SHOT:
- cpu_openrisc_count_start(cpu);
- break;
- case TIMER_CONT:
- cpu_openrisc_count_start(cpu);
- break;
- default:
- break;
- }
+ cpu_openrisc_timer_update(cpu);
}
break;
@@ -162,7 +160,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
if (env->ttmr & TIMER_NONE) {
return;
}
- cpu_openrisc_count_start(cpu);
+ cpu_openrisc_timer_update(cpu);
break;
default: