Commit 8e195b43da0db4f2e9bd6f56cf68ba91b57676e2
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).

2 files changed:
simavr/sim/sim_avr.c
simavr/sim/sim_avr.h

index fe1f007b4d38fdc89454fb85fab3512e00e6cb91..37fae8f4d554c3404b227b3d85e6787f844401a0 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 199af292309160e76fec637a34e379c68a908799..f7ac26d32168b9a76c39dfdc854f0d9c7b20dd73 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);