Commit 9475768fbc5ceebb6b648909040e48c5de7efa03
authorMichel Pollet <buserror@gmail.com>
Thu, 17 Dec 2009 19:56:01 +0000 (19:56 +0000)
committerMichel Pollet <buserror@gmail.com>
Thu, 17 Dec 2009 19:56:01 +0000 (19:56 +0000)
Ensure that a timer when called does not continue to have a
"call next" that is smaller than the current cycle, bogging
down the rest of the core.
Also ensure the cycle is always incremented by at least one
when sleeping, even if a cycle callback is called.

Signed-off-by: Michel Pollet <buserror@gmail.com>
simavr/sim/sim_avr.c

index ae480ffe7cbdaf13492d7015f77b622e838bf7c4..dbd06c21389fa456c0b0be6b35ae0db922d01f2f 100644 (file)
@@ -124,23 +124,23 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
 }
 
 // converts a number of usec to a number of machine cycles, at current speed
-uint64_t avr_usec_to_cycles(avr_t * avr, uint32_t usec)
+avr_cycle_count_t avr_usec_to_cycles(avr_t * avr, uint32_t usec)
 {
-       return avr->frequency * (uint64_t)usec / 1000000;
+       return avr->frequency * (avr_cycle_count_t)usec / 1000000;
 }
 
-uint32_t avr_cycles_to_usec(avr_t * avr, uint64_t cycles)
+uint32_t avr_cycles_to_usec(avr_t * avr, avr_cycle_count_t cycles)
 {
        return 1000000 * cycles / avr->frequency;
 }
 
 // converts a number of hz (to megahertz etc) to a number of cycle
-uint64_t avr_hz_to_cycles(avr_t * avr, uint32_t hz)
+avr_cycle_count_t avr_hz_to_cycles(avr_t * avr, uint32_t hz)
 {
        return avr->frequency / hz;
 }
 
-void avr_cycle_timer_register(avr_t * avr, uint64_t when, avr_cycle_timer_t timer, void * param)
+void avr_cycle_timer_register(avr_t * avr, avr_cycle_count_t when, avr_cycle_timer_t timer, void * param)
 {
        avr_cycle_timer_cancel(avr, timer, param);
 
@@ -185,18 +185,18 @@ void avr_cycle_timer_cancel(avr_t * avr, avr_cycle_timer_t timer, void * param)
  * clear the ones that wants it, and calculate the next
  * potential cycle we could sleep for...
  */
-static uint64_t avr_cycle_timer_check(avr_t * avr)
+static avr_cycle_count_t avr_cycle_timer_check(avr_t * avr)
 {
        if (!avr->cycle_timer_map)
-               return (uint32_t)-1;
+               return (avr_cycle_count_t)-1;
 
-       uint64_t min = (uint64_t)-1;
+       avr_cycle_count_t min = (avr_cycle_count_t)-1;
 
        for (int i = 0; i < 32; i++) {
                if (!(avr->cycle_timer_map & (1 << i)))
                        continue;
-
-               if (avr->cycle_timer[i].when <= avr->cycle) {
+               // do it several times, in case we're late
+               while (avr->cycle_timer[i].when && avr->cycle_timer[i].when <= avr->cycle) {
                        // call it
                        avr->cycle_timer[i].when =
                                        avr->cycle_timer[i].timer(avr,
@@ -208,10 +208,10 @@ static uint64_t avr_cycle_timer_check(avr_t * avr)
                                avr->cycle_timer[i].param = NULL;
                                avr->cycle_timer[i].when = 0;
                                avr->cycle_timer_map &= ~(1 << i);
-                               continue;
+                               break;
                        }
                }
-               if (avr->cycle_timer[i].when < min)
+               if (avr->cycle_timer[i].when && avr->cycle_timer[i].when < min)
                        min = avr->cycle_timer[i].when;
        }
        return min - avr->cycle;
@@ -257,18 +257,20 @@ int avr_run(avr_t * avr)
        if (avr->state == cpu_Sleeping) {
                if (!avr->sreg[S_I]) {
                        printf("simavr: sleeping with interrupts off, quitting gracefully\n");
+                       avr_terminate(avr);
                        exit(0);
                }
                /*
                 * try to sleep for as long as we can (?)
                 */
                uint32_t usec = avr_cycles_to_usec(avr, sleep);
+       //      printf("sleep usec %d cycles %d\n", usec, sleep);
                if (avr->gdb) {
                        while (avr_gdb_processor(avr, usec))
                                ;
                } else
                        usleep(usec);
-               avr->cycle += sleep;
+               avr->cycle += 1 + sleep;
        }
        // Interrupt servicing might change the PC too
        if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {