#include "sim_avr.h"
#include "sim_core.h"
#include "sim_gdb.h"
+#include "avr_uart.h"
+#include "sim_vcd_file.h"
+#include "avr_mcu_section.h"
int avr_init(avr_t * avr)
// cpu is in limbo before init is finished.
avr->state = cpu_Limbo;
avr->frequency = 1000000; // can be overriden 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_reset(avr);
return 0;
}
+void avr_terminate(avr_t * avr)
+{
+ if (avr->special_deinit)
+ avr->special_deinit(avr);
+ if (avr->vcd) {
+ avr_vcd_close(avr->vcd);
+ avr->vcd = NULL;
+ }
+ avr_deallocate_ios(avr);
+
+ if (avr->flash) free(avr->flash);
+ if (avr->data) free(avr->data);
+ avr->flash = avr->data = NULL;
+}
+
void avr_reset(avr_t * avr)
{
memset(avr->data, 0x0, avr->ramend + 1);
void avr_sadly_crashed(avr_t *avr, uint8_t signal)
{
+ printf("%s\n", __FUNCTION__);
avr->state = cpu_Stopped;
if (avr->gdb_port) {
// enable gdb server, and wait
exit(1); // no gdb ?
}
-void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
-{
- memcpy(avr->flash + address, code, size);
-}
-
-void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
+static void _avr_io_command_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
{
- if (addr > avr->ramend) {
- printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
- CRASH();
- }
- if (addr < 32) {
- printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
- CRASH();
- }
-#if AVR_STACK_WATCH
- /*
- * this checks that the current "function" is not doctoring the stack frame that is located
- * higher on the stack than it should be. It's a sign of code that has overrun it's stack
- * frame and is munching on it's own return address.
- */
- if (avr->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
- printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
- }
-#endif
- avr->data[addr] = v;
-}
+ printf("%s %02x\n", __FUNCTION__, v);
+ switch (v) {
+ case SIMAVR_CMD_VCD_START_TRACE:
+ if (avr->vcd)
+ avr_vcd_start(avr->vcd);
+ break;
+ case SIMAVR_CMD_VCD_STOP_TRACE:
+ if (avr->vcd)
+ avr_vcd_stop(avr->vcd);
+ break;
+ case SIMAVR_CMD_UART_LOOPBACK: {
+ avr_irq_t * src = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT);
+ avr_irq_t * dst = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT);
+ if (src && dst) {
+ printf("%s activating uart local echo IRQ src %p dst %p\n", __FUNCTION__, src, dst);
+ avr_connect_irq(src, dst);
+ }
+ } break;
-uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
-{
- if (addr > avr->ramend) {
- printf("*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, avr->ramend);
- CRASH();
}
- return avr->data[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)
+void avr_set_command_register(avr_t * avr, avr_io_addr_t addr)
{
- return avr->frequency * (uint64_t)usec / 1000000;
+ if (addr)
+ avr_register_io_write(avr, addr, _avr_io_command_write, NULL);
}
-uint32_t avr_cycles_to_usec(avr_t * avr, uint64_t cycles)
+static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
{
- return 1000000 * cycles / avr->frequency;
-}
+ static char * buf = NULL;
+ static int size = 0, len = 0;
-// 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)
-{
- return avr->frequency / hz;
-}
-
-void avr_cycle_timer_register(avr_t * avr, uint64_t when, avr_cycle_timer_t timer, void * param)
-{
- avr_cycle_timer_cancel(avr, timer, param);
-
- if (avr->cycle_timer_map == 0xffffffff) {
- fprintf(stderr, "avr_cycle_timer_register is full!\n");
- return;
+ if (v == '\r') {
+ printf("O:" "%s" "" "\n", buf);
+ fflush(stdout);
}
- when += avr->cycle;
- for (int i = 0; i < 32; i++)
- if (!(avr->cycle_timer_map & (1 << i))) {
- avr->cycle_timer[i].timer = timer;
- avr->cycle_timer[i].param = param;
- avr->cycle_timer[i].when = when;
- avr->cycle_timer_map |= (1 << i);
- return;
- }
+ if (len + 1 >= size) {
+ size += 128;
+ buf = (char*)realloc(buf, size);
+ }
+ buf[len++] = v;
}
-void avr_cycle_timer_register_usec(avr_t * avr, uint32_t when, avr_cycle_timer_t timer, void * param)
+void avr_set_console_register(avr_t * avr, avr_io_addr_t addr)
{
- avr_cycle_timer_register(avr, avr_usec_to_cycles(avr, when), timer, param);
+ if (addr)
+ avr_register_io_write(avr, addr, _avr_io_console_write, NULL);
}
-void avr_cycle_timer_cancel(avr_t * avr, avr_cycle_timer_t timer, void * param)
+void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
{
- if (!avr->cycle_timer_map)
- return;
- for (int i = 0; i < 32; i++)
- if ((avr->cycle_timer_map & (1 << i)) &&
- avr->cycle_timer[i].timer == timer &&
- avr->cycle_timer[i].param == param) {
- avr->cycle_timer[i].timer = NULL;
- avr->cycle_timer[i].param = NULL;
- avr->cycle_timer[i].when = 0;
- avr->cycle_timer_map &= ~(1 << i);
- return;
- }
+ 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);
}
-/*
- * run thru all the timers, call the ones that needs it,
- * 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)
+void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong)
{
- if (!avr->cycle_timer_map)
- return (uint32_t)-1;
-
- uint64_t min = (uint64_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) {
- // call it
- avr->cycle_timer[i].when =
- avr->cycle_timer[i].timer(avr,
- avr->cycle_timer[i].when,
- avr->cycle_timer[i].param);
- if (avr->cycle_timer[i].when == 0) {
- // clear it
- avr->cycle_timer[i].timer = NULL;
- avr->cycle_timer[i].param = NULL;
- avr->cycle_timer[i].when = 0;
- avr->cycle_timer_map &= ~(1 << i);
- continue;
- }
- }
- if (avr->cycle_timer[i].when < min)
- min = avr->cycle_timer[i].when;
- }
- return min - avr->cycle;
+ 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;
- if (step) {
+ if (step)
avr->state = cpu_Running;
- }
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...
- if (avr->sreg[S_I] && !(avr->data[R_SREG] & (1 << S_I))) {
- // printf("*** %s: Renabling interrupts\n", __FUNCTION__);
+ // double buffer the I flag, to detect that edge
+ if (avr->sreg[S_I] && !avr->i_shadow)
avr->pending_wait++;
- }
- avr_io_t * port = avr->io_port;
- while (port) {
- if (port->run)
- port->run(port);
- port = port->next;
- }
- avr_cycle_count_t sleep = avr_cycle_timer_check(avr);
+ 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 (?)
*/
- uint32_t usec = avr_cycles_to_usec(avr, sleep);
- if (avr->gdb) {
- while (avr_gdb_processor(avr, usec))
- ;
- } else
- usleep(usec);
- avr->cycle += sleep;
+ avr->sleep(avr, sleep);
+ avr->cycle += 1 + sleep;
}
- // Interrupt servicing might change the PC too
- if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
+ // Interrupt servicing might change the PC too, during 'sleep'
+ if (avr->state == cpu_Running || avr->state == cpu_Sleeping)
avr_service_interrupts(avr);
+
+ // if we were stepping, use this state to inform remote gdb
+ 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;
- avr->data[R_SREG] = 0;
- for (int i = 0; i < 8; i++)
- if (avr->sreg[i] > 1) {
- printf("** Invalid SREG!!\n");
- CRASH();
- } else if (avr->sreg[i])
- avr->data[R_SREG] |= (1 << i);
+ if (avr->state == cpu_Running) {
+ new_pc = avr_run_one(avr);
+#if CONFIG_SIMAVR_TRACE
+ avr_dump_state(avr);
+#endif
}
- if (step) {
- avr->state = cpu_StepDone;
+ // 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;
}
extern avr_kind_t tiny13;
+extern avr_kind_t tiny2313;
extern avr_kind_t tiny25,tiny45,tiny85;
-extern avr_kind_t mega48,mega88,mega168;
-extern avr_kind_t mega644;
+extern avr_kind_t tiny24,tiny44,tiny84;
+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,
- &tiny25,
- &tiny45,
- &tiny85,
- &mega48,
- &mega88,
- &mega168,
- &mega644,
+ &tiny2313,
+ &tiny25, &tiny45, &tiny85,
+ &tiny24, &tiny44, &tiny84,
+ &mega48, &mega88, &mega168, &mega328,
+ &mega164, &mega324, &mega644,
+ &mega128,
NULL
};