Commit 24c5c6069017010fd7d27eda7585e38b5fff7a4b
authorMichel Pollet <buserror@gmail.com>
Wed, 2 Dec 2009 21:50:09 +0000 (21:50 +0000)
committerMichel Pollet <buserror@gmail.com>
Wed, 2 Dec 2009 21:52:53 +0000 (21:52 +0000)
Big news is gdb support, you can trace, breakpoint,
resume, inspect (including eeprom addresses!).
You can't modify variables on the fly yet.
It's not very fast rignt now, but some very obvious
changes will help that a lot.

Other changes are more moving, shuffling. "simavr"
is gone, replaced by a simple "run_avr" that does
the same, but no longer has any emulation specific
code.

Signed-off-by: Michel Pollet <buserror@gmail.com>
33 files changed:
.gitignore
.simavr.jcc
simavr/Makefile
simavr/cores/sim_mega168.c
simavr/cores/sim_mega48.c
simavr/cores/sim_mega644.c
simavr/cores/sim_mega88.c
simavr/cores/sim_megax8.c
simavr/cores/sim_megax8.h
simavr/cores/sim_tiny85.c
simavr/sim/avr_eeprom.c
simavr/sim/avr_eeprom.h
simavr/sim/avr_ioport.h
simavr/sim/avr_spi.c
simavr/sim/avr_spi.h
simavr/sim/avr_timer8.h
simavr/sim/avr_uart.c
simavr/sim/avr_uart.h
simavr/sim/run_avr.c [new file with mode: 0644]
simavr/sim/sim_avr.c [new file with mode: 0644]
simavr/sim/sim_avr.h [new file with mode: 0644]
simavr/sim/sim_core.c
simavr/sim/sim_elf.c
simavr/sim/sim_elf.h
simavr/sim/sim_gdb.c
simavr/sim/sim_gdb.h
simavr/sim/sim_interrupts.h
simavr/sim/sim_io.h
simavr/sim/sim_irq.h
simavr/sim/sim_regbit.h
simavr/sim/simavr.c [deleted file]
simavr/sim/simavr.h [deleted file]
tests/atmega48_disabled_timer.c

index b3de6c02028ffede58d443b15377defeba7d3e79..543ae13f810bd32d56bd50463df97bc5bcfe0bbf 100644 (file)
@@ -3,3 +3,4 @@ obj
 *.hex
 *.s
 simavr/simavr
+simavr/run_avr
index b69769ef12548036523634a5ac0652ccc4600195..d7a4a412986e8ce21c85e1e61a93f0d3680f0dd7 100644 (file)
@@ -100,17 +100,21 @@ T
 F
 "./simavr/sim/sim_io.h"
 T
-2 "simavr.c"
+2 "sim_avr.c"
 F
-"./simavr/sim/simavr.c"
+"./simavr/sim/sim_avr.c"
 T
-2 "simavr.h"
+2 "sim_avr.h"
 F
-"./simavr/sim/simavr.h"
+"./simavr/sim/sim_avr.h"
 T
 2 "fifo_declare.h"
 F
 "./simavr/sim/fifo_declare.h"
+T
+2 "run_avr.c"
+F
+"./simavr/sim/run_avr.c"
 F
 T
 1 "tests"
@@ -118,6 +122,14 @@ T
 2 "atmega88_example.c"
 F
 "./tests/atmega88_example.c"
+T
+2 "atmega48_disabled_timer.c"
+F
+"./tests/atmega48_disabled_timer.c"
+T
+2 "atmega88_uart_echo.c"
+F
+"./tests/atmega88_uart_echo.c"
 F
 T
 1 "cores"
index 6138d99318168c934526967d0cc3e14136842bc2..3625912a3557d0788900b318bb18613e2c7826e0 100644 (file)
@@ -16,7 +16,7 @@
 #      You should have received a copy of the GNU General Public License
 #      along with simavr.  If not, see <http://www.gnu.org/licenses/>.
 
-target = simavr
+target = run_avr
 
 ifeq (${shell uname}, Darwin)
 AVR_ROOT := "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr-4/"
@@ -44,7 +44,7 @@ IPATH += /opt/local/include
 
 CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}}
 LFLAGS = -L/opt/local/lib/
-LDFLAGS        += -lelf
+LDFLAGS        += -lelf -lpthread
 
 all:   obj ${target}
 
index 54d8bcf44057ebaffdcf0eed350f6fbdffa36fe8..8d0f2e4f9c8aec690e51c60adb448a2f734e9887 100644 (file)
@@ -19,7 +19,7 @@
        along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 #define SIM_VECTOR_SIZE        4
 #define SIM_MMCU               "atmega168"
index b0b0c9577b41a6e8568a113537edbf35d233ae11..08771afa2446e6ad276ee422de4e6eafab04d088 100644 (file)
@@ -19,7 +19,7 @@
        along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 #define SIM_VECTOR_SIZE        2
 #define SIM_MMCU               "atmega48"
index 22b439d7e554d0af462e731e46983f0bce2bb6b2..f240a2f1d878666cae5a367eabcd5aa97762ae04 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include </usr/include/stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
 #include "sim_core_declare.h"
 #include "avr_eeprom.h"
 #include "avr_ioport.h"
index c5e43cb598f9c874417aeb13cbbf07c583ab8dcc..59bc48059b356e949c008a6f4182d1c55139c610 100644 (file)
@@ -19,7 +19,7 @@
        along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 #define SIM_VECTOR_SIZE        2
 #define SIM_MMCU               "atmega88"
index 44bf3347c5a85d678224197a82891e75dbdeb383..7b1f29386b845674753aeb1930c6ca4cc6054914 100644 (file)
@@ -19,7 +19,7 @@
        along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include <stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
 
 #include "sim_megax8.h"
 
index 8ea2bd3468dbbcfa5d6ec8f181927fe6d227b03c..97eb61e70b8e40c936eb42fd6392d08c65e9ef0e 100644 (file)
@@ -181,11 +181,13 @@ struct mcu_t SIM_CORENAME = {
        
        .spi = {
                .disabled = AVR_IO_REGBIT(PRR,PRSPI),
+
+               .r_spdr = SPDR,
+               .r_spcr = SPCR,
+               .r_spsr = SPSR,
+
                .spe = AVR_IO_REGBIT(SPCR, SPE),
-               .dord = AVR_IO_REGBIT(SPCR, DORD),
                .mstr = AVR_IO_REGBIT(SPCR, MSTR),
-               .cpol = AVR_IO_REGBIT(SPCR, CPOL),
-               .cpha = AVR_IO_REGBIT(SPCR, CPHA),
 
                .spr = { AVR_IO_REGBIT(SPCR, SPR0), AVR_IO_REGBIT(SPCR, SPR1), AVR_IO_REGBIT(SPSR, SPI2X) },
                .spi = {
index e4d7af326a39291912480388e7e10dfeb0d7426b..eec13a639b191e9118fc36e2b3461c46222c115a 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include </usr/include/stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
 #include "sim_core_declare.h"
 #include "avr_eeprom.h"
 #include "avr_ioport.h"
index b6ff5a1987b0e0f6fc56d4e0c2377cbed571340e..53c82f0bd1ddd894e08bb1e62870a769ebdd4d93 100644 (file)
@@ -93,6 +93,18 @@ static int avr_eeprom_ioctl(avr_t * avr, avr_io_t * port, uint32_t ctl, void * i
                        printf("%s: AVR_IOCTL_EEPROM_SET Loaded %d at offset %d\n",
                                        __FUNCTION__, desc->size, desc->offset);
                }       break;
+               case AVR_IOCTL_EEPROM_GET: {
+                       avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
+                       if (!desc || (desc->offset + desc->size) >= p->size) {
+                               printf("%s: AVR_IOCTL_EEPROM_GET Invalid argument\n",
+                                               __FUNCTION__);
+                               return -2;
+                       }
+                       if (desc->ee)
+                               memcpy(desc->ee, p->eeprom + desc->offset, desc->size);
+                       else    // allow to get access to the read data, for gdb support
+                               desc->ee = p->eeprom + desc->offset;
+               }       break;
        }
        
        return res;
index c7f1dcd53021dcc12e94c12ecb51f16fee5ae0e7..89678fe84ce5e7e7d69c0a204c341fc86265f843 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __AVR_EEPROM_H__
 #define __AVR_EEPROM_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 typedef struct avr_eeprom_t {
        avr_io_t        io;
index 04d0890453969f46fdde460348d06395260b2aad..0a1ca37f195381dcd3a5d2a5bebe5da0ae58d712 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __AVR_IOPORT_H__
 #define __AVR_IOPORT_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 enum {
        IOPORT_IRQ_PIN0 = 0,
index b373e8e642d191655389f92bc23d2d659a015f44..01b0d7f99896e3d971f44509393bbc85989baaa2 100644 (file)
@@ -27,7 +27,6 @@ static void avr_spi_run(avr_t * avr, avr_io_t * port)
 //     printf("%s\n", __FUNCTION__);
 }
 
-#if 0
 static uint8_t avr_spi_read(struct avr_t * avr, uint8_t addr, void * param)
 {
        avr_spi_t * p = (avr_spi_t *)param;
@@ -40,27 +39,27 @@ static void avr_spi_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * pa
 {
        avr_spi_t * p = (avr_spi_t *)param;
 
-       if (addr == p->r_udr) {
+       if (addr == p->r_spdr) {
        //      printf("UDR%c(%02x) = %02x\n", p->name, addr, v);
                avr_core_watch_write(avr, addr, v);
-               avr_regbit_set(avr, p->udre);
-
-               static char buf[128];
-               static int l = 0;
-               buf[l++] = v <= ' ' ? '.' : v;
-               buf[l] = 0;
-               if (v == '\n' || l == 127) {
-                       l = 0;
-                       printf("\e[32m%s\e[0m\n", buf);
-               }
        }
 }
-#endif
+
+static void avr_spi_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+{
+       avr_spi_t * p = (avr_spi_t *)param;
+
+       // check to see fi receiver is enabled
+       if (!avr_regbit_get(avr, p->spe))
+               return;
+
+       // double buffer the input.. ?
+}
 
 void avr_spi_reset(avr_t * avr, struct avr_io_t *io)
 {
-//     avr_spi_t * p = (avr_spi_t *)io;
-//     avr_regbit_set(avr, p->udre);
+       avr_spi_t * p = (avr_spi_t *)io;
+       avr_irq_register_notify(avr, p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p);
 }
 
 static avr_io_t        _io = {
@@ -76,7 +75,12 @@ void avr_spi_init(avr_t * avr, avr_spi_t * p)
 
        printf("%s SPI%c init\n", __FUNCTION__, p->name);
 
-//     avr_register_io_write(avr, p->r_udr, avr_spi_write, p);
-//     avr_register_io_read(avr, p->r_udr, avr_spi_read, p);
+       // allocate this module's IRQ
+       p->io.irq_count = SPI_IRQ_COUNT;
+       p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count);
+       p->io.irq_ioctl_get = AVR_IOCTL_SPI_GETIRQ(p->name);
+
+       avr_register_io_write(avr, p->r_spdr, avr_spi_write, p);
+       avr_register_io_read(avr, p->r_spdr, avr_spi_read, p);
 }
 
index e15176ab5f4fc4c9d69c03ae6a5454743a730ea6..2c24e5285e3a42296f6470b3bee7277682e49c48 100644 (file)
 #ifndef AVR_SPI_H_
 #define AVR_SPI_H_
 
-#include "simavr.h"
+#include "sim_avr.h"
+
+enum {
+       SPI_IRQ_INPUT = 0,
+       SPI_IRQ_OUTPUT,
+       SPI_IRQ_COUNT
+};
+
+// add port number to get the real IRQ
+#define AVR_IOCTL_SPI_GETIRQ(_name) AVR_IOCTL_DEF('s','p','i',(_name))
 
 typedef struct avr_spi_t {
        avr_io_t        io;
@@ -31,12 +40,10 @@ typedef struct avr_spi_t {
 
        uint8_t r_spdr;                 // data register
        uint8_t r_spcr;                 // control register
+       uint8_t r_spsr;                 // status register
        
        avr_regbit_t spe;               // spi enable
-       avr_regbit_t dord;              // data order
        avr_regbit_t mstr;              // master/slave
-       avr_regbit_t cpol;              // clock polarity
-       avr_regbit_t cpha;              // phase
        avr_regbit_t spr[4];    // clock divider
        
        avr_int_vector_t spi;   // spi interrupt
index b73a83148c67635eee5e81aa7522b9b6a67dc303..1f3eccabc68eae273c4b050400f2cf7c2f3a863c 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef AVR_TIMER8_H_
 #define AVR_TIMER8_H_
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 typedef struct avr_timer8_t {
        avr_io_t        io;
index e24609a6183141591e8e13fa527c60f6b0593a5e..35b8b0db950c638a687cfde3b0a9efbd63e0d586 100644 (file)
@@ -97,7 +97,7 @@ static void avr_uart_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * p
        }
 }
 
-void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+static void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
 {
        avr_uart_t * p = (avr_uart_t *)param;
 
index 9de90d244230c73996be62bff2eaedfc587cd0dc..81b4e13ba2ae9daa8426ba5f230cb1ad3d4114c8 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef AVR_UART_H_
 #define AVR_UART_H_
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 #include "fifo_declare.h"
 
diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c
new file mode 100644 (file)
index 0000000..4560033
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+       run_avr.c
+
+       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include "sim_avr.h"
+#include "sim_elf.h"
+#include "sim_core.h"
+#include "sim_gdb.h"
+#include "avr_eeprom.h"
+#include "avr_uart.h"
+
+void hdump(const char *w, uint8_t *b, size_t l)
+{
+       uint32_t i;
+       if (l < 16) {
+               printf("%s: ",w);
+               for (i = 0; i < l; i++) printf("%02x",b[i]);
+       } else {
+               printf("%s:\n",w);
+               for (i = 0; i < l; i++) {
+                       if (!(i & 0x1f)) printf("    ");
+                       printf("%02x",b[i]);
+                       if ((i & 0x1f) == 0x1f) {
+                               printf(" ");
+                               printf("\n");
+                       }
+               }
+       }
+       printf("\n");
+}
+
+
+void display_usage()
+{
+       printf("usage: simavr [-t] [-g] [-m <device>] [-f <frequency>] firmware\n");
+       printf("       -t: run full scale decoder trace\n");
+       printf("       -g: listen for gdb connection on port 1234\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       elf_firmware_t f;
+       long f_cpu = 0;
+       int trace = 0;
+       int gdb = 0;
+       char name[16] = "";
+       int option_count;
+       int option_index = 0;
+
+       struct option long_options[] = {
+               {"help", no_argument, 0, 'h'},
+               {"mcu", required_argument, 0, 'm'},
+               {"freq", required_argument, 0, 'f'},
+               {"trace", no_argument, 0, 't'},
+               {"gdb", no_argument, 0, 'g'},
+               {0, 0, 0, 0}
+       };
+
+       if (argc == 1)
+               display_usage();
+
+       while ((option_count = getopt_long(argc, argv, "tghm:f:", long_options, &option_index)) != -1) {
+               switch (option_count) {
+                       case 'h':
+                               display_usage();
+                               break;
+                       case 'm':
+                               strcpy(name, optarg);
+                               break;
+                       case 'f':
+                               f_cpu = atoi(optarg);
+                               break;
+                       case 't':
+                               trace++;
+                               break;
+                       case 'g':
+                               gdb++;
+                               break;
+               }
+       }
+
+       elf_read_firmware(argv[argc-1], &f);
+
+       if (strlen(name))
+               strcpy(f.mmcu.name, name);
+       if (f_cpu)
+               f.mmcu.f_cpu = f_cpu;
+
+       printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], (int)f.mmcu.f_cpu, f.mmcu.name);
+
+       avr_t * avr = avr_make_mcu_by_name(f.mmcu.name);
+       if (!avr) {
+               fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
+               exit(1);
+       }
+       avr_init(avr);
+       avr->frequency = f.mmcu.f_cpu;
+       avr->codeline = f.codeline;
+       avr_loadcode(avr, f.flash, f.flashsize, 0);
+       avr->codeend = f.flashsize - f.datasize;
+       if (f.eeprom && f.eesize) {
+               avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
+               avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
+       }
+       avr->trace = trace;
+
+       // try to enable "local echo" on the first uart, for testing purposes
+       {
+               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);
+               printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
+               if (src && dst)
+                       avr_connect_irq(avr, src, dst);
+       }
+
+       if (gdb) {
+               avr->state = cpu_Stopped;
+               avr_gdb_init(avr);
+       }
+
+//     for (long long i = 0; i < 8000000*10; i++)
+//     for (long long i = 0; i < 80000; i++)
+       for (;;)
+               avr_run(avr);
+       
+}
diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c
new file mode 100644 (file)
index 0000000..16a908a
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+       sim_avr.c
+
+       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "sim_avr.h"
+#include "sim_core.h"
+#include "sim_gdb.h"
+
+
+int avr_init(avr_t * avr)
+{
+       avr->flash = malloc(avr->flashend + 1);
+       memset(avr->flash, 0xff, avr->flashend + 1);
+       avr->data = malloc(avr->ramend + 1);
+       memset(avr->data, 0, avr->ramend + 1);
+
+       // cpu is in limbo before init is finished.
+       avr->state = cpu_Limbo;
+       avr->frequency = 1000000;       // can be overriden via avr_mcu_section
+       if (avr->init)
+               avr->init(avr);
+       avr->state = cpu_Running;
+       avr_reset(avr); 
+       return 0;
+}
+
+void avr_reset(avr_t * avr)
+{
+       memset(avr->data, 0x0, avr->ramend + 1);
+       _avr_sp_set(avr, avr->ramend);
+       avr->pc = 0;
+       for (int i = 0; i < 8; i++)
+               avr->sreg[i] = 0;
+       if (avr->reset)
+               avr->reset(avr);
+
+       avr_io_t * port = avr->io_port;
+       while (port) {
+               if (port->reset)
+                       port->reset(avr, port);
+               port = port->next;
+       }
+}
+
+
+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)
+{
+       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;
+}
+
+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];
+}
+
+
+int avr_run(avr_t * avr)
+{
+       avr_gdb_processor(avr);
+
+       if (avr->state == cpu_Stopped) {
+               usleep(500);
+               return avr->state;
+       }
+
+       int step = avr->state == cpu_Step;
+       if (step) {
+               avr->state = cpu_Running;
+       }
+       
+       uint16_t new_pc = avr->pc;
+
+       if (avr->state == cpu_Running) {
+               new_pc = avr_run_one(avr);
+               avr_dump_state(avr);
+       } else
+               avr->cycle ++;
+
+       // re-synth the SREG
+       //SREG();
+       // 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(avr, port);
+               port = port->next;
+       }
+
+       avr->pc = new_pc;
+
+       if (avr->state == cpu_Sleeping) {
+               if (!avr->sreg[S_I]) {
+                       printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
+                       exit(0);
+               }
+               usleep(500);
+               long sleep = (float)avr->frequency * (1.0f / 500.0f);
+               avr->cycle += sleep;
+       //      avr->state = cpu_Running;
+       }
+       // Interrupt servicing might change the PC too
+       if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
+               avr_service_interrupts(avr);
+
+               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 (step) {
+               avr->state = cpu_StepDone;
+       }
+
+       return avr->state;
+}
+
+
+extern avr_kind_t tiny85;
+extern avr_kind_t mega48,mega88,mega168;
+extern avr_kind_t mega644;
+
+avr_kind_t * avr_kind[] = {
+       &tiny85,
+       &mega48,
+       &mega88,
+       &mega168,
+       &mega644,
+       NULL
+};
+
+avr_t * avr_make_mcu_by_name(const char *name)
+{
+       avr_kind_t * maker = NULL;
+       for (int i = 0; avr_kind[i] && !maker; i++) {
+               for (int j = 0; avr_kind[i]->names[j]; j++)
+                       if (!strcmp(avr_kind[i]->names[j], name)) {
+                               maker = avr_kind[i];
+                               break;
+                       }
+       }
+       if (!maker) {
+               fprintf(stderr, "%s: AVR '%s' now known\n", __FUNCTION__, name);
+               return NULL;
+       }
+
+       avr_t * avr = maker->make();
+       printf("Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end);
+       return avr;     
+}
+
diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h
new file mode 100644 (file)
index 0000000..fe7f36d
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+       sim_avr.h
+
+       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SIM_AVR_H__
+#define __SIM_AVR_H__
+
+#include <stdint.h>
+
+struct avr_t;
+typedef uint8_t (*avr_io_read_t)(struct avr_t * avr, uint8_t addr, void * param);
+typedef void (*avr_io_write_t)(struct avr_t * avr, uint8_t addr, uint8_t v, void * param);
+
+enum {
+       // SREG bit indexes
+       S_C = 0,S_Z,S_N,S_V,S_S,S_H,S_T,S_I,
+
+       // 16 bits register pairs
+       R_XL    = 0x1a, R_XH,R_YL,R_YH,R_ZL,R_ZH,
+       // stack pointer
+       R_SPL   = 32+0x3d, R_SPH,
+       // real SREG
+       R_SREG  = 32+0x3f,
+
+       // maximum number of IO regisrer, on normal AVRs
+       MAX_IOs = 256 - 32,     // minus 32 GP registers
+};
+
+#define AVR_DATA_TO_IO(v) ((v) - 32)
+#define AVR_IO_TO_DATA(v) ((v) + 32)
+
+/*
+ * Core states. This will need populating with debug states for gdb
+ */
+enum {
+       cpu_Limbo = 0,  // before initialization is finished
+       cpu_Stopped,
+       cpu_Running,
+       cpu_Sleeping,
+
+       cpu_Step,
+       cpu_StepDone,
+};
+
+/*
+ * Main AVR instance. Some of these fields are set by the AVR "Core" definition files
+ * the rest is runtime data (as little as possible)
+ */
+typedef struct avr_t {
+       const char * mmcu;      // name of the AVR
+       // these are filled by sim_core_declare from constants in /usr/lib/avr/include/avr/io*.h
+       uint16_t        ramend;         
+       uint32_t        flashend;
+       uint32_t        e2end;
+       uint8_t         vector_size;
+       uint8_t         signature[3];
+       uint8_t         fuse[4];
+
+       // filled by the ELF data, this allow tracking of invalid jumps
+       uint32_t        codeend;
+
+       int                     state;          // stopped, running, sleeping
+       uint32_t        frequency;      // frequency we are running at
+       uint64_t        cycle;          // current cycle
+       
+       // called at init time
+       void (*init)(struct avr_t * avr);
+       // called at reset time
+       void (*reset)(struct avr_t * avr);
+
+       // 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
+       uint8_t         sreg[8];
+
+       /* 
+        * ** current PC **
+        * Note that the PC is reoresenting /bytes/ while the AVR value is
+        * assumed to be "words". This is in line with what GDB does...
+        * this is why you will see >>1 ane <<1 in the decoder to handle jumps
+        */
+       uint32_t        pc;
+
+       /*
+        * callback when specific IO registers are read/written
+        */
+       struct {
+               void * param;
+               avr_io_read_t r;
+       } ior[MAX_IOs];
+       struct {
+               void * param;
+               avr_io_write_t w;
+       } iow[MAX_IOs];
+
+       // flash memory (initialized to 0xff, and code loaded into it)
+       uint8_t *       flash;
+       // this is the general purpose registers, IO registers, and SRAM
+       uint8_t *       data;
+
+       // queue of io modules
+       struct avr_io_t *io_port;
+
+       // interrupt vectors, and their enable/clear registers
+       struct avr_int_vector_t * vector[64];
+       uint8_t         pending_wait;   // number of cycles to wait for pending
+       uint32_t        pending[2];             // pending interrupts
+
+       // DEBUG ONLY
+       int             trace;
+       struct avr_symbol_t ** codeline;
+
+       /* DEBUG ONLY
+        * this keeps track of "jumps" ie, call,jmp,ret,reti and so on
+        * allows dumping of a meaningful data even if the stack is
+        * munched and so on
+        */
+       #define OLD_PC_SIZE     32
+       struct {
+               uint32_t pc;
+               uint16_t sp;
+       } old[OLD_PC_SIZE]; // catches reset..
+       int                     old_pci;
+
+#if AVR_STACK_WATCH
+       #define STACK_FRAME_SIZE        32
+       // this records the call/ret pairs, to try to catch
+       // code that munches the stack -under- their own frame
+       struct {
+               uint32_t        pc;
+               uint16_t        sp;             
+       } stack_frame[STACK_FRAME_SIZE];
+       int                     stack_frame_index;
+#endif
+
+       // DEBUG ONLY
+       // keeps track of wich registers gets touched by instructions
+       // reset before each new instructions. Allows meaningful traces
+       uint32_t        touched[256 / 32];      // debug
+
+       // placeholder
+       struct avr_gdb_t * gdb;
+} avr_t;
+
+
+// this is a static constructor for each of the AVR devices
+typedef struct avr_kind_t {
+       const char * names[4];  // name aliases
+       avr_t * (*make)();
+} avr_kind_t;
+
+// a symbol loaded from the .elf file
+typedef struct avr_symbol_t {
+       const char * symbol;
+       uint32_t        addr;
+} avr_symbol_t;
+
+// locate the maker for mcu "name" and allocates a new avr instance
+avr_t * avr_make_mcu_by_name(const char *name);
+// initializes a new AVR instance. Will call the IO registers init(), and then reset()
+int avr_init(avr_t * avr);
+// resets the AVR, and the IO modules
+void avr_reset(avr_t * avr);
+// run one cycle of the AVR, sleep if necessary
+int avr_run(avr_t * avr);
+
+// load code in the "flash"
+void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address);
+
+
+/*
+ * these are accessors for avr->data but allows watchpoints to be set for gdb
+ * IO modules use that to set values to registers, and the AVR core decoder uses
+ * that to register "public" read by instructions.
+ */
+void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v);
+uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr);
+
+
+#include "sim_io.h"
+#include "sim_regbit.h"
+#include "sim_interrupts.h"
+#include "sim_irq.h"
+
+#endif /*__SIM_AVR_H__*/
+
index 0980ab503b0eeea9b489ade0d3f95764c22e9c8d..b70edd63f5d6d41d5bb3e322729cfed71c4da0af 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
-#include "simavr.h"
+#include "sim_avr.h"
 #include "sim_core.h"
 
 // SREG bit names
@@ -717,6 +717,8 @@ uint16_t avr_run_one(avr_t * avr)
                                }       break;
                                case 0x9598: { // BREAK
                                        STATE("break\n");
+                                       if (avr->gdb)
+                                               avr->state = cpu_StepDone;
                                }       break;
                                case 0x95a8: { // WDR
                                        STATE("wdr\n");
index 1270d67d3da10cd53a5fcec9e686a69588b0a250..02aaa93ff8f244d468d351fd36d6253f1ec5b133 100644 (file)
@@ -89,7 +89,7 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware)
                } else if (!strcmp(name, ".mmcu")) {
                        Elf_Data *s = elf_getdata(scn, NULL);
                        firmware->mmcu = *((struct avr_mcu_t*)s->d_buf);
-               //      printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(avr_mcu_t), s->d_size);
+                       printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size);
                //      avr->frequency = f_cpu;
                }
 #if ELF_SYMBOLS
index 7b13e512abf1dc178cf367062c22a3a04b4d780b..aa6bc77ab9e11334638ac111ab98fd646a38b432 100644 (file)
@@ -29,7 +29,7 @@
 #endif
 
 #if ELF_SYMBOLS
-#include "simavr.h"
+#include "sim_avr.h"
 #endif
 
 typedef struct elf_firmware_t {
index 74714d18f44b41dc967694da51a0c81e0514b834..eac0d20d588e90814492930c37a669f753f67537 100644 (file)
@@ -1,8 +1,6 @@
 /*
        sim_gdb.c
 
-       Placeholder!
-
        Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
 
        This file is part of simavr.
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
+#include <sys/time.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <poll.h>
-#include "simavr.h"
+#include <pthread.h>
+#include "sim_avr.h"
+#include "avr_eeprom.h"
 
 typedef struct avr_gdb_t {
        avr_t * avr;
-       int             sock;
+       int             listen; // listen socket
+       int             s;              // current gdb connection
+       
+       pthread_t thread;
+
+       uint32_t        query_len;
+       char            query[1024];
+
+       uint32_t        watchmap;
+       struct {
+               uint32_t        pc;
+               uint32_t        len;
+               int kind;
+       } watch[32];
 } avr_gdb_t;
 
+    // decode line text hex to binary
+int read_hex_string(const char * src, uint8_t * buffer, int maxlen)
+{
+    uint8_t * dst = buffer;
+    int ls = 0;
+    uint8_t b = 0;
+    while (*src && maxlen--) {
+        char c = *src++;
+        switch (c) {
+            case 'a' ... 'f':   b = (b << 4) | (c - 'a' + 0xa); break;
+            case 'A' ... 'F':   b = (b << 4) | (c - 'A' + 0xa); break;
+            case '0' ... '9':   b = (b << 4) | (c - '0'); break;
+            default:
+                if (c > ' ') {
+                    fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src);
+                    return -1;
+                }
+                continue;
+        }
+        if (ls & 1) {
+            *dst++ = b; b = 0;
+        }
+        ls++;
+    }
+
+    return dst - buffer;
+}
+
+static void gdb_send_reply(avr_gdb_t * g, char * cmd)
+{
+       uint8_t reply[1024];
+       uint8_t * dst = reply;
+       uint8_t check = 0;
+       *dst++ = '$';
+       while (*cmd) {
+               check += *cmd;
+               *dst++ = *cmd++;
+       }
+       sprintf((char*)dst, "#%02x", check);
+       printf("%s '%s'\n", __FUNCTION__, reply);
+       send(g->s, reply, dst - reply + 3, 0);
+}
+
+static void gdb_send_quick_status(avr_gdb_t * g, uint8_t signal)
+{
+       char cmd[64];
+
+       sprintf(cmd, "T%02x20:%02x;21:%02x%02x;22:%02x%02x%02x00;",
+               signal, g->avr->data[R_SREG], 
+               g->avr->data[R_SPL], g->avr->data[R_SPH],
+               g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
+       gdb_send_reply(g, cmd);
+}
+
+static int gdb_change_breakpoint(avr_gdb_t * g, int set, int kind, uint32_t addr, uint32_t len)
+{
+       printf("set %d kind %d addr %08x len %d (map %08x)\n", set, kind, addr, len, g->watchmap);
+       if (set) {
+               if (g->watchmap == 0xffffffff)
+                       return -1;      // map full
+
+               // check to see if it exists
+               for (int i = 0; i < 32; i++)
+                       if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
+                               g->watch[i].len = len;
+                               return 0;
+                       }
+               for (int i = 0; i < 32; i++)
+                       if (!(g->watchmap & (1 << i))) {
+                               g->watchmap |= (1 << i);
+                               g->watch[i].len = len;
+                               g->watch[i].pc = addr;
+                               g->watch[i].kind = kind;
+                               return 0;
+                       }
+       } else {
+               for (int i = 0; i < 32; i++)
+                       if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
+                               g->watchmap &= ~(1 << i);
+                               g->watch[i].len = 0;
+                               g->watch[i].pc = 0;
+                               g->watch[i].kind = 0;
+                               return 0;
+                       }
+       }
+       return -1;
+}
+
+static void gdb_handle_command(avr_gdb_t * g)
+{
+       avr_t * avr = g->avr;
+       char * cmd = g->query;
+       char rep[1024];
+       uint8_t command = *cmd++;
+       switch (command) {
+               case '?':
+                       gdb_send_reply(g, "S00");
+                       break;
+               case 'p': {
+                       unsigned int regi = 0;
+                       sscanf(cmd, "%x", &regi);
+                       switch (regi) {
+                               case 0 ... 31:
+                                       sprintf(rep, "%02x", g->avr->data[regi]);
+                                       break;
+                               case 32:
+                                       sprintf(rep, "%02x", g->avr->data[R_SREG]);
+                                       break;
+                               case 33:
+                                       sprintf(rep, "%02x%02x", g->avr->data[R_SPL], g->avr->data[R_SPH]);
+                                       break;
+                               case 34:
+                                       sprintf(rep, "%02x%02x%02x00", 
+                                               g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
+                                       break;
+                       }
+                       gdb_send_reply(g, rep);                 
+               }       break;
+               case 'm': {
+                       uint32_t addr, len;
+                       sscanf(cmd, "%x,%x", &addr, &len);
+                       printf("read memory %08x, %08x\n", addr, len);
+                       uint8_t * src = NULL;
+                       if (addr < 0xffff) {
+                               src = avr->flash + addr;
+                       } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
+                               src = avr->data + addr - 0x800000;
+                       } else if (addr >= 0x810000 && (addr - 0x810000) <= (16*1024)) {
+                               avr_eeprom_desc_t ee = {.offset = (addr - 0x810000)};
+                               avr_ioctl(avr, AVR_IOCTL_EEPROM_GET, &ee);
+                               if (ee.ee)
+                                       src = ee.ee;
+                               else
+                                       gdb_send_reply(g, "E01");
+                       } else {
+                               gdb_send_reply(g, "E01");
+                               break;
+                       }
+                       char * dst = rep;
+                       while (len--) {
+                               sprintf(dst, "%02x", *src++);
+                               dst += 2;
+                       }
+                       *dst = 0;
+                       gdb_send_reply(g, rep);
+               }       break;
+               case 'M': {
+                       uint32_t addr, len;
+                       sscanf(cmd, "%x,%x", &addr, &len);
+                       printf("write memory %08x, %08x\n", addr, len);
+                       char * start = strchr(cmd, ':');
+                       if (!start) {
+                               gdb_send_reply(g, "E01");
+                               break;
+                       }
+                       if (addr < 0xffff) {
+                               read_hex_string(start + 1, avr->flash + addr, strlen(start+1));
+                               gdb_send_reply(g, "OK");                        
+                       } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
+                               read_hex_string(start + 1, avr->data + addr - 0x800000, strlen(start+1));
+                               gdb_send_reply(g, "OK");                                                        
+                       } else
+                               gdb_send_reply(g, "E01");                       
+               }       break;
+               case 'c': {
+                       avr->state = cpu_Running;
+               }       break;
+               case 's': {
+                       avr->state = cpu_Step;
+               }       break;
+               case 'Z': 
+               case 'z': {
+                       uint32_t kind, addr, len;
+                       sscanf(cmd, "%d,%x,%x", &kind, &addr, &len);
+                       printf("breakbpoint %d, %08x, %08x\n", kind, addr, len);
+                       switch (kind) {
+                               case 0: // software breakpoint
+                               case 1: // hardware breakpoint
+                                       if (addr <= avr->flashend) {
+                                               if (gdb_change_breakpoint(g, command == 'Z', kind, addr, len))
+                                                       gdb_send_reply(g, "E01");
+                                               else
+                                                       gdb_send_reply(g, "OK");
+                                       } else
+                                               gdb_send_reply(g, "E01");               // out of flash address
+                                       break;
+                               case 2: // write watchpoint
+                               case 3: // read watchpoint
+                               case 4: // access watchpoint
+                               default:
+                                       gdb_send_reply(g, "");
+                       }       
+               }       break;
+               default:
+                       gdb_send_reply(g, "");
+       }
+}
+
+void avr_gdb_processor(avr_t * avr)
+{
+       if (!avr || !avr->gdb)
+               return; 
+       avr_gdb_t * g = avr->gdb;
+
+       if (g->watchmap && avr->state == cpu_Running) {
+               for (int i = 0; i < 32; i++)
+                       if ((g->watchmap & (1 << i)) && g->watch[i].pc == avr->pc) {
+                               printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);
+                               gdb_send_quick_status(g, 0);
+                               avr->state = cpu_Stopped;
+                       }               
+       }
+       if (avr->state == cpu_StepDone) {
+               gdb_send_quick_status(g, 0);
+               avr->state = cpu_Stopped;
+       }
+       if (avr->gdb->query_len) {
+               g->query_len = 0;
+       
+       //      printf("avr_gdb_handle_query got a query '%s'\n", g->query);
+               gdb_handle_command(g);
+       }
+}
+
+
+static void * gdb_network_handler(void * param)
+{
+       avr_gdb_t * g = (avr_gdb_t*)param;
+
+       do {
+               if (listen(g->listen, 1)) {
+                       perror("gdb_network_handler listen");
+                       sleep(5);
+                       continue;
+               }
+               
+               struct sockaddr_in address = { 0 };
+               socklen_t ad_len = sizeof(address);
+
+               g->s = accept(g->listen, (struct sockaddr*)&address, &ad_len);
+
+               if (g->s == -1) {
+                       perror("gdb_network_handler accept");
+                       sleep(5);
+                       continue;
+               }
+               // should make that thread safe... 
+               g->avr->state = cpu_Stopped;
+               
+               do {
+                       fd_set read_set;
+                       FD_ZERO(&read_set);
+                       FD_SET(g->s, &read_set);
+
+                       struct timeval timo = { 1, 0000 };      // short, but not too short interval
+                       /*int ret =*/ select(g->s + 1, &read_set, NULL, NULL, &timo);
+
+                       if (FD_ISSET(g->s, &read_set)) {
+                               uint8_t buffer[1024];
+                               
+                               ssize_t r = recv(g->s, buffer, sizeof(buffer)-1, 0);
+
+                               if (r == 0) {
+                                       printf("%s connection closed\n", __FUNCTION__);
+                                       break;
+                               }
+                               if (r == -1) {
+                                       perror("gdb_network_handler recv");
+                                       break;
+                               }
+                               buffer[r] = 0;
+                       //      printf("%s: received %d bytes\n'%s'\n", __FUNCTION__, r, buffer);
+                       //      hdump("gdb", buffer, r);
+
+                               uint8_t * src = buffer;
+                               while (*src == '+' || *src == '-')
+                                       src++;
+                               if (*src == 3) {
+                                       src++;
+                                       g->query[0] = 3;
+                                       g->query_len = 1; // pass it on ?
+                               }
+                               if (*src  == '$') {
+                                       // strip checksum
+                                       uint8_t * end = buffer + r - 1;
+                                       while (end > src && *end != '#')
+                                               *end-- = 0;
+                                       *end = 0;
+                                       src++;
+                                       printf("GDB command = '%s'\n", src);
+
+                                       send(g->s, "+", 1, 0);
+
+                                       strcpy(g->query, (char*)src);
+                                       g->query_len = strlen((char*)src);
+                               }
+                       }
+               } while(1);
+               
+               close(g->s);
+                       
+       } while(1);
+       
+       return NULL;
+}
+
+
 int avr_gdb_init(avr_t * avr)
 {
        avr_gdb_t * g = malloc(sizeof(avr_gdb_t));
@@ -45,22 +366,27 @@ int avr_gdb_init(avr_t * avr)
 
        avr->gdb = NULL;
 
-       if ((g->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+       if ((g->listen = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
                fprintf(stderr, "Can't create socket: %s", strerror(errno));
                return -1;
        }
 
        int i = 1;
-       setsockopt(g->sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+       setsockopt(g->listen, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
 
        struct sockaddr_in address = { 0 };
        address.sin_family = AF_INET;
        address.sin_port = htons (1234);
 
-       if (bind(g->sock, (struct sockaddr *) &address, sizeof(address))) {
+       if (bind(g->listen, (struct sockaddr *) &address, sizeof(address))) {
                fprintf(stderr, "Can not bind socket: %s", strerror(errno));
                return -1;
        }
+       printf("avr_gdb_init listening on port %d\n", 1234);
+       g->avr = avr;
        avr->gdb = g;
+
+       pthread_create(&g->thread, NULL, gdb_network_handler, g);
+
        return 0;
 }
index 67f7a07becbba3ad710dcb55a431ee9530d1fcd8..cbd4ed1e15afbb5dff9d25a23b25d4ed5a83c5ab 100644 (file)
@@ -22,4 +22,9 @@
 #ifndef __SIM_GDB_H__
 #define __SIM_GDB_H__
 
+int avr_gdb_init(avr_t * avr);
+
+// call from the main AVR decoder thread
+void avr_gdb_processor(avr_t * avr);
+
 #endif
index 270b39d3b932792af39613df0575353d4f07a86c..c602e8edf1c1a371f2fbc0487eb8596b0842a4f7 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __SIM_INTERUPTS_H__
 #define __SIM_INTERUPTS_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 // interrupt vector for the IO modules
 typedef struct avr_int_vector_t {
index 770b3a8c95fdcef61a58c0debff70785d84833ad..87eb5b9ddeda961be6e97fa27f828ffb94be7567 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __SIM_IO_H__
 #define __SIM_IO_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 /*
  * used by the ioports to implement their own features
index 9349d30d8353bf64b938733d933bbada5e0abc17..161c3110357d38111c9a448da6281d820acef7d1 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __SIM_IRQ_H__
 #define __SIM_IRQ_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 /*
  * Internal IRQ system
index 719dbbaf06c5d6df10b351dd188d5e870c2f2d2e..11700c89fa92e6d6f3de5d4e865db204182d4e0f 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __SIM_REGBIT_H__
 #define __SIM_REGBIT_H__
 
-#include "simavr.h"
+#include "sim_avr.h"
 
 #define ARRAY_SIZE(_aa) (sizeof(_aa) / sizeof((_aa)[0]))
 
diff --git a/simavr/sim/simavr.c b/simavr/sim/simavr.c
deleted file mode 100644 (file)
index 7cb73fa..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
-       simavr.c
-
-       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
-       This file is part of simavr.
-
-       simavr is free software: you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
-       (at your option) any later version.
-
-       simavr is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <getopt.h>
-#include "simavr.h"
-#include "sim_elf.h"
-
-#include "sim_core.h"
-#include "avr_eeprom.h"
-#include "avr_uart.h"
-
-void hdump(const char *w, uint8_t *b, size_t l)
-{
-       uint32_t i;
-       if (l < 16) {
-               printf("%s: ",w);
-               for (i = 0; i < l; i++) printf("%02x",b[i]);
-       } else {
-               printf("%s:\n",w);
-               for (i = 0; i < l; i++) {
-                       if (!(i & 0x1f)) printf("    ");
-                       printf("%02x",b[i]);
-                       if ((i & 0x1f) == 0x1f) {
-                               printf(" ");
-                               printf("\n");
-                       }
-               }
-       }
-       printf("\n");
-}
-
-
-
-int avr_init(avr_t * avr)
-{
-       avr->flash = malloc(avr->flashend + 1);
-       memset(avr->flash, 0xff, avr->flashend + 1);
-       avr->data = malloc(avr->ramend + 1);
-       memset(avr->data, 0, avr->ramend + 1);
-
-       // cpu is in limbo before init is finished.
-       avr->state = cpu_Limbo;
-       avr->frequency = 1000000;       // can be overriden via avr_mcu_section
-       if (avr->init)
-               avr->init(avr);
-       avr->state = cpu_Running;
-       avr_reset(avr); 
-       return 0;
-}
-
-void avr_reset(avr_t * avr)
-{
-       memset(avr->data, 0x0, avr->ramend + 1);
-       _avr_sp_set(avr, avr->ramend);
-       avr->pc = 0;
-       for (int i = 0; i < 8; i++)
-               avr->sreg[i] = 0;
-       if (avr->reset)
-               avr->reset(avr);
-
-       avr_io_t * port = avr->io_port;
-       while (port) {
-               if (port->reset)
-                       port->reset(avr, port);
-               port = port->next;
-       }
-
-}
-
-
-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)
-{
-       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;
-}
-
-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];
-}
-
-
-int avr_run(avr_t * avr)
-{
-       if (avr->state == cpu_Stopped)
-               return avr->state;
-
-       uint16_t new_pc = avr->pc;
-
-       if (avr->state == cpu_Running) {
-               new_pc = avr_run_one(avr);
-               avr_dump_state(avr);
-       } else
-               avr->cycle ++;
-
-       // re-synth the SREG
-       //SREG();
-       // 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(avr, port);
-               port = port->next;
-       }
-
-       avr->pc = new_pc;
-
-       if (avr->state == cpu_Sleeping) {
-               if (!avr->sreg[S_I]) {
-                       printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
-                       exit(0);
-               }
-               usleep(500);
-               long sleep = (float)avr->frequency * (1.0f / 500.0f);
-               avr->cycle += sleep;
-       //      avr->state = cpu_Running;
-       }
-       // Interrupt servicing might change the PC too
-       if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
-               avr_service_interrupts(avr);
-
-               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);
-       }
-       return avr->state;
-}
-
-extern avr_kind_t tiny85;
-extern avr_kind_t mega48,mega88,mega168;
-extern avr_kind_t mega644;
-
-avr_kind_t * avr_kind[] = {
-       &tiny85,
-       &mega48,
-       &mega88,
-       &mega168,
-       &mega644,
-       NULL
-};
-
-void display_usage()
-{
-       printf("usage: simavr [-t] [-m <device>] [-f <frequency>] firmware\n");
-       printf("       -t: run full scale decoder trace\n");
-       exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-       elf_firmware_t f;
-       long f_cpu = 0;
-       int trace = 0;
-       char name[16] = "";
-       int option_count;
-       int option_index = 0;
-
-       struct option long_options[] = {
-               {"help", no_argument, 0, 'h'},
-               {"mcu", required_argument, 0, 'm'},
-               {"freq", required_argument, 0, 'f'},
-               {"trace", no_argument, 0, 't'},
-               {0, 0, 0, 0}
-       };
-
-       if (argc == 1)
-               display_usage();
-
-       while ((option_count = getopt_long(argc, argv, "thm:f:", long_options, &option_index)) != -1) {
-               switch (option_count) {
-                       case 'h':
-                               display_usage();
-                               break;
-                       case 'm':
-                               strcpy(name, optarg);
-                               break;
-                       case 'f':
-                               f_cpu = atoi(optarg);
-                               break;
-                       case 't':
-                               trace++;
-                               break;
-               }
-       }
-
-       elf_read_firmware(argv[argc-1], &f);
-
-       if (strlen(name))
-               strcpy(f.mmcu.name, name);
-       if (f_cpu)
-               f.mmcu.f_cpu = f_cpu;
-
-       printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], f.mmcu.f_cpu, f.mmcu.name);
-
-       avr_kind_t * maker = NULL;
-       for (int i = 0; avr_kind[i] && !maker; i++) {
-               for (int j = 0; avr_kind[i]->names[j]; j++)
-                       if (!strcmp(avr_kind[i]->names[j], f.mmcu.name)) {
-                               maker = avr_kind[i];
-                               break;
-                       }
-       }
-       if (!maker) {
-               fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
-               exit(1);
-       }
-
-       avr_t * avr = maker->make();
-       printf("Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end);
-       avr_init(avr);
-       avr->frequency = f.mmcu.f_cpu;
-       avr->codeline = f.codeline;
-       avr_loadcode(avr, f.flash, f.flashsize, 0);
-       avr->codeend = f.flashsize - f.datasize;
-       if (f.eeprom && f.eesize) {
-               avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
-               avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
-       }
-       avr->trace = trace;
-
-       // try to enable "local echo" on the first uart, for testing purposes
-       {
-               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);
-               printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
-               if (src && dst)
-                       avr_connect_irq(avr, src, dst);
-       }
-
-       for (long long i = 0; i < 8000000*10; i++)
-//     for (long long i = 0; i < 80000; i++)
-               avr_run(avr);
-       
-}
diff --git a/simavr/sim/simavr.h b/simavr/sim/simavr.h
deleted file mode 100644 (file)
index 61a7d03..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-       simavr.h
-
-       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
-       This file is part of simavr.
-
-       simavr is free software: you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
-       (at your option) any later version.
-
-       simavr is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIMAVR_H__
-#define __SIMAVR_H__
-
-#include <stdint.h>
-
-struct avr_t;
-typedef uint8_t (*avr_io_read_t)(struct avr_t * avr, uint8_t addr, void * param);
-typedef void (*avr_io_write_t)(struct avr_t * avr, uint8_t addr, uint8_t v, void * param);
-
-enum {
-       // SREG bit indexes
-       S_C = 0,S_Z,S_N,S_V,S_S,S_H,S_T,S_I,
-
-       // 16 bits register pairs
-       R_XL    = 0x1a, R_XH,R_YL,R_YH,R_ZL,R_ZH,
-       // stack pointer
-       R_SPL   = 32+0x3d, R_SPH,
-       // real SREG
-       R_SREG  = 32+0x3f,
-
-       // maximum number of IO regisrer, on normal AVRs
-       MAX_IOs = 256 - 32,     // minus 32 GP registers
-};
-
-#define AVR_DATA_TO_IO(v) ((v) - 32)
-#define AVR_IO_TO_DATA(v) ((v) + 32)
-
-/*
- * Core states. This will need populating with debug states for gdb
- */
-enum {
-       cpu_Limbo = 0,  // before initialization is finished
-       cpu_Stopped,
-       cpu_Running,
-       cpu_Sleeping,
-};
-
-/*
- * Main AVR instance. Some of these fields are set by the AVR "Core" definition files
- * the rest is runtime data (as little as possible)
- */
-typedef struct avr_t {
-       const char * mmcu;      // name of the AVR
-       // these are filled by sim_core_declare from constants in /usr/lib/avr/include/avr/io*.h
-       uint16_t        ramend;         
-       uint32_t        flashend;
-       uint32_t        e2end;
-       uint8_t         vector_size;
-       uint8_t         signature[3];
-       uint8_t         fuse[4];
-
-       // filled by the ELF data, this allow tracking of invalid jumps
-       uint32_t        codeend;
-
-       int                     state;          // stopped, running, sleeping
-       uint32_t        frequency;      // frequency we are running at
-       uint64_t        cycle;          // current cycle
-       
-       // called at init time
-       void (*init)(struct avr_t * avr);
-       // called at reset time
-       void (*reset)(struct avr_t * avr);
-
-       // 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
-       uint8_t         sreg[8];
-
-       /* 
-        * ** current PC **
-        * Note that the PC is reoresenting /bytes/ while the AVR value is
-        * assumed to be "words". This is in line with what GDB does...
-        * this is why you will see >>1 ane <<1 in the decoder to handle jumps
-        */
-       uint32_t        pc;
-
-       /*
-        * callback when specific IO registers are read/written
-        */
-       struct {
-               void * param;
-               avr_io_read_t r;
-       } ior[MAX_IOs];
-       struct {
-               void * param;
-               avr_io_write_t w;
-       } iow[MAX_IOs];
-
-       // flash memory (initialized to 0xff, and code loaded into it)
-       uint8_t *       flash;
-       // this is the general purpose registers, IO registers, and SRAM
-       uint8_t *       data;
-
-       // queue of io modules
-       struct avr_io_t *io_port;
-
-       // interrupt vectors, and their enable/clear registers
-       struct avr_int_vector_t * vector[64];
-       uint8_t         pending_wait;   // number of cycles to wait for pending
-       uint32_t        pending[2];             // pending interrupts
-
-       // DEBUG ONLY
-       int             trace;
-       struct avr_symbol_t ** codeline;
-
-       /* DEBUG ONLY
-        * this keeps track of "jumps" ie, call,jmp,ret,reti and so on
-        * allows dumping of a meaningful data even if the stack is
-        * munched and so on
-        */
-       #define OLD_PC_SIZE     32
-       struct {
-               uint32_t pc;
-               uint16_t sp;
-       } old[OLD_PC_SIZE]; // catches reset..
-       int                     old_pci;
-
-#if AVR_STACK_WATCH
-       #define STACK_FRAME_SIZE        32
-       // this records the call/ret pairs, to try to catch
-       // code that munches the stack -under- their own frame
-       struct {
-               uint32_t        pc;
-               uint16_t        sp;             
-       } stack_frame[STACK_FRAME_SIZE];
-       int                     stack_frame_index;
-#endif
-
-       // DEBUG ONLY
-       // keeps track of wich registers gets touched by instructions
-       // reset before each new instructions. Allows meaningful traces
-       uint32_t        touched[256 / 32];      // debug
-
-       // placeholder
-       struct avr_gdb_t * gdb;
-} avr_t;
-
-
-// this is a static constructor for each of the AVR devices
-typedef struct avr_kind_t {
-       const char * names[4];  // name aliases
-       avr_t * (*make)();
-} avr_kind_t;
-
-// a symbol loaded from the .elf file
-typedef struct avr_symbol_t {
-       const char * symbol;
-       uint32_t        addr;
-} avr_symbol_t;
-
-
-// initializes a new AVR instance. Will call the IO registers init(), and then reset()
-int avr_init(avr_t * avr);
-// resets the AVR, and the IO modules
-void avr_reset(avr_t * avr);
-
-// load code in the "flash"
-void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address);
-
-
-/*
- * these are accessors for avr->data but allows watchpoints to be set for gdb
- * IO modules use that to set values to registers, and the AVR core decoder uses
- * that to register "public" read by instructions.
- */
-void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v);
-uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr);
-
-
-#include "sim_io.h"
-#include "sim_regbit.h"
-#include "sim_interrupts.h"
-#include "sim_irq.h"
-
-#endif /*__SIMAVR_H__*/
-
index 5d0b0690871cc8710ca8b2796b8d0a8ca083021e..2ccfaf8dba99e6785ef32259b8f4913012b9cfac 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <avr/io.h>
 #include <avr/interrupt.h>
+#include <avr/sleep.h>
 
 #include "avr_mcu_section.h"
 AVR_MCU(F_CPU, "atmega48");
@@ -29,5 +30,5 @@ int main(void)
        // here the interupts are enabled, but the interupt
        // vector should not be called
        while(1)
-               ;
+               sleep_mode();
 }