From 7ef9679874d24f3062bf64525d9dd13d45dc2f27 Mon Sep 17 00:00:00 2001
From: Blue Swirl <blauwirbel@gmail.com>
Date: Fri, 2 Apr 2010 15:54:26 +0000
Subject: [PATCH] sparc32: improve timer implementation

Timer with zero period (free-run) will never match.

Timer counting starts with tick value of 0x200, not from 0,
so the period must calculated from one tick less than the limit.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
 hw/slavio_timer.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index ef36fe4..d787553 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -88,8 +88,8 @@ typedef struct TimerContext {
 #define TIMER_MAX_COUNT32  0x7ffffe00ULL
 #define TIMER_REACHED      0x80000000
 #define TIMER_PERIOD       500ULL // 500ns
-#define LIMIT_TO_PERIODS(l) ((l) >> 9)
-#define PERIODS_TO_LIMIT(l) ((l) << 9)
+#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
+#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
 
 static int slavio_timer_is_user(TimerContext *tc)
 {
@@ -127,7 +127,10 @@ static void slavio_timer_irq(void *opaque)
 
     slavio_timer_get_out(t);
     DPRINTF("callback: count %x%08x\n", t->counthigh, t->count);
-    t->reached = TIMER_REACHED;
+    /* if limit is 0 (free-run), there will be no match */
+    if (t->limit != 0) {
+        t->reached = TIMER_REACHED;
+    }
     /* there is no interrupt if user timer or free-run */
     if (!slavio_timer_is_user(tc) && t->limit != 0) {
         qemu_irq_raise(t->irq);
-- 
1.5.6.5
