simavr: Improved accuracy of sleep durations
authorJakob Gruber <jakob.gruber@gmail.com>
Thu, 19 Jul 2012 21:37:02 +0000 (23:37 +0200)
committerJakob Gruber <jakob.gruber@gmail.com>
Thu, 19 Jul 2012 21:46:19 +0000 (23:46 +0200)
This commit solves (or at least improves) an issue that occurs when
short sleep times are requested in avr_callback_sleep_*. The operating
system cannot accurately handle short sleep requests, and sending many
short requests takes significantly longer than requesting the equivalent
time in longer bursts. This can be observed by running the board_hd77480
example - the counter is much slower when vcd recording is turned on
(= short sleep requests) than when it is turned off (= long sleep
requests).

We improve this situation by accumulating sleep requests until a certain
minimum count of pending usecs is reached which can be handled somewhat
accurately (200 microseconds worked well for me).

simavr/sim/sim_avr.c
simavr/sim/sim_avr.h

index fe1f007..37fae8f 100644 (file)
@@ -173,9 +173,25 @@ void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, avr_flashaddr_t ad
        memcpy(avr->flash + address, code, size);
 }
 
+/**
+ * Accumulates sleep requests (and returns a sleep time of 0) until
+ * a minimum count of requested sleep microseconds are reached
+ * (low amounts cannot be handled accurately).
+ */
+static inline uint32_t avr_pending_sleep_usec(avr_t * avr, avr_cycle_count_t howLong)
+{
+       avr->sleep_usec += avr_cycles_to_usec(avr, howLong);
+       uint32_t usec = avr->sleep_usec;
+       if (usec > 200) {
+               avr->sleep_usec = 0;
+               return usec;
+       }
+       return 0;
+}
+
 void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong)
 {
-       uint32_t usec = avr_cycles_to_usec(avr, howLong);
+       uint32_t usec = avr_pending_sleep_usec(avr, howLong);
        while (avr_gdb_processor(avr, usec))
                ;
 }
@@ -239,8 +255,10 @@ void avr_callback_run_gdb(avr_t * avr)
 
 void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong)
 {
-       uint32_t usec = avr_cycles_to_usec(avr, howLong);
-       usleep(usec);
+       uint32_t usec = avr_pending_sleep_usec(avr, howLong);
+       if (usec > 0) {
+               usleep(usec);
+       }
 }
 
 void avr_callback_run_raw(avr_t * avr)
index 199af29..f7ac26d 100644 (file)
@@ -139,6 +139,13 @@ typedef struct avr_t {
        // not only to "cycles that runs" but also "cycles that might have run"
        // like, sleeping.
        avr_cycle_count_t       cycle;          // current cycle
+
+       /**
+        * Sleep requests are accumulated in sleep_usec until the minimum sleep value
+        * is reached, at which point sleep_usec is cleared and the sleep request
+        * is passed on to the operating system.
+        */
+       uint32_t sleep_usec;
        
        // called at init time
        void (*init)(struct avr_t * avr);