X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Fsim_avr.c;h=d3e67067266e87f789ca3a4363cd72efd906cc67;hb=dc3747065c3e00715808918b54337d99abba6fc3;hp=73883d4b3304c10027760abb1af7e09e468f58c5;hpb=c8c74557657e0b89904538344f2127128c95d62a;p=simavr diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 73883d4..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,26 +40,42 @@ 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; } void avr_terminate(avr_t * avr) { - if (avr->vcd) + 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; + avr->vcd = NULL; + } avr_deallocate_ios(avr); - free(avr->flash); - free(avr->data); + if (avr->flash) free(avr->flash); + if (avr->data) free(avr->data); avr->flash = avr->data = NULL; } @@ -69,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) @@ -88,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) @@ -121,25 +141,78 @@ void avr_set_command_register(avr_t * avr, avr_io_addr_t addr) avr_register_io_write(avr, addr, _avr_io_command_write, NULL); } -void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address) +static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + static char * buf = NULL; + static int size = 0, len = 0; + + 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); + } + if (v >= ' ') + buf[len++] = v; +} + +void avr_set_console_register(avr_t * avr, avr_io_addr_t addr) { + if (addr) + avr_register_io_write(avr, addr, _avr_io_console_write, NULL); +} + +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; +} -int avr_run(avr_t * avr) +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)) + ; +} + +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); @@ -151,18 +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 IO modules that wants it - avr_io_t * port = avr->io_port; - while (port) { - if (port->run) - port->run(port); - port = port->next; - } - - // 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); @@ -170,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' @@ -194,28 +254,77 @@ int avr_run(avr_t * avr) if (step) avr->state = cpu_StepDone; - return avr->state; } +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); + } +} -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; +void avr_callback_run_raw(avr_t * avr) +{ + avr_flashaddr_t new_pc = avr->pc; -avr_kind_t * avr_kind[] = { - &tiny13, - &tiny2313, - &tiny25, &tiny45, &tiny85, - &mega48, &mega88, &mega168, &mega328, - &mega164, &mega324, &mega644, - &mega128, - NULL -}; + 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; +} -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++) { @@ -226,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; }