From 3c5e1ae3f560ba1568da247f4e835206ff12a264 Mon Sep 17 00:00:00 2001 From: bsekisser Date: Tue, 9 Sep 2014 17:53:56 -0400 Subject: [PATCH] Changes to allow for free run in core between cycle timers with per interval limiting. Average cycle times drop by about upwards of 50-60+ cycles per emulated cycle, dependant on usage. sim_avr.h: struct avr_t changed. added members run_cycle_count and run_cycle_limit. run_cycle_count is number of cycles till next cycle timer. run_cycle_limit is maximum number of cycles to run per interval. sim_core.c: avr_run_one * run_one_again label added at top. * clause added at end which loops to run_one_again given that the core is still in a cpu_Running state, run_cycle_count is greater than cycles, and no interrups are pending. sim_cycle_timers.c: * static avr_cycle_timer_return_sleep_run_cycles_limited() added. run_cycle_count is bounded to run_cycle_limit. returns sleep count unbounded, preserving original behavior. * static avr_cycle_timer_reset_sleep_run_cycles_limited() added. sets new run_cycle_count based on present list of cycle timers. * avr_cycle_timer_reset() changed. run_cycle_count and run_cycle_limit is set to default values. * avr_cycle_timer_register() changed. * avr_cycle_timer_cancel() changed. * avr_cycle_timer_process() changed. call the relevant function to set/maintain run_cycle_count. modified: simavr/sim/sim_avr.c modified: simavr/sim/sim_avr.h modified: simavr/sim/sim_cycle_timers.c --- simavr/sim/sim_avr.h | 5 ++++ simavr/sim/sim_core.c | 11 ++++++++ simavr/sim/sim_cycle_timers.c | 51 ++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index 07985e1..7b95bd5 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -162,6 +162,11 @@ typedef struct avr_t { // like, sleeping. avr_cycle_count_t cycle; // current cycle + // these next two allow the core to freely run between cycle timers and also allows + // for a maximum run cycle limit... run_cycle_count is set during cycle timer processing. + avr_cycle_count_t run_cycle_count; // cycles to run before next timer + avr_cycle_count_t run_cycle_limit; // maximum run cycle interval limit + /** * 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 diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index f740aa5..c4e7b3e 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -581,6 +581,7 @@ static inline int _avr_is_instruction_32_bits(avr_t * avr, avr_flashaddr_t pc) */ avr_flashaddr_t avr_run_one(avr_t * avr) { +run_one_again: #if CONFIG_SIMAVR_TRACE /* * this traces spurious reset or bad jumps @@ -1402,6 +1403,16 @@ avr_flashaddr_t avr_run_one(avr_t * avr) } avr->cycle += cycle; + + if( (avr->state == cpu_Running) && + (avr->run_cycle_count > cycle) && + !(avr->sreg[S_I] && avr_has_pending_interrupts(avr)) ) + { + avr->run_cycle_count -= cycle; + avr->pc = new_pc; + goto run_one_again; + } + return new_pc; } diff --git a/simavr/sim/sim_cycle_timers.c b/simavr/sim/sim_cycle_timers.c index 1064dc5..93cf265 100644 --- a/simavr/sim/sim_cycle_timers.c +++ b/simavr/sim/sim_cycle_timers.c @@ -46,6 +46,8 @@ } \ } +#define DEFAULT_SLEEP_CYCLES 1000 + void avr_cycle_timer_reset( struct avr_t * avr) @@ -57,6 +59,41 @@ avr_cycle_timer_reset( avr_cycle_timer_slot_p t = &pool->timer_slots[i]; QUEUE(pool->timer_free, t); } + avr->run_cycle_count = 1; + avr->run_cycle_limit = 1; +} + +static avr_cycle_count_t +avr_cycle_timer_return_sleep_run_cycles_limited( + avr_t *avr, + avr_cycle_count_t sleep_cycle_count) +{ + // run_cycle_count is bound to run_cycle_limit but NOT less than 1 cycle... + // this is not an error!.. unless you like deadlock. + avr_cycle_count_t run_cycle_count = ((avr->run_cycle_limit >= sleep_cycle_count) ? + sleep_cycle_count : avr->run_cycle_limit); + avr->run_cycle_count = run_cycle_count ? run_cycle_count : 1; + + // sleep cycles are returned unbounded thus preserving original behavior. + return(sleep_cycle_count); +} + +static void +avr_cycle_timer_reset_sleep_run_cycles_limited( + avr_t *avr) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + avr_cycle_count_t sleep_cycle_count = DEFAULT_SLEEP_CYCLES; + + if(pool->timer) { + if(pool->timer->when > avr->cycle) { + sleep_cycle_count = pool->timer->when - avr->cycle; + } else { + sleep_cycle_count = 0; + } + } + + avr_cycle_timer_return_sleep_run_cycles_limited(avr, sleep_cycle_count); } // no sanity checks checking here, on purpose @@ -112,6 +149,7 @@ avr_cycle_timer_register( return; } avr_cycle_timer_insert(avr, when, timer, param); + avr_cycle_timer_reset_sleep_run_cycles_limited(avr); } void @@ -143,6 +181,7 @@ avr_cycle_timer_cancel( last = t; t = t->next; } + avr_cycle_timer_reset_sleep_run_cycles_limited(avr); } /* @@ -179,15 +218,12 @@ avr_cycle_timer_process( { avr_cycle_timer_pool_t * pool = &avr->cycle_timers; - if (!pool->timer) - return (avr_cycle_count_t)1000; - - do { + if (pool->timer) do { avr_cycle_timer_slot_p t = pool->timer; avr_cycle_count_t when = t->when; if (when > avr->cycle) - return t->when - avr->cycle; + return avr_cycle_timer_return_sleep_run_cycles_limited(avr, when - avr->cycle); // detach from active timers pool->timer = t->next; @@ -206,5 +242,8 @@ avr_cycle_timer_process( QUEUE(pool->timer_free, t); } while (pool->timer); - return (avr_cycle_count_t)1000; + // original behavior was to return 1000 cycles when no timers were present... + // run_cycles are bound to at least one cycle but no more than requested limit... + // value passed here is returned unbounded, thus preserving original behavior. + return avr_cycle_timer_return_sleep_run_cycles_limited(avr, DEFAULT_SLEEP_CYCLES); } -- 2.39.5