From: Michel Pollet Date: Thu, 3 Dec 2009 23:31:42 +0000 (+0000) Subject: Polished gdb support, etc X-Git-Tag: v1.0a1~72 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=4ebde35337d05315c5170390377ef3a0f9dde53c;p=sx%2Fsimavr.git Polished gdb support, etc GDB handler re-done, removed the thread, removed the pauses, Now as fast as possible for stepping trhu code. Note you /need/ the dwarf-2 debug symbols for gdb to work properly, a simple '-g' will not work. Also added a mode that starts the gdb server and waits if the AVR core detects a "crash". Added a piece if test unit to test just that. Signed-off-by: Michel Pollet --- diff --git a/.gitignore b/.gitignore index 543ae13..f7e610b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ obj *.s simavr/simavr simavr/run_avr +*.a diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 0000000..1f89b04 --- /dev/null +++ b/Makefile.common @@ -0,0 +1,48 @@ +# +# This makefile take each "at*" file, extracts it's part name +# And compile it into an ELF binary. +# It also disassemble it for debugging purposes. +# +# The code is compiled "optimized" to the max. +# +# The wierd "-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000" +# is used to tell the linker not to discard the .mmcu section, +# otherwise the --gc-sections will delete it. +# +# 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 . + +%.hex: %.axf + @${AVR}objcopy -j .text -j .data -O ihex ${<} ${@} + +%.s: %.axf + @${AVR}objdump -j .text -j .data -j .bss -d ${<} > ${@} + +# --mcall-prologues +%.axf: %.c + @echo CC ${<} + @part=${<} ; part=$${part/_*}; \ + ${AVR}gcc -Wall -gdwarf-2 -Os -std=gnu99 \ + -mmcu=$$part \ + -DF_CPU=8000000 \ + -fno-inline-small-functions \ + -ffunction-sections -fdata-sections \ + -Wl,--relax,--gc-sections \ + -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \ + -I../include \ + ${<} -o ${@} + @${AVR}size ${@}|sed '1d' diff --git a/simavr/Makefile b/simavr/Makefile index 3625912..eba24e0 100644 --- a/simavr/Makefile +++ b/simavr/Makefile @@ -29,7 +29,7 @@ CFLAGS += -O3 -mfpmath=sse -msse2 cores = ${wildcard cores/*.c} cores_o = ${patsubst cores/%.c, obj/%.o, ${cores}} -sim = ${wildcard sim/*.c} +sim = ${wildcard sim/sim_*.c} ${wildcard sim/avr_*.c} sim_o = ${patsubst sim/%.c, obj/%.o, ${sim}} VPATH = . @@ -44,9 +44,9 @@ IPATH += /opt/local/include CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}} LFLAGS = -L/opt/local/lib/ -LDFLAGS += -lelf -lpthread +LDFLAGS += -lelf -all: obj ${target} +all: obj ${target} libsimavr.a obj: @mkdir -p obj @@ -63,14 +63,20 @@ obj/%.o: %.c @gcc $(CFLAGS) \ $< -c -o $@ @echo CC $< - + +libsimavr.a : ${cores_o} +libsimavr.a : ${sim_o} + ar cru $@ $^ + ranlib $@ + ${target} : ${cores_o} ${target} : ${sim_o} +${target} : obj/${target}.o @gcc $(CFLAGS) $(LFLAGS) \ ${^} -o $@ \ $(LDFLAGS) @echo LD $@ clean: - rm -rf ${target} obj + rm -rf ${target} obj *.a diff --git a/simavr/cores/sim_mega644.c b/simavr/cores/sim_mega644.c index f240a2f..cc1b396 100644 --- a/simavr/cores/sim_mega644.c +++ b/simavr/cores/sim_mega644.c @@ -26,6 +26,7 @@ #include "avr_ioport.h" #include "avr_uart.h" #include "avr_timer8.h" +#include "avr_spi.h" #define _AVR_IO_H_ #define __ASSEMBLER__ @@ -41,6 +42,7 @@ static struct mcu_t { avr_ioport_t porta, portb, portc, portd; avr_uart_t uart0,uart1; avr_timer8_t timer0,timer2; + avr_spi_t spi; } mcu = { .core = { .mmcu = "atmega644", @@ -201,6 +203,23 @@ static struct mcu_t { .vector = TIMER2_COMPB_vect, }, }, + .spi = { + .disabled = AVR_IO_REGBIT(PRR,PRSPI), + + .r_spdr = SPDR, + .r_spcr = SPCR, + .r_spsr = SPSR, + + .spe = AVR_IO_REGBIT(SPCR, SPE), + .mstr = AVR_IO_REGBIT(SPCR, MSTR), + + .spr = { AVR_IO_REGBIT(SPCR, SPR0), AVR_IO_REGBIT(SPCR, SPR1), AVR_IO_REGBIT(SPSR, SPI2X) }, + .spi = { + .enable = AVR_IO_REGBIT(SPCR, SPIE), + .raised = AVR_IO_REGBIT(SPSR, SPIF), + .vector = SPI_STC_vect, + }, + }, }; static avr_t * make() @@ -228,6 +247,7 @@ static void init(struct avr_t * avr) avr_uart_init(avr, &mcu->uart1); avr_timer8_init(avr, &mcu->timer0); avr_timer8_init(avr, &mcu->timer2); + avr_spi_init(avr, &mcu->spi); } static void reset(struct avr_t * avr) diff --git a/simavr/cores/sim_tiny85.c b/simavr/cores/sim_tiny85.c index eec13a6..aac8299 100644 --- a/simavr/cores/sim_tiny85.c +++ b/simavr/cores/sim_tiny85.c @@ -120,6 +120,7 @@ static avr_t * make() } avr_kind_t tiny85 = { + .names = { "attiny85" }, .make = make }; diff --git a/simavr/sim/avr_eeprom.c b/simavr/sim/avr_eeprom.c index 53c82f0..eebdf31 100644 --- a/simavr/sim/avr_eeprom.c +++ b/simavr/sim/avr_eeprom.c @@ -26,9 +26,10 @@ #include #include "avr_eeprom.h" -static void avr_eeprom_run(avr_t * avr, avr_io_t * port) +static void avr_eeprom_run(avr_io_t * port) { avr_eeprom_t * p = (avr_eeprom_t *)port; + avr_t * avr = p->io.avr; //printf("%s\n", __FUNCTION__); if (p->eempe_clear_timer) { p->eempe_clear_timer--; @@ -44,7 +45,7 @@ static void avr_eeprom_run(avr_t * avr, avr_io_t * port) } } -static void avr_eeprom_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * param) +static void avr_eeprom_write(avr_t * avr, uint8_t addr, uint8_t v, void * param) { avr_eeprom_t * p = (avr_eeprom_t *)param; uint8_t eempe = avr_regbit_get(avr, p->eempe); @@ -76,7 +77,7 @@ static void avr_eeprom_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * avr_regbit_clear(avr, p->eere); } -static int avr_eeprom_ioctl(avr_t * avr, avr_io_t * port, uint32_t ctl, void * io_param) +static int avr_eeprom_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) { avr_eeprom_t * p = (avr_eeprom_t *)port; int res = -1; diff --git a/simavr/sim/avr_ioport.c b/simavr/sim/avr_ioport.c index 7394c0c..2b3eaae 100644 --- a/simavr/sim/avr_ioport.c +++ b/simavr/sim/avr_ioport.c @@ -22,11 +22,6 @@ #include #include "avr_ioport.h" -static void avr_ioport_run(avr_t * avr, avr_io_t * port) -{ - //printf("%s\n", __FUNCTION__); -} - static uint8_t avr_ioport_read(struct avr_t * avr, uint8_t addr, void * param) { avr_ioport_t * p = (avr_ioport_t *)param; @@ -58,8 +53,8 @@ static void avr_ioport_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * // raise the internal IRQ callbacks for (int i = 0; i < 8; i++) if (mask & (1 << i)) - avr_raise_irq(avr, p->io.irq + i, (v >> i) & 1); - avr_raise_irq(avr, p->io.irq + IOPORT_IRQ_PIN_ALL, v); + avr_raise_irq(p->io.irq + i, (v >> i) & 1); + avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v); } } } @@ -69,9 +64,10 @@ static void avr_ioport_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * * AVR code, or any external piece of code that see fit to do it. * Either way, this will raise pin change interrupts, if needed */ -void avr_ioport_irq_notify(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param) +void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) { avr_ioport_t * p = (avr_ioport_t *)param; + avr_t * avr = p->io.avr; if (p->r_pcint) { uint8_t mask = 1 << irq->irq; // set the real PIN bit. ddr doesn't matter here as it's masked when read. @@ -85,16 +81,15 @@ void avr_ioport_irq_notify(avr_t * avr, struct avr_irq_t * irq, uint32_t value, } } -static void avr_ioport_reset(avr_t * avr, avr_io_t * port) +static void avr_ioport_reset(avr_io_t * port) { avr_ioport_t * p = (avr_ioport_t *)port; for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++) - avr_irq_register_notify(avr, p->io.irq + i, avr_ioport_irq_notify, p); + avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p); } static avr_io_t _io = { .kind = "io", - .run = avr_ioport_run, .reset = avr_ioport_reset, }; @@ -108,7 +103,7 @@ void avr_ioport_init(avr_t * avr, avr_ioport_t * p) // allocate this module's IRQ p->io.irq_count = IOPORT_IRQ_COUNT; - p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count); + p->io.irq = avr_alloc_irq(0, p->io.irq_count); p->io.irq_ioctl_get = AVR_IOCTL_IOPORT_GETIRQ(p->name); avr_register_io(avr, &p->io); diff --git a/simavr/sim/avr_spi.c b/simavr/sim/avr_spi.c index 01b0d7f..1ef1ee9 100644 --- a/simavr/sim/avr_spi.c +++ b/simavr/sim/avr_spi.c @@ -22,15 +22,11 @@ #include #include "avr_spi.h" -static void avr_spi_run(avr_t * avr, avr_io_t * port) -{ -// printf("%s\n", __FUNCTION__); -} - static uint8_t avr_spi_read(struct avr_t * avr, uint8_t addr, void * param) { avr_spi_t * p = (avr_spi_t *)param; - uint8_t v = avr->data[addr]; + uint8_t v = p->input_data_register; + p->input_data_register = 0; // printf("** PIN%c = %02x\n", p->name, v); return v; } @@ -42,29 +38,44 @@ static void avr_spi_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * pa if (addr == p->r_spdr) { // printf("UDR%c(%02x) = %02x\n", p->name, addr, v); avr_core_watch_write(avr, addr, v); + + if (avr_regbit_get(avr, p->spe)) { + // in master mode, any byte is sent as it comes.. + if (avr_regbit_get(avr, p->mstr)) { + avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, v); + } + } } } -static void avr_spi_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param) +static void avr_spi_irq_input(struct avr_irq_t * irq, uint32_t value, void * param) { avr_spi_t * p = (avr_spi_t *)param; + avr_t * avr = p->io.avr; // check to see fi receiver is enabled if (!avr_regbit_get(avr, p->spe)) return; // double buffer the input.. ? + p->input_data_register = value; + avr_raise_interrupt(avr, &p->spi); + + // if in slave mode, + // 'output' the byte only when we received one... + if (!avr_regbit_get(avr, p->mstr)) { + avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]); + } } -void avr_spi_reset(avr_t * avr, struct avr_io_t *io) +void avr_spi_reset(struct avr_io_t *io) { avr_spi_t * p = (avr_spi_t *)io; - avr_irq_register_notify(avr, p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p); + avr_irq_register_notify(p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p); } static avr_io_t _io = { .kind = "spi", - .run = avr_spi_run, .reset = avr_spi_reset, }; @@ -77,7 +88,7 @@ void avr_spi_init(avr_t * avr, avr_spi_t * 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 = avr_alloc_irq(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); diff --git a/simavr/sim/avr_spi.h b/simavr/sim/avr_spi.h index 2c24e52..9926e66 100644 --- a/simavr/sim/avr_spi.h +++ b/simavr/sim/avr_spi.h @@ -47,6 +47,8 @@ typedef struct avr_spi_t { avr_regbit_t spr[4]; // clock divider avr_int_vector_t spi; // spi interrupt + + uint8_t input_data_register; } avr_spi_t; void avr_spi_init(avr_t * avr, avr_spi_t * port); diff --git a/simavr/sim/avr_timer8.c b/simavr/sim/avr_timer8.c index 6cf20c0..1e209f9 100644 --- a/simavr/sim/avr_timer8.c +++ b/simavr/sim/avr_timer8.c @@ -25,10 +25,10 @@ #include #include "avr_timer8.h" -static void avr_timer8_run(avr_t * avr, avr_io_t * port) +static void avr_timer8_run(avr_io_t * port) { avr_timer8_t * p = (avr_timer8_t *)port; - //printf("%s\n", __FUNCTION__); + avr_t * avr = p->io.avr; if (p->compa_cycles) { if (p->compa_next == 0) { @@ -79,7 +79,7 @@ static void avr_timer8_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * } -static void avr_timer8_reset(avr_t * avr, avr_io_t * port) +static void avr_timer8_reset(avr_io_t * port) { } diff --git a/simavr/sim/avr_uart.c b/simavr/sim/avr_uart.c index 35b8b0d..e268cf7 100644 --- a/simavr/sim/avr_uart.c +++ b/simavr/sim/avr_uart.c @@ -28,9 +28,10 @@ DEFINE_FIFO(uint8_t, uart_fifo, 128); -static void avr_uart_run(avr_t * avr, avr_io_t * port) +static void avr_uart_run(avr_io_t * port) { avr_uart_t * p = (avr_uart_t *)port; + avr_t * avr = p->io.avr; if (p->input_cycle_timer) { p->input_cycle_timer--; if (p->input_cycle_timer == 0) { @@ -81,7 +82,7 @@ static void avr_uart_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * p } // tell other modules we are "outputing" a byte if (avr_regbit_get(avr, p->txen)) - avr_raise_irq(avr, p->io.irq + UART_IRQ_OUTPUT, v); + avr_raise_irq(p->io.irq + UART_IRQ_OUTPUT, v); } else { // get the bits before the write uint8_t udre = avr_regbit_get(avr, p->udrc.raised); @@ -97,9 +98,10 @@ static void avr_uart_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * p } } -static void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param) +static void avr_uart_irq_input(struct avr_irq_t * irq, uint32_t value, void * param) { avr_uart_t * p = (avr_uart_t *)param; + avr_t * avr = p->io.avr; // check to see fi receiver is enabled if (!avr_regbit_get(avr, p->rxen)) @@ -112,11 +114,12 @@ static void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t val } -void avr_uart_reset(avr_t * avr, struct avr_io_t *io) +void avr_uart_reset(struct avr_io_t *io) { avr_uart_t * p = (avr_uart_t *)io; + avr_t * avr = p->io.avr; avr_regbit_set(avr, p->udrc.raised); - avr_irq_register_notify(avr, p->io.irq + UART_IRQ_INPUT, avr_uart_irq_input, p); + avr_irq_register_notify(p->io.irq + UART_IRQ_INPUT, avr_uart_irq_input, p); p->input_cycle_timer = 0; uart_fifo_reset(&p->input); } @@ -136,7 +139,7 @@ void avr_uart_init(avr_t * avr, avr_uart_t * p) // allocate this module's IRQ p->io.irq_count = UART_IRQ_COUNT; - p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count); + p->io.irq = avr_alloc_irq(0, p->io.irq_count); p->io.irq_ioctl_get = AVR_IOCTL_UART_GETIRQ(p->name); avr_register_io_write(avr, p->r_udr, avr_uart_write, p); diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index 4560033..49c374c 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -27,7 +27,6 @@ #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) @@ -116,33 +115,25 @@ int main(int argc, char *argv[]) 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_load_firmware(avr, &f); 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 (src && dst) { + printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst); + avr_connect_irq(src, dst); + } } - + // even if not setup at startup, activate gdb if crashing + avr->gdb_port = 1234; 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); - + avr_run(avr); } diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 16a908a..46ed8de 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -58,11 +58,22 @@ void avr_reset(avr_t * avr) avr_io_t * port = avr->io_port; while (port) { if (port->reset) - port->reset(avr, port); + port->reset(port); port = port->next; } } +void avr_sadly_crashed(avr_t *avr, uint8_t signal) +{ + avr->state = cpu_Stopped; + if (avr->gdb_port) { + // enable gdb server, and wait + if (!avr->gdb) + avr_gdb_init(avr); + } + if (!avr->gdb) + exit(1); // no gdb ? +} void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address) { @@ -107,13 +118,12 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) int avr_run(avr_t * avr) { - avr_gdb_processor(avr); + avr_gdb_processor(avr, avr->state == cpu_Stopped); - if (avr->state == cpu_Stopped) { - usleep(500); + if (avr->state == cpu_Stopped) return avr->state; - } + // if we are stepping one insruction, we "run" for one.. int step = avr->state == cpu_Step; if (step) { avr->state = cpu_Running; @@ -137,7 +147,7 @@ int avr_run(avr_t * avr) avr_io_t * port = avr->io_port; while (port) { if (port->run) - port->run(avr, port); + port->run(port); port = port->next; } @@ -148,7 +158,11 @@ int avr_run(avr_t * avr) printf("simavr: sleeping with interrupts off, quitting gracefuly\n"); exit(0); } - usleep(500); + if (avr->gdb) { + while (avr_gdb_processor(avr, 1)) + ; + } else + usleep(500); long sleep = (float)avr->frequency * (1.0f / 500.0f); avr->cycle += sleep; // avr->state = cpu_Running; diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index fe7f36d..0af4836 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -155,8 +155,12 @@ typedef struct avr_t { // reset before each new instructions. Allows meaningful traces uint32_t touched[256 / 32]; // debug - // placeholder + // gdb hooking structure. Only present when gdb server is active struct avr_gdb_t * gdb; + // if non-zero, the gdb server will be started when the core + // crashed even if not activated at startup + // if zero, the simulator will just exit() in case of a crash + int gdb_port; } avr_t; @@ -193,6 +197,9 @@ void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address); 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); +// called when the core has detected a crash somehow. +// this might activate gdb server +void avr_sadly_crashed(avr_t *avr, uint8_t signal); #include "sim_io.h" #include "sim_regbit.h" diff --git a/simavr/sim/sim_core.h b/simavr/sim/sim_core.h index bdc1626..e5e2a96 100644 --- a/simavr/sim/sim_core.h +++ b/simavr/sim/sim_core.h @@ -76,7 +76,7 @@ void avr_dump_state(avr_t * avr); }\ printf("Stack Ptr %04x/%04x = %d \n", _avr_sp_get(avr), avr->ramend, avr->ramend - _avr_sp_get(avr));\ DUMP_STACK();\ - exit(1);\ + avr_sadly_crashed(avr, 0);\ } #endif /* SIM_CORE_H_ */ diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 02aaa93..8cdb12a 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -33,6 +33,19 @@ #include #include "sim_elf.h" +#include "avr_eeprom.h" + +void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) +{ + avr->frequency = firmware->mmcu.f_cpu; + avr->codeline = firmware->codeline; + avr_loadcode(avr, firmware->flash, firmware->flashsize, 0); + avr->codeend = firmware->flashsize - firmware->datasize; + if (firmware->eeprom && firmware->eesize) { + avr_eeprom_desc_t d = { .ee = firmware->eeprom, .offset = 0, .size = firmware->eesize }; + avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d); + } +} int elf_read_firmware(const char * file, elf_firmware_t * firmware) { @@ -89,7 +102,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(struct 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 aa6bc77..bc61613 100644 --- a/simavr/sim/sim_elf.h +++ b/simavr/sim/sim_elf.h @@ -28,9 +28,7 @@ #define ELF_SYMBOLS 1 #endif -#if ELF_SYMBOLS #include "sim_avr.h" -#endif typedef struct elf_firmware_t { struct avr_mcu_t mmcu; @@ -50,4 +48,6 @@ typedef struct elf_firmware_t { int elf_read_firmware(const char * file, elf_firmware_t * firmware); +void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware); + #endif /* ELF_H_ */ diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index eac0d20..751f511 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -34,15 +34,12 @@ #include "sim_avr.h" #include "avr_eeprom.h" +#define DBG(w) + typedef struct avr_gdb_t { avr_t * avr; int listen; // listen socket int s; // current gdb connection - - pthread_t thread; - - uint32_t query_len; - char query[1024]; uint32_t watchmap; struct { @@ -91,7 +88,7 @@ static void gdb_send_reply(avr_gdb_t * g, char * cmd) *dst++ = *cmd++; } sprintf((char*)dst, "#%02x", check); - printf("%s '%s'\n", __FUNCTION__, reply); + DBG(printf("%s '%s'\n", __FUNCTION__, reply);) send(g->s, reply, dst - reply + 3, 0); } @@ -100,7 +97,7 @@ 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], + signal ? signal : 5, 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); @@ -108,7 +105,7 @@ static void gdb_send_quick_status(avr_gdb_t * g, uint8_t signal) 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); + DBG(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 @@ -140,46 +137,95 @@ static int gdb_change_breakpoint(avr_gdb_t * g, int set, int kind, uint32_t addr return -1; } -static void gdb_handle_command(avr_gdb_t * g) +static int gdb_write_register(avr_gdb_t * g, int regi, uint8_t * src) +{ + switch (regi) { + case 0 ... 31: + g->avr->data[regi] = *src; + return 1; + case 32: + g->avr->data[R_SREG] = * src; + return 1; + case 33: + g->avr->data[R_SPL] = *src++; + g->avr->data[R_SPH] = *src++; + return 2; + case 34: + g->avr->pc = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + return 4; + } + return 1; +} + +static int gdb_read_register(avr_gdb_t * g, int regi, char * rep) +{ + 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; + } + return strlen(rep); +} + +static void gdb_handle_command(avr_gdb_t * g, char * cmd) { avr_t * avr = g->avr; - char * cmd = g->query; char rep[1024]; uint8_t command = *cmd++; switch (command) { case '?': - gdb_send_reply(g, "S00"); + gdb_send_quick_status(g, 0); break; - case 'p': { + case 'G': { // set all general purpose registers + // get their binary form + read_hex_string(cmd, (uint8_t*)rep, strlen(cmd)); + uint8_t *src = (uint8_t*)rep; + for (int i = 0; i < 35; i++) + src += gdb_write_register(g, i, src); + gdb_send_reply(g, "OK"); + } break; + case 'g': { // read all general purpose registers + char * dst = rep; + for (int i = 0; i < 35; i++) + dst += gdb_read_register(g, i, dst); + gdb_send_reply(g, rep); + } break; + case 'p': { // read register 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_read_register(g, regi, rep); gdb_send_reply(g, rep); } break; - case 'm': { + case 'P': { // write register + unsigned int regi = 0; + char * val = strchr(cmd, '='); + if (!val) + break; + *val++ = 0; + sscanf(cmd, "%x", ®i); + read_hex_string(val, (uint8_t*)rep, strlen(val)); + gdb_write_register(g, regi, (uint8_t*)rep); + gdb_send_reply(g, "OK"); + } break; + case 'm': { // read memory 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)) { + } else if (addr >= 0x810000 && (addr - 0x810000) <= avr->e2end) { avr_eeprom_desc_t ee = {.offset = (addr - 0x810000)}; avr_ioctl(avr, AVR_IOCTL_EEPROM_GET, &ee); if (ee.ee) @@ -187,6 +233,7 @@ static void gdb_handle_command(avr_gdb_t * g) else gdb_send_reply(g, "E01"); } else { + printf("read memory error %08x, %08x (ramend %04x)\n", addr, len, avr->ramend+1); gdb_send_reply(g, "E01"); break; } @@ -198,10 +245,9 @@ static void gdb_handle_command(avr_gdb_t * g) *dst = 0; gdb_send_reply(g, rep); } break; - case 'M': { + case 'M': { // write memory 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"); @@ -213,20 +259,27 @@ static void gdb_handle_command(avr_gdb_t * g) } 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"); + } else if (addr >= 0x810000 && (addr - 0x810000) <= avr->e2end) { + read_hex_string(start + 1, (uint8_t*)rep, strlen(start+1)); + avr_eeprom_desc_t ee = {.offset = (addr - 0x810000), .size = len, .ee = (uint8_t*)rep }; + avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &ee); + gdb_send_reply(g, "OK"); + } else { + printf("write memory error %08x, %08x\n", addr, len); + gdb_send_reply(g, "E01"); + } } break; - case 'c': { + case 'c': { // continue avr->state = cpu_Running; } break; - case 's': { + case 's': { // step avr->state = cpu_Step; } break; - case 'Z': + case 'Z': // set clear break/watchpoint case 'z': { uint32_t kind, addr, len; sscanf(cmd, "%d,%x,%x", &kind, &addr, &len); - printf("breakbpoint %d, %08x, %08x\n", kind, addr, len); +// printf("breakbpoint %d, %08x, %08x\n", kind, addr, len); switch (kind) { case 0: // software breakpoint case 1: // hardware breakpoint @@ -238,6 +291,7 @@ static void gdb_handle_command(avr_gdb_t * g) } else gdb_send_reply(g, "E01"); // out of flash address break; + // TODO case 2: // write watchpoint case 3: // read watchpoint case 4: // access watchpoint @@ -250,16 +304,97 @@ static void gdb_handle_command(avr_gdb_t * g) } } -void avr_gdb_processor(avr_t * avr) +static int gdb_network_handler(avr_gdb_t * g, int dosleep) +{ + fd_set read_set; + int max; + FD_ZERO(&read_set); + + if (g->s != -1) { + FD_SET(g->s, &read_set); + max = g->s + 1; + } else { + FD_SET(g->listen, &read_set); + max = g->listen + 1; + } + struct timeval timo = { 0, dosleep ? 500 : 0 }; // short, but not too short interval + int ret = select(max, &read_set, NULL, NULL, &timo); + + if (ret == 0) + return 0; + + if (FD_ISSET(g->listen, &read_set)) { + g->s = accept(g->listen, NULL, NULL); + + if (g->s == -1) { + perror("gdb_network_handler accept"); + sleep(5); + return 1; + } + int i = 1; + setsockopt (g->s, IPPROTO_TCP, TCP_NODELAY, &i, sizeof (i)); + g->avr->state = cpu_Stopped; + printf("%s connection opened\n", __FUNCTION__); + } + + 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__); + close(g->s); + g->watchmap = 0; // clear breakpoints + g->avr->state = cpu_Running; // resume + g->s = -1; + return 1; + } + if (r == -1) { + perror("gdb_network_handler recv"); + sleep(1); + return 1; + } + 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++; + // control C -- lets send the guy a nice status packet + if (*src == 3) { + src++; + g->avr->state = cpu_StepDone; + printf("GDB hit control-c\n"); + } + if (*src == '$') { + // strip checksum + uint8_t * end = buffer + r - 1; + while (end > src && *end != '#') + *end-- = 0; + *end = 0; + src++; + DBG(printf("GDB command = '%s'\n", src);) + + send(g->s, "+", 1, 0); + + gdb_handle_command(g, (char*)src); + } + } + return 1; +} + +int avr_gdb_processor(avr_t * avr, int sleep) { if (!avr || !avr->gdb) - return; + return 0; 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); + DBG(printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);) gdb_send_quick_status(g, 0); avr->state = cpu_Stopped; } @@ -268,94 +403,8 @@ void avr_gdb_processor(avr_t * avr) 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; + // this also sleeps for a bit + return gdb_network_handler(g, sleep); } @@ -376,17 +425,20 @@ int avr_gdb_init(avr_t * avr) struct sockaddr_in address = { 0 }; address.sin_family = AF_INET; - address.sin_port = htons (1234); + address.sin_port = htons (avr->gdb_port); 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); + if (listen(g->listen, 1)) { + perror("listen"); + return -1; + } + printf("avr_gdb_init listening on port %d\n", avr->gdb_port); g->avr = avr; + g->s = -1; 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 cbd4ed1..548c59c 100644 --- a/simavr/sim/sim_gdb.h +++ b/simavr/sim/sim_gdb.h @@ -25,6 +25,6 @@ int avr_gdb_init(avr_t * avr); // call from the main AVR decoder thread -void avr_gdb_processor(avr_t * avr); +int avr_gdb_processor(avr_t * avr, int sleep); #endif diff --git a/simavr/sim/sim_interrupts.c b/simavr/sim/sim_interrupts.c index 545123e..bf620bb 100644 --- a/simavr/sim/sim_interrupts.c +++ b/simavr/sim/sim_interrupts.c @@ -76,7 +76,7 @@ void avr_clear_interrupt(avr_t * avr, int v) avr->pending[v >> 5] &= ~(1 << (v & 0x1f)); if (!vector) return; - printf("%s cleared %d\n", __FUNCTION__, vector->vector); +// printf("%s cleared %d\n", __FUNCTION__, vector->vector); if (vector->raised.reg) avr_regbit_clear(avr, vector->raised); } diff --git a/simavr/sim/sim_io.c b/simavr/sim/sim_io.c index d2bf62e..4f5dcb6 100644 --- a/simavr/sim/sim_io.c +++ b/simavr/sim/sim_io.c @@ -31,7 +31,7 @@ int avr_ioctl(avr_t *avr, uint32_t ctl, void * io_param) int res = -1; while (port && res == -1) { if (port->ioctl) - res = port->ioctl(avr, port, ctl, io_param); + res = port->ioctl(port, ctl, io_param); port = port->next; } return res; @@ -40,6 +40,7 @@ int avr_ioctl(avr_t *avr, uint32_t ctl, void * io_param) void avr_register_io(avr_t *avr, avr_io_t * io) { io->next = avr->io_port; + io->avr = avr; avr->io_port = io; } diff --git a/simavr/sim/sim_io.h b/simavr/sim/sim_io.h index 87eb5b9..330a9de 100644 --- a/simavr/sim/sim_io.h +++ b/simavr/sim/sim_io.h @@ -36,18 +36,19 @@ * Modules uses that as their first member in their own struct */ typedef struct avr_io_t { - struct avr_io_t * next; + struct avr_io_t * next; + avr_t * avr; // avr we are attached to const char * kind; // pretty name, for debug uint32_t irq_ioctl_get; // used to get irqs from this module int irq_count; // number of (optional) irqs struct avr_irq_t * irq; // optional external IRQs // called at every instruction - void (*run)(avr_t * avr, struct avr_io_t *io); + void (*run)(struct avr_io_t *io); // called at reset time - void (*reset)(avr_t * avr, struct avr_io_t *io); + void (*reset)(struct avr_io_t *io); // called externally. allow access to io modules and so on - int (*ioctl)(avr_t * avr, struct avr_io_t *io, uint32_t ctl, void *io_param); + int (*ioctl)(struct avr_io_t *io, uint32_t ctl, void *io_param); } avr_io_t; /* diff --git a/simavr/sim/sim_irq.c b/simavr/sim/sim_irq.c index b5db20e..5daa824 100644 --- a/simavr/sim/sim_irq.c +++ b/simavr/sim/sim_irq.c @@ -25,7 +25,7 @@ #include "sim_irq.h" -void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count) +void avr_init_irq(avr_irq_t * irq, uint32_t base, uint32_t count) { memset(irq, 0, sizeof(avr_irq_t) * count); @@ -33,14 +33,14 @@ void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count) irq[i].irq = base + i; } -avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count) +avr_irq_t * avr_alloc_irq(uint32_t base, uint32_t count) { avr_irq_t * irq = (avr_irq_t*)malloc(sizeof(avr_irq_t) * count); - avr_init_irq(avr, irq, base, count); + avr_init_irq(irq, base, count); return irq; } -void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param) +void avr_irq_register_notify(avr_irq_t * irq, avr_irq_notify_t notify, void * param) { if (!irq || !notify) return; @@ -59,16 +59,17 @@ void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t noti irq->hook = hook; } -void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value) +void avr_raise_irq(avr_irq_t * irq, uint32_t value) { if (!irq || irq->value == value) return ; avr_irq_hook_t *hook = irq->hook; while (hook) { - if (hook->notify) { + if (hook->notify) { + // prevents reentrance / endless calling loops if (hook->busy == 0) { hook->busy++; - hook->notify(avr, irq, value, hook->param); + hook->notify(irq, value, hook->param); hook->busy--; } } @@ -77,13 +78,13 @@ void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value) irq->value = value; } -static void _avr_irq_connect(avr_t * avr, avr_irq_t * irq, uint32_t value, void * param) +static void _avr_irq_connect(avr_irq_t * irq, uint32_t value, void * param) { avr_irq_t * dst = (avr_irq_t*)param; - avr_raise_irq(avr, dst, value); + avr_raise_irq(dst, value); } -void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst) +void avr_connect_irq(avr_irq_t * src, avr_irq_t * dst) { - avr_irq_register_notify(avr, src, _avr_irq_connect, dst); + avr_irq_register_notify(src, _avr_irq_connect, dst); } diff --git a/simavr/sim/sim_irq.h b/simavr/sim/sim_irq.h index 161c311..c678214 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 "sim_avr.h" +#include /* * Internal IRQ system @@ -42,7 +42,7 @@ // internal structure for a hook, never seen by the notify procs struct avr_irq_t; -typedef void (*avr_irq_notify_t)(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param); +typedef void (*avr_irq_notify_t)(struct avr_irq_t * irq, uint32_t value, void * param); typedef struct avr_irq_hook_t { struct avr_irq_hook_t * next; @@ -57,11 +57,11 @@ typedef struct avr_irq_t { avr_irq_hook_t * hook; } avr_irq_t; -avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count); -void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count); -void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value); +avr_irq_t * avr_alloc_irq(uint32_t base, uint32_t count); +void avr_init_irq(avr_irq_t * irq, uint32_t base, uint32_t count); +void avr_raise_irq(avr_irq_t * irq, uint32_t value); // this connects a "source" IRQ to a "destination" IRQ -void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst); -void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param); +void avr_connect_irq(avr_irq_t * src, avr_irq_t * dst); +void avr_irq_register_notify(avr_irq_t * irq, avr_irq_notify_t notify, void * param); #endif /* __SIM_IRQ_H__ */ diff --git a/tests/Makefile b/tests/Makefile index 1de514e..e75a12f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -39,25 +39,7 @@ sources := $(wildcard at*.c) all : ${sources:.c=.axf} ${sources:.c=.hex} ${sources:.c=.s} -%.hex: %.axf - @${AVR}objcopy -j .text -j .data -O ihex ${<} ${@} - -%.s: %.axf - @${AVR}objdump -j .text -j .data -j .bss -d ${<} > ${@} - -%.axf: %.c - @echo CC ${<} - @part=${<} ; part=$${part/_*}; \ - ${AVR}gcc -Wall -g -Os -std=gnu99 \ - -mmcu=$$part \ - -DF_CPU=8000000 \ - -mcall-prologues -fno-inline-small-functions \ - -ffunction-sections -fdata-sections \ - -Wl,--relax,--gc-sections \ - -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \ - -I../include \ - ${<} -o ${@} - @${AVR}size ${@}|sed '1d' +include ../Makefile.common clean: rm -f *.hex *.o *.axf *.s diff --git a/tests/attiny85_crash_gdb.c b/tests/attiny85_crash_gdb.c new file mode 100644 index 0000000..cfa5bb8 --- /dev/null +++ b/tests/attiny85_crash_gdb.c @@ -0,0 +1,29 @@ +/* + * attiny85_crash_gdb.c + * + * Created on: 1 Dec 2009 + * Author: jone + */ + +#include +#include "avr_mcu_section.h" + +AVR_MCU(F_CPU, "attiny85"); + +int value = 0; + +int main() +{ + + /* + * this is not much, but that crashed the core, and should activate + * the gdb server properly, so you can see it stopped, here + */ + value++; + + *((uint8_t*)0xdead) = 0x55; + + // should never reach here ! + value++; + sleep_mode(); +}