X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Fsim_avr.c;h=d3e67067266e87f789ca3a4363cd72efd906cc67;hb=dc3747065c3e00715808918b54337d99abba6fc3;hp=7f7a3abf1042cc9ccbf092f55070900732aa54c3;hpb=c1a849dc1b8a86c6d00970421b27756580ba6ac7;p=simavr diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 7f7a3ab..d3e6706 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -25,11 +25,14 @@ #include #include "sim_avr.h" #include "sim_core.h" +#include "sim_time.h" #include "sim_gdb.h" #include "avr_uart.h" #include "sim_vcd_file.h" #include "avr_mcu_section.h" +#define AVR_KIND_DECL +#include "sim_core_decl.h" int avr_init(avr_t * avr) { @@ -37,15 +40,22 @@ int avr_init(avr_t * avr) memset(avr->flash, 0xff, avr->flashend + 1); avr->data = malloc(avr->ramend + 1); memset(avr->data, 0, avr->ramend + 1); +#ifdef CONFIG_SIMAVR_TRACE + avr->trace_data = calloc(1, sizeof(struct avr_trace_data_t)); +#endif // cpu is in limbo before init is finished. avr->state = cpu_Limbo; - avr->frequency = 1000000; // can be overriden via avr_mcu_section + avr->frequency = 1000000; // can be overridden via avr_mcu_section if (avr->special_init) 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->log = 1; avr_reset(avr); return 0; } @@ -54,6 +64,10 @@ void avr_terminate(avr_t * avr) { if (avr->special_deinit) avr->special_deinit(avr); + if (avr->gdb) { + avr_deinit_gdb(avr); + avr->gdb = NULL; + } if (avr->vcd) { avr_vcd_close(avr->vcd); avr->vcd = NULL; @@ -74,7 +88,8 @@ void avr_reset(avr_t * avr) avr->sreg[i] = 0; if (avr->reset) avr->reset(avr); - + avr_interrupt_reset(avr); + avr_cycle_timer_reset(avr); avr_io_t * port = avr->io_port; while (port) { if (port->reset) @@ -93,7 +108,7 @@ void avr_sadly_crashed(avr_t *avr, uint8_t signal) avr_gdb_init(avr); } if (!avr->gdb) - exit(1); // no gdb ? + avr->state = cpu_Crashed; } static void _avr_io_command_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) @@ -131,15 +146,19 @@ static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_ static char * buf = NULL; static int size = 0, len = 0; - if (v == '\r') { + if (v == '\r' && buf) { + buf[len] = 0; printf("O:" "%s" "" "\n", buf); fflush(stdout); + len = 0; + return; } if (len + 1 >= size) { size += 128; buf = (char*)realloc(buf, size); } - buf[len++] = v; + if (v >= ' ') + buf[len++] = v; } void avr_set_console_register(avr_t * avr, avr_io_addr_t addr) @@ -148,25 +167,52 @@ void avr_set_console_register(avr_t * avr, avr_io_addr_t addr) avr_register_io_write(avr, addr, _avr_io_console_write, NULL); } -void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address) +void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, avr_flashaddr_t address) { + if (size > avr->flashend+1) { + fprintf(stderr, "avr_loadcode(): Attempted to load code of size %d but flash size is only %d.\n", + size, avr->flashend+1); + abort(); + } 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_pending_sleep_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; if (step) avr->state = cpu_Running; - uint16_t new_pc = avr->pc; + avr_flashaddr_t new_pc = avr->pc; if (avr->state == cpu_Running) { new_pc = avr_run_one(avr); @@ -178,10 +224,10 @@ int avr_run(avr_t * avr) // 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->interrupts.pending_wait++; avr->i_shadow = avr->sreg[S_I]; - // run the cycle timers, get the suggested sleeo time + // run the cycle timers, get the suggested sleep time // until the next timer is due avr_cycle_count_t sleep = avr_cycle_timer_process(avr); @@ -189,20 +235,15 @@ 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); + if (avr->log) + printf("simavr: sleeping with interrupts off, quitting gracefully\n"); + avr->state = cpu_Done; + return; } /* * 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' @@ -213,28 +254,77 @@ 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_pending_sleep_usec(avr, howLong); + if (usec > 0) { + usleep(usec); + } +} + +void avr_callback_run_raw(avr_t * avr) +{ + avr_flashaddr_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->interrupts.pending_wait++; + avr->i_shadow = avr->sreg[S_I]; + + // run the cycle timers, get the suggested sleep 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]) { + if (avr->log) + printf("simavr: sleeping with interrupts off, quitting gracefully\n"); + avr->state = cpu_Done; + return; + } + /* + * 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; } +avr_t * +avr_core_allocate( + const avr_t * core, + uint32_t coreLen) +{ + uint8_t * b = malloc(coreLen); + memcpy(b, core, coreLen); + return (avr_t *)b; +} -extern avr_kind_t tiny13; -extern avr_kind_t tiny2313; -extern avr_kind_t tiny25,tiny45,tiny85; -extern avr_kind_t mega48,mega88,mega168,mega328; -extern avr_kind_t mega164,mega324,mega644; -extern avr_kind_t mega128; - -avr_kind_t * avr_kind[] = { - &tiny13, - &tiny2313, - &tiny25, &tiny45, &tiny85, - &mega48, &mega88, &mega168, &mega328, - &mega164, &mega324, &mega644, - &mega128, - NULL -}; - -avr_t * avr_make_mcu_by_name(const char *name) +avr_t * +avr_make_mcu_by_name( + const char *name) { avr_kind_t * maker = NULL; for (int i = 0; avr_kind[i] && !maker; i++) { @@ -245,7 +335,7 @@ avr_t * avr_make_mcu_by_name(const char *name) } } if (!maker) { - fprintf(stderr, "%s: AVR '%s' now known\n", __FUNCTION__, name); + fprintf(stderr, "%s: AVR '%s' not known\n", __FUNCTION__, name); return NULL; }