core: Deinitialize GDB in avr_terminate()
[simavr] / simavr / sim / sim_avr.c
index 1af351e..d3e6706 100644 (file)
 #include <unistd.h>
 #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)
 {
@@ -35,22 +40,43 @@ 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);
+
+       if (avr->flash) free(avr->flash);
+       if (avr->data) free(avr->data);
+       avr->flash = avr->data = NULL;
 }
 
 void avr_reset(avr_t * avr)
@@ -62,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)
@@ -73,6 +100,7 @@ void avr_reset(avr_t * avr)
 
 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
@@ -80,157 +108,111 @@ 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;
 }
 
-void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
+static void _avr_io_command_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
 {
-       memcpy(avr->flash + address, code, size);
-}
-
-void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
-{
-       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
-avr_cycle_count_t avr_usec_to_cycles(avr_t * avr, uint32_t usec)
-{
-       return avr->frequency * (avr_cycle_count_t)usec / 1000000;
-}
-
-uint32_t avr_cycles_to_usec(avr_t * avr, avr_cycle_count_t cycles)
-{
-       return 1000000 * cycles / avr->frequency;
 }
 
-// converts a number of hz (to megahertz etc) to a number of cycle
-avr_cycle_count_t avr_hz_to_cycles(avr_t * avr, uint32_t hz)
+void avr_set_command_register(avr_t * avr, avr_io_addr_t addr)
 {
-       return avr->frequency / hz;
+       if (addr)
+               avr_register_io_write(avr, addr, _avr_io_command_write, NULL);
 }
 
-void avr_cycle_timer_register(avr_t * avr, avr_cycle_count_t when, avr_cycle_timer_t timer, void * param)
+static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
 {
-       avr_cycle_timer_cancel(avr, timer, param);
-
-       if (avr->cycle_timer_map == 0xffffffff) {
-               fprintf(stderr, "avr_cycle_timer_register is full!\n");
+       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;
        }
-       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);
+       }
+       if (v >= ' ')
+               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, avr_flashaddr_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...
+/**
+ * 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 avr_cycle_count_t avr_cycle_timer_check(avr_t * avr)
+static inline uint32_t avr_pending_sleep_usec(avr_t * avr, avr_cycle_count_t howLong)
 {
-       if (!avr->cycle_timer_map)
-               return (avr_cycle_count_t)-1;
-
-       avr_cycle_count_t min = (avr_cycle_count_t)-1;
-
-       for (int i = 0; i < 32; i++) {
-               if (!(avr->cycle_timer_map & (1 << i)))
-                       continue;
-               // do it several times, in case we're late
-               while (avr->cycle_timer[i].when && 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);
-                               break;
-                       }
-               }
-               if (avr->cycle_timer[i].when && avr->cycle_timer[i].when < min)
-                       min = avr->cycle_timer[i].when;
+       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 min - avr->cycle;
+       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) {
+       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);
@@ -240,75 +222,109 @@ int avr_run(avr_t * avr)
        }
 
        // 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__);
-               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);
+       // 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]) {
-                       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
-       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;
 
-               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);
+}
+
+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);
        }
+}
 
-       if (step) {
-               avr->state = cpu_StepDone;
+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
        }
 
-       return avr->state;
+       // 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);
 }
 
 
-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;
+int avr_run(avr_t * avr)
+{
+       avr->run(avr);
+       return avr->state;
+}
 
-avr_kind_t * avr_kind[] = {
-       &tiny13,
-       &tiny2313,
-       &tiny25, &tiny45, &tiny85,
-       &mega48, &mega88, &mega168, &mega328,
-       &mega164, &mega324, &mega644,
-       NULL
-};
+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++) {
@@ -319,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;
        }