Commit 6660aba00a898ff4db6c689e35e7fd03b4f9d47d
authorDelio Brignoli <brignoli.delio@gmail.com>
Fri, 20 Oct 2017 09:22:45 +0000 (11:22 +0200)
committerMichel Pollet <github.com@pollet.net>
Fri, 27 Oct 2017 07:07:14 +0000 (08:07 +0100)
To avoid simulated time and wall clock time to diverge over time
this implementation tries to keep them in sync (roughly) by sleeping
for the time required to match the expected sleep deadline
in wall clock time.

The simulation will burst as fast as the host CPU will allow
until the simulated MCU sleeps, at which point avr_callback_sleep_raw()
sleeps for the time required to sync wall clock time with simulated MCU
time.

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

index 9999a174a4a920b3c22347951efed114f489dfdf..6106df6041ebf22411a20e4ba3571ed3327dfa38 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 #include "sim_avr.h"
 #include "sim_core.h"
@@ -148,6 +149,10 @@ avr_reset(
                avr->sreg[i] = 0;
        avr_interrupt_reset(avr);
        avr_cycle_timer_reset(avr);
+       /* Take simulation start time */
+       struct timespec tp;
+       clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
+       avr->sim_start_time_ns = tp.tv_sec*1E9+tp.tv_nsec;
        if (avr->reset)
                avr->reset(avr);
        avr_io_t * port = avr->io_port;
@@ -311,15 +316,30 @@ avr_callback_run_gdb(
 
 }
 
+/*
+To avoid simulated time and wall clock time to diverge over time
+this function tries to keep them in sync (roughly) by sleeping
+for the time required to match the expected sleep deadline
+in wall clock time.
+*/
 void
 avr_callback_sleep_raw(
-               avr_t * avr,
-               avr_cycle_count_t howLong)
+               avr_t *avr,
+               avr_cycle_count_t how_long)
 {
-       uint32_t usec = avr_pending_sleep_usec(avr, howLong);
-       if (usec > 0) {
-               usleep(usec);
+       struct timespec tp;
+
+       /* figure out how long we should wait to match the sleep deadline */
+       uint64_t deadline_ns = avr_cycles_to_nsec(avr, avr->cycle + how_long);
+       clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
+       uint64_t runtime_ns = (tp.tv_sec*1E9+tp.tv_nsec) - avr->sim_start_time_ns;
+       if (runtime_ns >= deadline_ns) {
+               return;
        }
+
+       uint64_t sleep_us = (deadline_ns - runtime_ns)/1000;
+       usleep(sleep_us);
+       return;
 }
 
 void
index aedffb2190a7a8bb8179af9a2d79e5323506c0c1..92459dc0f65b4d86d24cd9688230a660e2948261 100644 (file)
@@ -201,6 +201,7 @@ typedef struct avr_t {
         * is passed on to the operating system.
         */
        uint32_t                        sleep_usec;
+       uint64_t                        sim_start_time_ns;
 
        // called at init time
        void (*init)(struct avr_t * avr);