From 24c5c6069017010fd7d27eda7585e38b5fff7a4b Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Wed, 2 Dec 2009 21:50:09 +0000 Subject: [PATCH] GDB working, some more source massaging 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 --- .gitignore | 1 + .simavr.jcc | 20 +- simavr/Makefile | 4 +- simavr/cores/sim_mega168.c | 2 +- simavr/cores/sim_mega48.c | 2 +- simavr/cores/sim_mega644.c | 2 +- simavr/cores/sim_mega88.c | 2 +- simavr/cores/sim_megax8.c | 2 +- simavr/cores/sim_megax8.h | 8 +- simavr/cores/sim_tiny85.c | 2 +- simavr/sim/avr_eeprom.c | 12 + simavr/sim/avr_eeprom.h | 2 +- simavr/sim/avr_ioport.h | 2 +- simavr/sim/avr_spi.c | 38 ++-- simavr/sim/avr_spi.h | 15 +- simavr/sim/avr_timer8.h | 2 +- simavr/sim/avr_uart.c | 2 +- simavr/sim/avr_uart.h | 2 +- simavr/sim/run_avr.c | 148 +++++++++++++ simavr/sim/{simavr.c => sim_avr.c} | 139 +++--------- simavr/sim/{simavr.h => sim_avr.h} | 16 +- simavr/sim/sim_core.c | 4 +- simavr/sim/sim_elf.c | 2 +- simavr/sim/sim_elf.h | 2 +- simavr/sim/sim_gdb.c | 340 ++++++++++++++++++++++++++++- simavr/sim/sim_gdb.h | 5 + simavr/sim/sim_interrupts.h | 2 +- simavr/sim/sim_io.h | 2 +- simavr/sim/sim_irq.h | 2 +- simavr/sim/sim_regbit.h | 2 +- tests/atmega48_disabled_timer.c | 3 +- 31 files changed, 613 insertions(+), 174 deletions(-) create mode 100644 simavr/sim/run_avr.c rename simavr/sim/{simavr.c => sim_avr.c} (64%) rename simavr/sim/{simavr.h => sim_avr.h} (94%) diff --git a/.gitignore b/.gitignore index b3de6c0..543ae13 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ obj *.hex *.s simavr/simavr +simavr/run_avr diff --git a/.simavr.jcc b/.simavr.jcc index b69769e..d7a4a41 100644 --- a/.simavr.jcc +++ b/.simavr.jcc @@ -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" diff --git a/simavr/Makefile b/simavr/Makefile index 6138d99..3625912 100644 --- a/simavr/Makefile +++ b/simavr/Makefile @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with simavr. If not, see . -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} diff --git a/simavr/cores/sim_mega168.c b/simavr/cores/sim_mega168.c index 54d8bcf..8d0f2e4 100644 --- a/simavr/cores/sim_mega168.c +++ b/simavr/cores/sim_mega168.c @@ -19,7 +19,7 @@ along with simavr. If not, see . */ -#include "simavr.h" +#include "sim_avr.h" #define SIM_VECTOR_SIZE 4 #define SIM_MMCU "atmega168" diff --git a/simavr/cores/sim_mega48.c b/simavr/cores/sim_mega48.c index b0b0c95..08771af 100644 --- a/simavr/cores/sim_mega48.c +++ b/simavr/cores/sim_mega48.c @@ -19,7 +19,7 @@ along with simavr. If not, see . */ -#include "simavr.h" +#include "sim_avr.h" #define SIM_VECTOR_SIZE 2 #define SIM_MMCU "atmega48" diff --git a/simavr/cores/sim_mega644.c b/simavr/cores/sim_mega644.c index 22b439d..f240a2f 100644 --- a/simavr/cores/sim_mega644.c +++ b/simavr/cores/sim_mega644.c @@ -20,7 +20,7 @@ */ #include -#include "simavr.h" +#include "sim_avr.h" #include "sim_core_declare.h" #include "avr_eeprom.h" #include "avr_ioport.h" diff --git a/simavr/cores/sim_mega88.c b/simavr/cores/sim_mega88.c index c5e43cb..59bc480 100644 --- a/simavr/cores/sim_mega88.c +++ b/simavr/cores/sim_mega88.c @@ -19,7 +19,7 @@ along with simavr. If not, see . */ -#include "simavr.h" +#include "sim_avr.h" #define SIM_VECTOR_SIZE 2 #define SIM_MMCU "atmega88" diff --git a/simavr/cores/sim_megax8.c b/simavr/cores/sim_megax8.c index 44bf334..7b1f293 100644 --- a/simavr/cores/sim_megax8.c +++ b/simavr/cores/sim_megax8.c @@ -19,7 +19,7 @@ along with simavr. If not, see . */ #include -#include "simavr.h" +#include "sim_avr.h" #include "sim_megax8.h" diff --git a/simavr/cores/sim_megax8.h b/simavr/cores/sim_megax8.h index 8ea2bd3..97eb61e 100644 --- a/simavr/cores/sim_megax8.h +++ b/simavr/cores/sim_megax8.h @@ -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 = { diff --git a/simavr/cores/sim_tiny85.c b/simavr/cores/sim_tiny85.c index e4d7af3..eec13a6 100644 --- a/simavr/cores/sim_tiny85.c +++ b/simavr/cores/sim_tiny85.c @@ -20,7 +20,7 @@ */ #include -#include "simavr.h" +#include "sim_avr.h" #include "sim_core_declare.h" #include "avr_eeprom.h" #include "avr_ioport.h" diff --git a/simavr/sim/avr_eeprom.c b/simavr/sim/avr_eeprom.c index b6ff5a1..53c82f0 100644 --- a/simavr/sim/avr_eeprom.c +++ b/simavr/sim/avr_eeprom.c @@ -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; diff --git a/simavr/sim/avr_eeprom.h b/simavr/sim/avr_eeprom.h index c7f1dcd..89678fe 100644 --- a/simavr/sim/avr_eeprom.h +++ b/simavr/sim/avr_eeprom.h @@ -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; diff --git a/simavr/sim/avr_ioport.h b/simavr/sim/avr_ioport.h index 04d0890..0a1ca37 100644 --- a/simavr/sim/avr_ioport.h +++ b/simavr/sim/avr_ioport.h @@ -22,7 +22,7 @@ #ifndef __AVR_IOPORT_H__ #define __AVR_IOPORT_H__ -#include "simavr.h" +#include "sim_avr.h" enum { IOPORT_IRQ_PIN0 = 0, diff --git a/simavr/sim/avr_spi.c b/simavr/sim/avr_spi.c index b373e8e..01b0d7f 100644 --- a/simavr/sim/avr_spi.c +++ b/simavr/sim/avr_spi.c @@ -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); } diff --git a/simavr/sim/avr_spi.h b/simavr/sim/avr_spi.h index e15176a..2c24e52 100644 --- a/simavr/sim/avr_spi.h +++ b/simavr/sim/avr_spi.h @@ -22,7 +22,16 @@ #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 diff --git a/simavr/sim/avr_timer8.h b/simavr/sim/avr_timer8.h index b73a831..1f3ecca 100644 --- a/simavr/sim/avr_timer8.h +++ b/simavr/sim/avr_timer8.h @@ -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; diff --git a/simavr/sim/avr_uart.c b/simavr/sim/avr_uart.c index e24609a..35b8b0d 100644 --- a/simavr/sim/avr_uart.c +++ b/simavr/sim/avr_uart.c @@ -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; diff --git a/simavr/sim/avr_uart.h b/simavr/sim/avr_uart.h index 9de90d2..81b4e13 100644 --- a/simavr/sim/avr_uart.h +++ b/simavr/sim/avr_uart.h @@ -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 index 0000000..4560033 --- /dev/null +++ b/simavr/sim/run_avr.c @@ -0,0 +1,148 @@ +/* + run_avr.c + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#include +#include +#include +#include +#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 ] [-f ] 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/simavr.c b/simavr/sim/sim_avr.c similarity index 64% rename from simavr/sim/simavr.c rename to simavr/sim/sim_avr.c index 7cb73fa..16a908a 100644 --- a/simavr/sim/simavr.c +++ b/simavr/sim/sim_avr.c @@ -1,5 +1,5 @@ /* - simavr.c + sim_avr.c Copyright 2008, 2009 Michel Pollet @@ -19,41 +19,13 @@ along with simavr. If not, see . */ -#include -#include -#include #include #include #include -#include -#include -#include "simavr.h" -#include "sim_elf.h" - +#include +#include "sim_avr.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"); -} - +#include "sim_gdb.h" int avr_init(avr_t * avr) @@ -89,7 +61,6 @@ void avr_reset(avr_t * avr) port->reset(avr, port); port = port->next; } - } @@ -136,9 +107,18 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) int avr_run(avr_t * avr) { - if (avr->state == cpu_Stopped) + 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) { @@ -185,9 +165,15 @@ int avr_run(avr_t * avr) } 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; @@ -201,96 +187,23 @@ avr_kind_t * avr_kind[] = { NULL }; -void display_usage() +avr_t * avr_make_mcu_by_name(const char *name) { - printf("usage: simavr [-t] [-m ] [-f ] 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)) { + if (!strcmp(avr_kind[i]->names[j], name)) { maker = avr_kind[i]; break; } } if (!maker) { - fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name); - exit(1); + 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); - 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); - + return avr; } + diff --git a/simavr/sim/simavr.h b/simavr/sim/sim_avr.h similarity index 94% rename from simavr/sim/simavr.h rename to simavr/sim/sim_avr.h index 61a7d03..fe7f36d 100644 --- a/simavr/sim/simavr.h +++ b/simavr/sim/sim_avr.h @@ -1,5 +1,5 @@ /* - simavr.h + sim_avr.h Copyright 2008, 2009 Michel Pollet @@ -19,8 +19,8 @@ along with simavr. If not, see . */ -#ifndef __SIMAVR_H__ -#define __SIMAVR_H__ +#ifndef __SIM_AVR_H__ +#define __SIM_AVR_H__ #include @@ -54,6 +54,9 @@ enum { cpu_Stopped, cpu_Running, cpu_Sleeping, + + cpu_Step, + cpu_StepDone, }; /* @@ -169,11 +172,14 @@ typedef struct avr_symbol_t { 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); @@ -193,5 +199,5 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr); #include "sim_interrupts.h" #include "sim_irq.h" -#endif /*__SIMAVR_H__*/ +#endif /*__SIM_AVR_H__*/ diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index 0980ab5..b70edd6 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -23,7 +23,7 @@ #include #include #include -#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"); diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 1270d67..02aaa93 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -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 diff --git a/simavr/sim/sim_elf.h b/simavr/sim/sim_elf.h index 7b13e51..aa6bc77 100644 --- a/simavr/sim/sim_elf.h +++ b/simavr/sim/sim_elf.h @@ -29,7 +29,7 @@ #endif #if ELF_SYMBOLS -#include "simavr.h" +#include "sim_avr.h" #endif typedef struct elf_firmware_t { diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index 74714d1..eac0d20 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -1,8 +1,6 @@ /* sim_gdb.c - Placeholder! - Copyright 2008, 2009 Michel Pollet This file is part of simavr. @@ -25,19 +23,342 @@ #include #include #include +#include #include #include #include #include #include #include -#include "simavr.h" +#include +#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", ®i); + 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; } diff --git a/simavr/sim/sim_gdb.h b/simavr/sim/sim_gdb.h index 67f7a07..cbd4ed1 100644 --- a/simavr/sim/sim_gdb.h +++ b/simavr/sim/sim_gdb.h @@ -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 diff --git a/simavr/sim/sim_interrupts.h b/simavr/sim/sim_interrupts.h index 270b39d..c602e8e 100644 --- a/simavr/sim/sim_interrupts.h +++ b/simavr/sim/sim_interrupts.h @@ -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 { diff --git a/simavr/sim/sim_io.h b/simavr/sim/sim_io.h index 770b3a8..87eb5b9 100644 --- a/simavr/sim/sim_io.h +++ b/simavr/sim/sim_io.h @@ -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 diff --git a/simavr/sim/sim_irq.h b/simavr/sim/sim_irq.h index 9349d30..161c311 100644 --- a/simavr/sim/sim_irq.h +++ b/simavr/sim/sim_irq.h @@ -22,7 +22,7 @@ #ifndef __SIM_IRQ_H__ #define __SIM_IRQ_H__ -#include "simavr.h" +#include "sim_avr.h" /* * Internal IRQ system diff --git a/simavr/sim/sim_regbit.h b/simavr/sim/sim_regbit.h index 719dbba..11700c8 100644 --- a/simavr/sim/sim_regbit.h +++ b/simavr/sim/sim_regbit.h @@ -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/tests/atmega48_disabled_timer.c b/tests/atmega48_disabled_timer.c index 5d0b069..2ccfaf8 100644 --- a/tests/atmega48_disabled_timer.c +++ b/tests/atmega48_disabled_timer.c @@ -7,6 +7,7 @@ #include #include +#include #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(); } -- 2.39.5