From 335869fab028466961751b8e2a5a9ebd1ac50d46 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Tue, 22 Feb 2011 12:48:31 +0000 Subject: [PATCH] core: Introduce run() and sleep() callbacks It seems that the default 'run_avr' function was penalized by some tests made that were only useful when gdb was active. This patch introduces two version of the critical run_avr, one for "raw" running, and one for gdb. It also introduces a sleep() callback for similar reasons. Ir can also be used to run unit testing at 100% speed instead of having random sleep code during execution. Signed-off-by: Michel Pollet --- simavr/sim/sim_avr.c | 74 ++++++++++++++++++++++++++++++++++++++------ simavr/sim/sim_avr.h | 25 +++++++++++++++ simavr/sim/sim_gdb.c | 3 ++ 3 files changed, 93 insertions(+), 9 deletions(-) diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index d5611ba..e13117d 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -45,6 +45,9 @@ int avr_init(avr_t * avr) avr->special_init(avr); if (avr->init) avr->init(avr); + // set default (non gdb) fast callbacks + avr->run = avr_callback_run_raw; + avr->sleep = avr_callback_sleep_raw; avr->state = cpu_Running; avr_reset(avr); return 0; @@ -158,13 +161,19 @@ void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address) memcpy(avr->flash + address, code, size); } +void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong) +{ + uint32_t usec = avr_cycles_to_usec(avr, howLong); + while (avr_gdb_processor(avr, usec)) + ; +} -int avr_run(avr_t * avr) +void avr_callback_run_gdb(avr_t * avr) { avr_gdb_processor(avr, avr->state == cpu_Stopped); if (avr->state == cpu_Stopped) - return avr->state; + return ; // if we are stepping one instruction, we "run" for one.. int step = avr->state == cpu_Step; @@ -201,13 +210,7 @@ int avr_run(avr_t * avr) /* * 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->sleep(avr, sleep); avr->cycle += 1 + sleep; } // Interrupt servicing might change the PC too, during 'sleep' @@ -218,6 +221,59 @@ int avr_run(avr_t * avr) if (step) avr->state = cpu_StepDone; +} + +void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong) +{ + uint32_t usec = avr_cycles_to_usec(avr, howLong); + usleep(usec); +} + +void avr_callback_run_raw(avr_t * avr) +{ + + uint16_t new_pc = avr->pc; + + if (avr->state == cpu_Running) { + new_pc = avr_run_one(avr); +#if CONFIG_SIMAVR_TRACE + avr_dump_state(avr); +#endif + } + + // if we just re-enabled the interrupts... + // double buffer the I flag, to detect that edge + if (avr->sreg[S_I] && !avr->i_shadow) + avr->pending_wait++; + avr->i_shadow = avr->sreg[S_I]; + + // run the cycle timers, get the suggested sleeo time + // until the next timer is due + avr_cycle_count_t sleep = avr_cycle_timer_process(avr); + + avr->pc = new_pc; + + 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 (?) + */ + avr->sleep(avr, sleep); + avr->cycle += 1 + sleep; + } + // Interrupt servicing might change the PC too, during 'sleep' + if (avr->state == cpu_Running || avr->state == cpu_Sleeping) + avr_service_interrupts(avr); +} + + +int avr_run(avr_t * avr) +{ + avr->run(avr); return avr->state; } diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index 32426dd..ae1a3ab 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -107,6 +107,22 @@ typedef struct avr_t { // called at reset time void (*reset)(struct avr_t * avr); + /* + * Default AVR core run function. + * Two modes are available, a "raw" run that goes as fast as + * it can, and a "gdb" mode that also watchouts for gdb events + * and is a little bit slower. + */ + void (*run)(struct avr_t * avr); + + /* + * Sleep default behaviour. + * In "raw" mode, it calls usleep, in gdb mode, it waits + * for howLong for gdb command on it's sockets. + */ + void (*sleep)(struct avr_t * avr, avr_cycle_count_t howLong); + + // Mirror of the SREG register, to facilitate the access to bits // in the opcode decoder. // This array is re-synthetized back/forth when SREG changes @@ -267,6 +283,15 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr); // this might activate gdb server void avr_sadly_crashed(avr_t *avr, uint8_t signal); + +/* + * These are callbacks for the two 'main' bahaviour in simavr + */ +void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong); +void avr_callback_run_gdb(avr_t * avr); +void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong); +void avr_callback_run_raw(avr_t * avr); + #ifdef __cplusplus }; #endif diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index 9bec4b5..3768022 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -425,6 +425,9 @@ int avr_gdb_init(avr_t * avr) g->avr = avr; g->s = -1; avr->gdb = g; + // change default run behaviour to use the slightly slower versions + avr->run = avr_callback_run_gdb; + avr->sleep = avr_callback_sleep_gdb; return 0; } -- 2.39.5