Commit 7b2457d2bc502e28e05edd54a305382932e077b5
receivedSun, 14. Jul 2024, 07:44:17 (by user sx)
Sun, 14 Jul 2024 05:44:17 +0000 (07:44 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Sun, 14 Jul 2024 05:43:41 +0000 (07:43 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Sun, 14 Jul 2024 05:43:41 +0000 (07:43 +0200)
22 files changed:
software/gdb-stub/.gdbinit [new file with mode: 0644]
software/gdb-stub/.gitignore [new file with mode: 0644]
software/gdb-stub/.simucinit [new file with mode: 0644]
software/gdb-stub/Makefile [new file with mode: 0644]
software/gdb-stub/README.md [new file with mode: 0644]
software/gdb-stub/ldscripts/avr5.x [new file with mode: 0644]
software/gdb-stub/ldscripts/ldscript_atmega324p.x [new file with mode: 0644]
software/gdb-stub/ldscripts/ldscript_atmega324p_sim.x [new file with mode: 0644]
software/gdb-stub/ldscripts/ldscript_atmega644p.x [new file with mode: 0644]
software/gdb-stub/ldscripts/ldscript_atmega644p_sim.x [new file with mode: 0644]
software/gdb-stub/ldscripts/ldscript_target.x [new file with mode: 0644]
software/gdb-stub/sim/avr_mcu_section.h [new file with mode: 0644]
software/gdb-stub/sim/simavr.c [new file with mode: 0644]
software/gdb-stub/src/app.cpp [new file with mode: 0644]
software/gdb-stub/src/app.h [new file with mode: 0644]
software/gdb-stub/src/blgdb.cpp [new file with mode: 0644]
software/gdb-stub/src/blgdb.h [new file with mode: 0644]
software/gdb-stub/src/bootloader.cpp [new file with mode: 0644]
software/gdb-stub/src/bootloader.h [new file with mode: 0644]
software/gdb-stub/src/gdb.cpp [new file with mode: 0644]
software/gdb-stub/src/gdb.h [new file with mode: 0644]
software/gdb-stub/src/main.cpp [new file with mode: 0644]

diff --git a/software/gdb-stub/.gdbinit b/software/gdb-stub/.gdbinit
new file mode 100644 (file)
index 0000000..62613ef
--- /dev/null
@@ -0,0 +1,12 @@
+alias reset = set *((uint8_t *)0x8008fd) = 0x40
+alias startapp = set *((uint8_t *)0x8008fd) = 0x20
+alias killapp = set *((uint8_t *)0x8008fd) = 0x10
+
+set history save on
+set history size unlimited
+set history remove-duplicates unlimited
+set pagination off
+set non-stop 1
+#file dist/gdb-stub-sm_atmega324p.elf
+#target remote localhost:2424
+
diff --git a/software/gdb-stub/.gitignore b/software/gdb-stub/.gitignore
new file mode 100644 (file)
index 0000000..867c5be
--- /dev/null
@@ -0,0 +1,9 @@
+**/.vscode/ipch
+dist/**
+build/**
+sim/dist/**
+sim/build/**
+sim/vcd/**
+nohup.out
+**/*.vcd
+.gdb_history
diff --git a/software/gdb-stub/.simucinit b/software/gdb-stub/.simucinit
new file mode 100644 (file)
index 0000000..f6f1f68
--- /dev/null
@@ -0,0 +1,9 @@
+#--board nano-644   
+--pc 0xe000
+--frequency 12000000
+#--log trace
+--log none
+#--nosync
+dist/gdb-stub_atmega644p.elf
+../test-2024-07-02/dist/test-nano-644.elf
+
diff --git a/software/gdb-stub/Makefile b/software/gdb-stub/Makefile
new file mode 100644 (file)
index 0000000..3826fba
--- /dev/null
@@ -0,0 +1,142 @@
+$(shell mkdir -p dist >/dev/null)
+$(shell mkdir -p build >/dev/null)
+$(shell mkdir -p sim/build >/dev/null)
+$(shell mkdir -p sim/dist >/dev/null)
+$(shell mkdir -p sim/vcd >/dev/null)
+
+PRJ=gdb-stub_atmega644p
+
+SECTION_APP = 0x0000
+SECTION_BOOTLOADER_START = 0xE000
+SECTION_BOOTLOADER = 0xE004
+
+## Intel Hex file production flags
+HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature
+
+CFLAGS = -g -Os -Wall -gdwarf-2
+LFLAGS = -gdwarf-2
+LFLAGS += -Wl,-Tldscripts/ldscript_atmega324p.x
+
+CFLAGS_SIM = -g -DF_CPU=12000000L -Os -Wall -gdwarf-2
+CFLAGS_SIM += -DSIMAVR
+LFLAGS_SIM = -gdwarf-2
+LFLAGS_SIM += -Wl,-Tldscripts/ldscript_atmega644p_sim.x
+
+DEVICE = atmega644p
+
+all: $(PRJ)
+#all: sim/dist/$(PRJ).elf sim/dist/$(PRJ).axf
+
+$(PRJ): build-sim build-xsim build-target
+
+build-target: dist/$(PRJ).elf dist/$(PRJ).hex dist/$(PRJ).bin
+
+build-sim: sim/dist/$(PRJ).elf sim/dist/$(PRJ).bin
+
+build-xsim: sim/dist/$(PRJ).axf sim/dist/$(PRJ).bin
+
+gui: gui/dist/gui.elf
+
+sim: build-sim
+       simavr -m $(DEVICE) sim/dist/$(PRJ).elf
+       # /work/sx/simavr/simavr/run_avr -m $(DEVICE) sim/dist/$(PRJ).axf
+
+xsim: build-xsim
+       simavr -m $(DEVICE) sim/dist/$(PRJ).axf
+       # /work/sx/simavr/simavr/run_avr -m $(DEVICE) sim/dist/$(PRJ).axf
+
+gdb: sim/dist/$(PRJ).axf
+       simavr -g -m $(DEVICE) sim/dist/$(PRJ).axf
+       # /work/sx/simavr/simavr/run_avr -g -m $(DEVICE) sim/$(PRJ).axf
+
+xgdb: sim/dist/$(PRJ).axf
+       simavr -g -m $(DEVICE) sim/dist/$(PRJ).axf
+       # /work/sx/simavr/simavr/run_avr -g -m $(DEVICE) sim/$(PRJ).axf
+
+
+rsync: dist/$(PRJ).hex
+       rsync -aP dist/ pi-hc2:/tmp/dist
+
+
+#dist/$(PRJ).elf: build/bootloader.o build/startup.o build/main.o build/gdb.o
+dist/$(PRJ).elf: build/bootloader.o build/gdb.o build/blgdb.o build/app.o build/main.o
+       avr-gcc -o $@ $(LFLAGS) -mmcu=$(DEVICE) -Wl,-Map=$@.map $^
+       @avr-objdump --disassemble $@ > $@.s
+       @echo
+       @echo "==> $@ ==========="
+       @avr-size --mcu=$(DEVICE) $@
+       @echo "=================================================="
+       @echo
+
+dist/$(PRJ).bin: dist/$(PRJ).elf
+       avr-objcopy -O binary $< $@
+
+dist/$(PRJ).hex: dist/$(PRJ).elf
+       avr-objcopy -O ihex $< $@
+
+sim/dist/$(PRJ).bin: sim/dist/$(PRJ).elf
+       avr-objcopy -O binary $< $@
+
+sim/dist/$(PRJ).hex: sim/dist/$(PRJ).elf
+       avr-objcopy -O ihex $< $@
+
+
+sim/dist/$(PRJ).elf: sim/build/bootloader.o sim/build/gdb.o sim/build/blgdb.o sim/build/app.o sim/build/main.o
+       avr-gcc -o $@ $(LFLAGS_SIM) -mmcu=$(DEVICE) -Wl,-Map=$@.map $^
+       @avr-objdump --disassemble $@ > $@.s
+       @echo
+       @echo "==> $@ ==========="
+       @avr-size --mcu=$(DEVICE) $@
+       @echo "=================================================="
+       @echo
+
+sim/dist/$(PRJ).axf: sim/build/bootloader.o sim/build/simavr.o sim/build/gdb.o sim/build/blgdb.o sim/build/app.o sim/build/main.o
+       avr-gcc -o $@ $(LFLAGS_SIM) -mmcu=$(DEVICE) -Wl,-Map=$@.map -Wl,--undefined=_mmcu,--section-start=.mmcu=0xa00000  $^
+       @avr-objdump --disassemble $@ > $@.s
+       @echo
+       @echo "==> $@ ==========="
+       @avr-size --mcu=$(DEVICE) $@
+       @echo "=================================================="
+       @echo
+
+
+build/bootloader.o: src/bootloader.cpp src/bootloader.h src/blgdb.h src/gdb.h
+       avr-gcc -o $@ $(CFLAGS) -mmcu=$(DEVICE) -c $<
+
+build/gdb.o: src/gdb.cpp src/gdb.h src/bootloader.h
+       avr-gcc -o $@ $(CFLAGS) -mmcu=$(DEVICE) -c $<
+
+build/blgdb.o: src/blgdb.cpp src/blgdb.h
+       avr-gcc -o $@ $(CFLAGS) -mmcu=$(DEVICE) -c $<
+
+build/app.o: src/app.cpp src/app.h src/blgdb.h
+       avr-gcc -o $@ $(CFLAGS) -mmcu=$(DEVICE) -c $<
+
+build/main.o: src/main.cpp src/blgdb.h src/app.h
+       avr-gcc -o $@ $(CFLAGS) -mmcu=$(DEVICE) -c $<
+
+
+sim/build/bootloader.o: src/bootloader.cpp src/bootloader.h src/blgdb.h src/gdb.h src/app.h
+       avr-g++ -o $@ $(CFLAGS_SIM) -mmcu=$(DEVICE) -c $<
+
+sim/build/gdb.o: src/gdb.cpp src/gdb.h src/bootloader.h
+       avr-gcc -o $@ $(CFLAGS_SIM) -mmcu=$(DEVICE) -c $<
+
+sim/build/blgdb.o: src/blgdb.cpp src/blgdb.h src/gdb.h src/bootloader.h
+       avr-gcc -o $@ $(CFLAGS_SIM) -mmcu=$(DEVICE) -c $<
+
+sim/build/app.o: src/app.cpp src/app.h src/blgdb.h
+       avr-g++ -o $@ $(CFLAGS_SIM) -mmcu=$(DEVICE) -c $<
+
+sim/build/main.o: src/main.cpp src/blgdb.h src/app.h
+       avr-g++ -o $@ $(CFLAGS_SIM) -mmcu=$(DEVICE) -c $<
+
+sim/build/simavr.o: sim/simavr.c
+       avr-gcc -o $@ $(CFLAGS_SIM) -std=gnu99 -Wall -gdwarf-2 -mmcu=$(DEVICE) -c $<
+
+clean:
+       -@rm -r dist
+       -@rm -r build
+       -@rm -r sim/build
+       -@rm -r sim/dist
+       -@rm -r sim/vcd
diff --git a/software/gdb-stub/README.md b/software/gdb-stub/README.md
new file mode 100644 (file)
index 0000000..50f98b6
--- /dev/null
@@ -0,0 +1,28 @@
+# gdb-stub-sm_atmega324p
+
+Small version of gdb stub for Atmega324P. Gdb must connect to target via [gdb-gateway](../gdb-gateway/README.md).
+
+## avrdude
+
+
+Start on address 0:
+```
+user@pi: $ avrdude -c usbasp -p atmega324p -U efuse:w:0xff:m -U hfuse:w:0xd1:m -U lfuse:w:0xd6:m
+
+```
+
+Start on address 0x7000, bootloader 4K:
+```
+user@pi: $ avrdude -c usbasp -p atmega324p -U efuse:w:0xff:m -U hfuse:w:0xd0:m -U lfuse:w:0xd6:m
+
+```
+
+Programm eeprom with 0x00 (stay in gdb-stub):
+```
+avrdude -c usbasp -p atmega324p -U eeprom:w:0x00:m
+```
+
+Programm eeprom with 0xff (skip gdb-stub in bootloader section and start application):
+```
+avrdude -c usbasp -p atmega324p -U eeprom:w:0x00:m
+```
\ No newline at end of file
diff --git a/software/gdb-stub/ldscripts/avr5.x b/software/gdb-stub/ldscripts/avr5.x
new file mode 100644 (file)
index 0000000..c6672dc
--- /dev/null
@@ -0,0 +1,265 @@
+/* Default linker script, for normal executables */
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copying and distribution of this script, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  */
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800060;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+MEMORY
+{
+  text   (rx)   : ORIGIN = __TEXT_REGION_ORIGIN__, LENGTH = __TEXT_REGION_LENGTH__
+  data   (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__
+  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/ldscripts/ldscript_atmega324p.x b/software/gdb-stub/ldscripts/ldscript_atmega324p.x
new file mode 100644 (file)
index 0000000..95f73ce
--- /dev/null
@@ -0,0 +1,302 @@
+/* /usr/lib/avr/lib/ldscripts/avr5.x taken and modified for this project */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0x0000;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800100;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 32K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 2K;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 1K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+__MMCU_SIGNATURE_0__ = DEFINED(__MMCU_SIGNATURE_0__) ? __SIGNATURE_0__ : 0x1e;
+__MMCU_SIGNATURE_1__ = DEFINED(__MMCU_SIGNATURE_1__) ? __SIGNATURE_1__ : 0x95;
+__MMCU_SIGNATURE_2__ = DEFINED(__MMCU_SIGNATURE_2__) ? __SIGNATURE_2__ : 0x08;
+__MMCU_SIGNATURE__ =  DEFINED(__MMCU_SIGNATURE__) ? __SIGNATURE__ : 0x08951e;
+
+
+MEMORY
+{
+  /* vectors    (rx)   : ORIGIN = 0x0000, LENGTH = 0xb8 */
+  /* text       (rx)   : ORIGIN = 0x00b8, LENGTH = 0x6f48 */
+  text       (rx)   : ORIGIN = 0x0000, LENGTH = 0x7000
+  bootloader (rx)   : ORIGIN = 0x7000, LENGTH = 4k
+  data       (rw!x) : ORIGIN = 0x800100, LENGTH = 2k
+  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+
+  .bootloader :
+  {
+    *(.bootloader_start)
+    KEEP(*(.bootloader_start))
+    *(.bootloader_table)
+    KEEP(*(.bootloader_table))
+    *(.bootloader)
+    *(.gdb)
+    *(.bootloadermem_0)
+    *(.bootloadermem_1)
+    *(.bootloadermem_2)
+    *(.bootloadermem_3)
+    *(.bootloadermem_4)
+    *(.bootloadermem_5)
+    *(.bootloadermem_6)
+    *(.bootloadermem)
+    *(.gdbmem)
+  } > bootloader
+
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    *(.appmem_0)
+    *(.appmem_1)
+    *(.appmem_2)
+    *(.appmem_3)
+    *(.appmem_4)
+    *(.appmem_5)
+    *(.appmem_6)
+    *(.appinit)
+    *(.appmem)
+    *(.progmem*)
+    *(.app)
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/ldscripts/ldscript_atmega324p_sim.x b/software/gdb-stub/ldscripts/ldscript_atmega324p_sim.x
new file mode 100644 (file)
index 0000000..5c90635
--- /dev/null
@@ -0,0 +1,270 @@
+/* /usr/lib/avr/lib/ldscripts/avr5.x taken and modified for this project */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0x0000;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800100;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 32K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 2K;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 1K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+__MMCU_SIGNATURE_0__ = DEFINED(__MMCU_SIGNATURE_0__) ? __SIGNATURE_0__ : 0x1e;
+__MMCU_SIGNATURE_1__ = DEFINED(__MMCU_SIGNATURE_1__) ? __SIGNATURE_1__ : 0x95;
+__MMCU_SIGNATURE_2__ = DEFINED(__MMCU_SIGNATURE_2__) ? __SIGNATURE_2__ : 0x08;
+__MMCU_SIGNATURE__ =  DEFINED(__MMCU_SIGNATURE__) ? __SIGNATURE__ : 0x08951e;
+
+MEMORY
+{
+  text            (rx)   : ORIGIN = 0x0000,   LENGTH = 0x7000
+  data            (rw!x) : ORIGIN = 0x800100, LENGTH = 2k
+  eeprom          (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse            (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock            (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature       (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    *(.progmem*)
+
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/ldscripts/ldscript_atmega644p.x b/software/gdb-stub/ldscripts/ldscript_atmega644p.x
new file mode 100644 (file)
index 0000000..691030b
--- /dev/null
@@ -0,0 +1,302 @@
+/* /usr/lib/avr/lib/ldscripts/avr5.x taken and modified for this project */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0x0000;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800100;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 64K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 4K;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 2K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+__MMCU_SIGNATURE_0__ = DEFINED(__MMCU_SIGNATURE_0__) ? __SIGNATURE_0__ : 0x1e;
+__MMCU_SIGNATURE_1__ = DEFINED(__MMCU_SIGNATURE_1__) ? __SIGNATURE_1__ : 0x96;
+__MMCU_SIGNATURE_2__ = DEFINED(__MMCU_SIGNATURE_2__) ? __SIGNATURE_2__ : 0x0A;
+__MMCU_SIGNATURE__ =  DEFINED(__MMCU_SIGNATURE__) ? __SIGNATURE__ : 0x0A961e;
+
+
+MEMORY
+{
+  /* vectors    (rx)   : ORIGIN = 0x0000, LENGTH = 0xb8 */
+  /* text       (rx)   : ORIGIN = 0x00b8, LENGTH = 0x6f48 */
+  text       (rx)   : ORIGIN = 0x0000, LENGTH = 0xE000
+  bootloader (rx)   : ORIGIN = 0xE000, LENGTH = 8K
+  data       (rw!x) : ORIGIN = 0x800100, LENGTH = 4K
+  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+
+  .bootloader :
+  {
+    *(.bootloader_start)
+    KEEP(*(.bootloader_start))
+    *(.bootloader_table)
+    KEEP(*(.bootloader_table))
+    *(.bootloader)
+    *(.gdb)
+    *(.bootloadermem_0)
+    *(.bootloadermem_1)
+    *(.bootloadermem_2)
+    *(.bootloadermem_3)
+    *(.bootloadermem_4)
+    *(.bootloadermem_5)
+    *(.bootloadermem_6)
+    *(.bootloadermem)
+    *(.gdbmem)
+  } > bootloader
+
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    *(.appmem_0)
+    *(.appmem_1)
+    *(.appmem_2)
+    *(.appmem_3)
+    *(.appmem_4)
+    *(.appmem_5)
+    *(.appmem_6)
+    *(.appinit)
+    *(.appmem)
+    *(.progmem*)
+    *(.app)
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/ldscripts/ldscript_atmega644p_sim.x b/software/gdb-stub/ldscripts/ldscript_atmega644p_sim.x
new file mode 100644 (file)
index 0000000..894214c
--- /dev/null
@@ -0,0 +1,270 @@
+/* /usr/lib/avr/lib/ldscripts/avr5.x taken and modified for this project */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0x0000;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800100;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 64K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 4K;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 2K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+__MMCU_SIGNATURE_0__ = DEFINED(__MMCU_SIGNATURE_0__) ? __SIGNATURE_0__ : 0x1E;
+__MMCU_SIGNATURE_1__ = DEFINED(__MMCU_SIGNATURE_1__) ? __SIGNATURE_1__ : 0x96;
+__MMCU_SIGNATURE_2__ = DEFINED(__MMCU_SIGNATURE_2__) ? __SIGNATURE_2__ : 0x0A;
+__MMCU_SIGNATURE__ =  DEFINED(__MMCU_SIGNATURE__) ? __SIGNATURE__ : 0x0A961E;
+
+MEMORY
+{
+  text            (rx)   : ORIGIN = 0x0000,   LENGTH = 0xE000
+  data            (rw!x) : ORIGIN = 0x800100, LENGTH = 4K
+  eeprom          (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse            (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock            (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature       (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    *(.progmem*)
+
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/ldscripts/ldscript_target.x b/software/gdb-stub/ldscripts/ldscript_target.x
new file mode 100644 (file)
index 0000000..473255a
--- /dev/null
@@ -0,0 +1,298 @@
+/* /usr/lib/avr/lib/ldscripts/avr5.x taken and modified for this project */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:5)
+__TEXT_REGION_ORIGIN__ = DEFINED(__TEXT_REGION_ORIGIN__) ? __TEXT_REGION_ORIGIN__ : 0x0000;
+__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800100;
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 32K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 2K;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 1K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+__MMCU_SIGNATURE_0 = DEFINED(__SIGNATURE_0__) ? __SIGNATURE_0__ : 0x00;
+__MMCU_SIGNATURE_1 = DEFINED(__SIGNATURE_1__) ? __SIGNATURE_1__ : 0x00;
+__MMCU_SIGNATURE_2 = DEFINED(__SIGNATURE_2__) ? __SIGNATURE_2__ : 0x00;
+__MMCU_SIGNATURE =  DEFINED(__SIGNATURE__) ? __SIGNATURE__ : 0x0;
+
+
+MEMORY
+{
+  /* vectors    (rx)   : ORIGIN = 0x0000, LENGTH = 0xb8 */
+  /* text       (rx)   : ORIGIN = 0x00b8, LENGTH = 0x6f48 */
+  text       (rx)   : ORIGIN = 0x0000, LENGTH = 0x7000
+  bootloader (rx)   : ORIGIN = 0x7000, LENGTH = 4k
+  data       (rw!x) : ORIGIN = 0x800100, LENGTH = 2k
+  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .gnu.version   : { *(.gnu.version)   }
+  .gnu.version_d   : { *(.gnu.version_d)       }
+  .gnu.version_r   : { *(.gnu.version_r)       }
+  .rel.init      : { *(.rel.init)              }
+  .rela.init     : { *(.rela.init)     }
+  .rel.text      :
+    {
+      *(.rel.text)
+      *(.rel.text.*)
+      *(.rel.gnu.linkonce.t*)
+    }
+  .rela.text     :
+    {
+      *(.rela.text)
+      *(.rela.text.*)
+      *(.rela.gnu.linkonce.t*)
+    }
+  .rel.fini      : { *(.rel.fini)              }
+  .rela.fini     : { *(.rela.fini)     }
+  .rel.rodata    :
+    {
+      *(.rel.rodata)
+      *(.rel.rodata.*)
+      *(.rel.gnu.linkonce.r*)
+    }
+  .rela.rodata   :
+    {
+      *(.rela.rodata)
+      *(.rela.rodata.*)
+      *(.rela.gnu.linkonce.r*)
+    }
+  .rel.data      :
+    {
+      *(.rel.data)
+      *(.rel.data.*)
+      *(.rel.gnu.linkonce.d*)
+    }
+  .rela.data     :
+    {
+      *(.rela.data)
+      *(.rela.data.*)
+      *(.rela.gnu.linkonce.d*)
+    }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  /* Internal text space or external memory.  */
+
+  .bootloader :
+  {
+    *(.bootloader_start)
+    KEEP(*(.bootloader_start))
+    *(.bootloader_table)
+    KEEP(*(.bootloader_table))
+    *(.bootloader)
+    *(.gdb)
+    *(.bootloadermem_0)
+    *(.bootloadermem_1)
+    *(.bootloadermem_2)
+    *(.bootloadermem_3)
+    *(.bootloadermem_4)
+    *(.bootloadermem)
+    *(.gdbmem)
+  } > bootloader
+
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    *(.appmem_0)
+    *(.appmem_1)
+    *(.appmem_2)
+    *(.appmem_3)
+    *(.appmem_4)
+    *(.appinit)
+    *(.appmem)
+    *(.progmem*)
+    *(.app)
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+     __trampolines_start = . ;
+    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
+    *(.trampolines)
+     *(.trampolines*)
+     __trampolines_end = . ;
+    /* avr-libc expects these data to reside in lower 64K. */
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*)
+    . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
+    /* For code that needs to reside in the lower 128k progmem.  */
+    *(.lowtext)
+     *(.lowtext*)
+     __ctors_start = . ;
+     *(.ctors)
+     __ctors_end = . ;
+     __dtors_start = . ;
+     *(.dtors)
+     __dtors_end = . ;
+    KEEP(SORT(*)(.ctors))
+    KEEP(SORT(*)(.dtors))
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .data          :
+  {
+     PROVIDE (__data_start = .) ;
+    *(.data)
+     *(.data*)
+    *(.gnu.linkonce.d*)
+    *(.rodata)  /* We need to include .rodata here if gcc is used */
+     *(.rodata*) /* with -fdata-sections.  */
+    *(.gnu.linkonce.r*)
+    . = ALIGN(2);
+     _edata = . ;
+     PROVIDE (__data_end = .) ;
+  }  > data AT> text
+  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
+  {
+     PROVIDE (__bss_start = .) ;
+    *(.bss)
+     *(.bss*)
+    *(COMMON)
+     PROVIDE (__bss_end = .) ;
+  }  > data
+   __data_load_start = LOADADDR(.data);
+   __data_load_end = __data_load_start + SIZEOF(.data);
+  /* Global data not cleared after reset.  */
+  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
+  {
+     PROVIDE (__noinit_start = .) ;
+    *(.noinit*)
+     PROVIDE (__noinit_end = .) ;
+     _end = . ;
+     PROVIDE (__heap_start = .) ;
+  }  > data
+  .eeprom  :
+  {
+    /* See .data above...  */
+    KEEP(*(.eeprom*))
+     __eeprom_end = . ;
+  }  > eeprom
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  .lock  :
+  {
+    KEEP(*(.lock*))
+  }  > lock
+  .signature  :
+  {
+    KEEP(*(.signature*))
+  }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}
diff --git a/software/gdb-stub/sim/avr_mcu_section.h b/software/gdb-stub/sim/avr_mcu_section.h
new file mode 100644 (file)
index 0000000..3deae7b
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+       avr_mcu_section.h
+
+       Copyright 2008-2013 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 __AVR_MCU_SECTION_H__
+#define __AVR_MCU_SECTION_H__
+
+/*
+ * This header is used to pass "parameters" to the programmer or the simulator,
+ * it tags the ELF file with a section that contains parameters about the physical
+ * AVR this was compiled for, including the speed, model, and signature bytes.
+ *
+ * A programmer software can read this and verify fuses values for example, and a
+ * simulator can instantiate the proper "model" of AVR, the speed and so on without
+ * command line parameters.
+ *
+ * Example of use:
+ *
+ * #include "avr_mcu_section.h"
+ * AVR_MCU(F_CPU, "atmega88");
+ *
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+       AVR_MMCU_TAG = 0,
+       AVR_MMCU_TAG_NAME,
+       AVR_MMCU_TAG_FREQUENCY,
+       AVR_MMCU_TAG_VCC,
+       AVR_MMCU_TAG_AVCC,
+       AVR_MMCU_TAG_AREF,
+       AVR_MMCU_TAG_LFUSE,
+       AVR_MMCU_TAG_HFUSE,
+       AVR_MMCU_TAG_EFUSE,
+       AVR_MMCU_TAG_SIGNATURE,
+       AVR_MMCU_TAG_SIMAVR_COMMAND,
+       AVR_MMCU_TAG_SIMAVR_CONSOLE,
+       AVR_MMCU_TAG_VCD_FILENAME,
+       AVR_MMCU_TAG_VCD_PERIOD,
+       AVR_MMCU_TAG_VCD_TRACE,
+       AVR_MMCU_TAG_VCD_PORTPIN,
+       AVR_MMCU_TAG_VCD_IRQ,
+       AVR_MMCU_TAG_PORT_EXTERNAL_PULL,
+};
+
+enum {
+       SIMAVR_CMD_NONE = 0,
+       SIMAVR_CMD_VCD_START_TRACE,
+       SIMAVR_CMD_VCD_STOP_TRACE,
+       SIMAVR_CMD_UART_LOOPBACK,
+};
+
+#if __AVR__
+/*
+ * WARNING. Due to newer GCC being stupid, they introduced a bug that
+ * prevents us introducing variable length strings in the declaration
+ * of structs. Worked for a million years, and no longer.
+ * So the new method declares the string as fixed size, and the parser
+ * is forced to skip the zeroes in padding. Dumbo.
+ */
+#define _MMCU_ __attribute__((section(".mmcu"))) __attribute__((used))
+struct avr_mmcu_long_t {
+       uint8_t tag;
+       uint8_t len;
+       uint32_t val;
+} __attribute__((__packed__));
+
+struct avr_mmcu_string_t {
+       uint8_t tag;
+       uint8_t len;
+       char string[64];
+} __attribute__((__packed__));
+
+struct avr_mmcu_addr_t {
+       uint8_t tag;
+       uint8_t len;
+       void * what;
+} __attribute__((__packed__));
+
+struct avr_mmcu_vcd_trace_t {
+       uint8_t tag;
+       uint8_t len;
+       uint8_t mask;
+       void * what;
+       char name[32];
+} __attribute__((__packed__));
+
+#define AVR_MCU_STRING(_tag, _str) \
+       const struct avr_mmcu_string_t _##_tag _MMCU_ = {\
+               .tag = _tag,\
+               .len = sizeof(struct avr_mmcu_string_t) - 2,\
+               .string = _str,\
+       }
+/*
+ * This trick allows concatenation of tokens. We need a macro redirection
+ * for it to work.
+ * The goal is to make unique variable names (they don't matter anyway)
+ */
+#define DO_CONCAT2(_a, _b) _a##_b
+#define DO_CONCAT(_a, _b) DO_CONCAT2(_a,_b)
+
+#define AVR_MCU_LONG(_tag, _val) \
+       const struct avr_mmcu_long_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\
+               .tag = _tag,\
+               .len = sizeof(struct avr_mmcu_long_t) - 2,\
+               .val = _val,\
+       }
+
+#define AVR_MCU_BYTE(_tag, _val) \
+       const uint8_t _##_tag _MMCU_ = { _tag, 1, _val }
+
+/*!
+ * This Macro allows you to specify traces for the VCD file output
+ * engine. This specifies a default header, and let you fill in the
+ * relevant bits.
+ * Example:
+ *     const struct avr_mmcu_vcd_trace_t _mytrace[]  _MMCU_ = {
+ *             { AVR_MCU_VCD_SYMBOL("UDR0"), .what = (void*)&UDR0, },
+ *             { AVR_MCU_VCD_SYMBOL("UDRE0"), .mask = (1 << UDRE0), .what = (void*)&UCSR0A, },
+ *     };
+ * This structure will automatically tell simavr to add a VCD trace
+ * for the UART register, and the UDRE0 bit, so you can trace exactly
+ * the timing of the changed using gtkwave.
+ */
+#define AVR_MCU_VCD_SYMBOL(_name) \
+       .tag = AVR_MMCU_TAG_VCD_TRACE, \
+       .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\
+       .name = _name
+
+/*!
+ * Specifies the name and wanted period (in usec) for a VCD file
+ * this is not mandatory for the VCD output to work, if this tag
+ * is not used, a VCD file will still be created with default values
+ */
+#define AVR_MCU_VCD_FILE(_name, _period) \
+       AVR_MCU_STRING(AVR_MMCU_TAG_VCD_FILENAME, _name);\
+       AVR_MCU_LONG(AVR_MMCU_TAG_VCD_PERIOD, _period)
+
+/*!
+ * It is possible to send "commands" to simavr from the
+ * firmware itself. For this to work you need to specify
+ * an IO register that is to be used for a write-only
+ * bridge. A favourite is one of the usual "GPIO register"
+ * that most (all ?) AVR have.
+ * See definition of SIMAVR_CMD_* to see what commands can
+ * be used from your firmware.
+ */
+#define AVR_MCU_SIMAVR_COMMAND(_register) \
+       const struct avr_mmcu_addr_t _simavr_command_register _MMCU_ = {\
+               .tag = AVR_MMCU_TAG_SIMAVR_COMMAND,\
+               .len = sizeof(void *),\
+               .what = (void*)_register, \
+       }
+/*!
+ * Similar to AVR_MCU_SIMAVR_COMMAND, The CONSOLE allows the AVR code
+ * to declare a register (typically a GPIO register, but any unused
+ * register can work...) that will allow printing on the host's console
+ * without using a UART to do debug.
+ */
+#define AVR_MCU_SIMAVR_CONSOLE(_register) \
+       const struct avr_mmcu_addr_t _simavr_console_register _MMCU_ = {\
+               .tag = AVR_MMCU_TAG_SIMAVR_CONSOLE,\
+               .len = sizeof(void *),\
+               .what = (void*)_register, \
+       }
+/*!
+ * Allows the firmware to hint simavr as to wether there are external
+ * pullups/down on PORT pins. It helps if the firmware uses "open drain"
+ * pins by toggling the DDR pins to switch between an output state and
+ * a "default" state.
+ * The value passed here will be output on the PORT IRQ when the DDR
+ * pin is set to input again
+ */
+#define AVR_MCU_EXTERNAL_PORT_PULL(_port, _mask, _val) \
+       AVR_MCU_LONG(AVR_MMCU_TAG_PORT_EXTERNAL_PULL, \
+               (((unsigned long)((_port)&0xff) << 16) | \
+               ((unsigned long)((_mask)&0xff) << 8) | \
+               ((_val)&0xff)));
+/*!
+ * Add this port/pin to the VCD file. The syntax uses the name of the
+ * port as a character, and not a pointer to a register.
+ * AVR_MCU_VCD_PORT_PIN('B', 5);
+ */
+#define AVR_MCU_VCD_PORT_PIN(_port, _pin, _name) \
+       const struct avr_mmcu_vcd_trace_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\
+               .tag = AVR_MMCU_TAG_VCD_PORTPIN, \
+               .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\
+               .mask = _port, \
+               .what = (void*)_pin, \
+               .name = _name, \
+       }
+
+/*!
+ * These allows you to add a trace showing how long an IRQ vector is pending,
+ * and also how long it is running. You can specify the IRQ as a vector name
+ * straight from the firmware file, and it will be named properly in the trace
+ */
+
+#define AVR_MCU_VCD_IRQ_TRACE(_vect_number, __what, _trace_name) \
+       const struct avr_mmcu_vcd_trace_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\
+               .tag = AVR_MMCU_TAG_VCD_IRQ, \
+               .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\
+               .mask = _vect_number, \
+               .what = (void*)__what, \
+               .name = _trace_name, \
+       };
+#define AVR_MCU_VCD_IRQ(_irq_name) \
+       AVR_MCU_VCD_IRQ_TRACE(_irq_name##_vect_num, 1, #_irq_name)
+#define AVR_MCU_VCD_IRQ_PENDING(_irq_name) \
+       AVR_MCU_VCD_IRQ_TRACE(_irq_name##_vect_num, 0, #_irq_name "_pend")
+#define AVR_MCU_VCD_ALL_IRQ() \
+       AVR_MCU_VCD_IRQ_TRACE(0xff, 1, "IRQ")
+#define AVR_MCU_VCD_ALL_IRQ_PENDING() \
+       AVR_MCU_VCD_IRQ_TRACE(0xff, 0, "IRQ_PENDING")
+
+/*!
+ * This tag allows you to specify the voltages used by your board
+ * It is optional in most cases, but you will need it if you use
+ * ADC module's IRQs. Not specifying it in this case might lead
+ * to a divide-by-zero crash.
+ * The units are Volts*1000 (millivolts)
+ */
+#define AVR_MCU_VOLTAGES(_vcc, _avcc, _aref) \
+       AVR_MCU_LONG(AVR_MMCU_TAG_VCC, (_vcc));\
+       AVR_MCU_LONG(AVR_MMCU_TAG_AVCC, (_avcc));\
+       AVR_MCU_LONG(AVR_MMCU_TAG_AREF, (_aref));
+
+/*!
+ * This the has to be used if you want to add other tags to the .mmcu section
+ * the _mmcu symbol is used as an anchor to make sure it stays linked in.
+ */
+#define AVR_MCU(_speed, _name) \
+       AVR_MCU_STRING(AVR_MMCU_TAG_NAME, _name);\
+       AVR_MCU_LONG(AVR_MMCU_TAG_FREQUENCY, _speed);\
+       const uint8_t _mmcu[2] _MMCU_ = { AVR_MMCU_TAG, 0 }
+
+/*
+ * The following MAP macros where copied from
+ * https://github.com/swansontec/map-macro/blob/master/map.h
+ *
+ * The license header for that file is reproduced below:
+ *
+ * Copyright (C) 2012 William Swanson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors or
+ * their institutions shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without
+ * prior written authorization from the authors.
+ */
+
+#define _EVAL0(...) __VA_ARGS__
+#define _EVAL1(...) _EVAL0 (_EVAL0 (_EVAL0 (__VA_ARGS__)))
+#define _EVAL2(...) _EVAL1 (_EVAL1 (_EVAL1 (__VA_ARGS__)))
+#define _EVAL3(...) _EVAL2 (_EVAL2 (_EVAL2 (__VA_ARGS__)))
+#define _EVAL4(...) _EVAL3 (_EVAL3 (_EVAL3 (__VA_ARGS__)))
+#define _EVAL(...)  _EVAL4 (_EVAL4 (_EVAL4 (__VA_ARGS__)))
+
+#define _MAP_END(...)
+#define _MAP_OUT
+
+#define _MAP_GET_END() 0, _MAP_END
+#define _MAP_NEXT0(test, next, ...) next _MAP_OUT
+#define _MAP_NEXT1(test, next) _MAP_NEXT0 (test, next, 0)
+#define _MAP_NEXT(test, next)  _MAP_NEXT1 (_MAP_GET_END test, next)
+
+#define _MAP0(f, x, peek, ...) f(x) _MAP_NEXT (peek, _MAP1) (f, peek, __VA_ARGS__)
+#define _MAP1(f, x, peek, ...) f(x) _MAP_NEXT (peek, _MAP0) (f, peek, __VA_ARGS__)
+#define _MAP(f, ...) _EVAL (-MAP1 (f, __VA_ARGS__, (), 0))
+
+/* End of original MAP macros. */
+
+// Define MAP macros with one additional argument
+#define _MAP0_1(f, a, x, peek, ...) f(a, x) _MAP_NEXT (peek, _MAP1_1) (f, a, peek, __VA_ARGS__)
+#define _MAP1_1(f, a, x, peek, ...) f(a, x) _MAP_NEXT (peek, _MAP0_1) (f, a, peek, __VA_ARGS__)
+#define _MAP_1(f, a, ...) _EVAL (_MAP1_1 (f, a, __VA_ARGS__, (), 0))
+
+#define _SEND_SIMAVR_CMD_BYTE(reg, b)            reg = b;
+
+// A helper macro for sending multi-byte commands
+#define SEND_SIMAVR_CMD(reg, ...)              \
+       do { \
+               _MAP_1(_SEND_SIMAVR_CMD_BYTE, reg, __VA_ARGS__) \
+       } while(0)
+
+#endif /* __AVR__ */
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/software/gdb-stub/sim/simavr.c b/software/gdb-stub/sim/simavr.c
new file mode 100644 (file)
index 0000000..31b0d34
--- /dev/null
@@ -0,0 +1,24 @@
+#include "avr_mcu_section.h"
+#include <avr/io.h>
+
+
+AVR_MCU(20000000L, "atmega324p");
+AVR_MCU_VOLTAGES(5000, 5000, 2500); // VCC, AVCC, AREF
+AVR_MCU_VCD_FILE("sim/vcd/atmega324p_u1_bootloader.simavr.vcd", 100000);
+
+/*
+ * This small section tells simavr to generate a VCD trace dump with changes to these
+ * registers.
+ * Opening it with gtkwave will show you the data being pumped out into the data register
+ * UDR0, and the UDRE0 bit being set, then cleared
+ */
+const struct avr_mmcu_vcd_trace_t _mytrace[]  _MMCU_ = {
+       { AVR_MCU_VCD_SYMBOL("TCNT1L"), .what = (void*)&TCNT1L, },
+       { AVR_MCU_VCD_SYMBOL("PORTB0"), .mask = (1 << PORTB0), .what = (void*)&PORTB, },
+       { AVR_MCU_VCD_SYMBOL("UDR0"), .what = (void*)&UDR0, },
+       { AVR_MCU_VCD_SYMBOL("UDRE0"), .mask = (1 << UDRE0), .what = (void*)&UCSR0A, },
+       { AVR_MCU_VCD_SYMBOL("UDR1"), .what = (void*)&UDR1, },
+       { AVR_MCU_VCD_SYMBOL("UDRE1"), .mask = (1 << UDRE1), .what = (void*)&UCSR1A, },
+};
+
+
diff --git a/software/gdb-stub/src/app.cpp b/software/gdb-stub/src/app.cpp
new file mode 100644 (file)
index 0000000..3aae82b
--- /dev/null
@@ -0,0 +1,141 @@
+
+#include "app.h"
+#include "blgdb.h"
+#include "gdb.h"
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include "string.h"
+
+
+extern const char APP_MSG_TEXT[]    APPMEM_0 = "TEST V1.0";
+extern const char APP_MSG_SEP1[]    APPMEM_1 = " (";
+extern const char APP_MSG_DATE[]    APPMEM_2 = __DATE__;
+extern const char APP_MSG_SEP2[]    APPMEM_3 = ",";
+extern const char APP_MSG_TIME[]    APPMEM_4 = __TIME__;
+extern const char APP_MSG_END[]     APPMEM_5 = ")\r\n\0";
+
+namespace app {
+
+       struct App app;
+
+       void init () {
+               memset((void *)&app, 0, sizeof(app));
+               UCSR0B |= (1 << RXCIE0);
+               UCSR1B |= (1 << RXCIE1);
+
+               OCR0A  = (F_CPU + 32) / 64 / 2000 - 1; // timer interrupt 2kHz
+               TCCR0A = (1 << WGM01);                 // CTC Mode
+               TCCR0B = (1 << CS01) | (1 << CS00);    // clock divider -> fcpu / 64
+               TIMSK0 = (1 << OCIE0A);
+               TIFR0  = (1 << OCF0A);
+
+               blgdb::putUint8Hex(*( (uint8_t *)0x08fc) ) ;
+               blgdb::puts(" START\n\r");
+
+               sei();
+       }
+
+       void __attribute__((optimize("O0"))) main () {
+               if (app.event) {
+                       static uint16_t cnt = 0;
+                       if (app.event & 0x01) {
+                               blgdb::puts("\rHELLO ");
+                               blgdb::putUint8Hex(cnt >> 8);
+                               blgdb::putUint8Hex(cnt & 0xff);
+                               cnt++;
+                       }
+                       if (app.event & 0x02) {
+                               blgdb::puts("\r\nBREAK IF CONNECTED");
+                               blgdb::stop();
+                               blgdb::puts("\r\n");
+                       }
+                       if (app.event & 0x04) {
+                               blgdb::puts("\r\nSET CONNECTED AND BREAK");
+                               blgdb::setGdbConnectedAndStop();
+                               blgdb::puts("\r\n");
+                       }
+
+                       app.event = 0;
+               }
+       }
+
+
+       void task1ms () {
+       }
+
+       void task2ms () {
+               static uint8_t timer = 0;
+               if (++timer >= 250 ) {
+                       app.event |= 1;
+                       timer = 0;
+               }
+       }
+
+       void task4ms () {
+       }
+
+       void task8ms () {
+       }
+
+       void task16ms () {
+       }
+
+       void task32ms () {
+       }
+
+       void task64ms () {
+       }
+
+       void task128ms () {
+               static uint8_t timer = 0;
+               if (++timer == 4) {
+                       PORTB ^= (1 << PB0);
+                       timer = 0;
+                       blgdb::serve500msTimer();
+               }
+       }
+
+}
+
+ISR (USART0_RX_vect) {
+    uint8_t c = UDR0;
+       if (c != ' ') {
+               app::app.event |= 2;
+       } else {
+               app::app.event |= 4;
+       }
+       c++;
+}
+
+// ISR (USART1_RX_vect) {
+//     uint8_t c = UDR1;
+//     app::app.event |= 4;
+//     blgdb::handleUartIsrByte(c);
+// }
+
+// Timer 0 Output/Compare Interrupt
+// called every 100us
+ISR (TIMER0_COMPA_vect) {
+    static uint8_t cnt500us = 0;
+    static uint8_t busy = 0;
+
+       cnt500us++;
+       if (busy) {
+               if (app::app.taskErr < 0xff) {
+                       app::app.taskErr++;
+               }
+       } else {
+               busy = 1;
+               sei();
+               if (cnt500us & 0x01) app::task1ms();
+               else if (cnt500us & 0x02) app::task2ms();
+               else if (cnt500us & 0x04) app::task4ms();
+               else if (cnt500us & 0x08) app::task8ms();
+               else if (cnt500us & 0x10) app::task16ms();
+               else if (cnt500us & 0x20) app::task32ms();
+               else if (cnt500us & 0x40) app::task64ms();
+               else if (cnt500us & 0x80) app::task128ms();
+               busy = 0;
+       }
+}
\ No newline at end of file
diff --git a/software/gdb-stub/src/app.h b/software/gdb-stub/src/app.h
new file mode 100644 (file)
index 0000000..1eb890c
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef APP_H
+#define APP_H
+
+#include <stdint.h>
+
+#ifdef SIMAVR
+       #define APPINIT
+       #define APPMEM   PROGMEM
+       #define APPMEM_0 PROGMEM
+       #define APPMEM_1 PROGMEM
+       #define APPMEM_2 PROGMEM
+       #define APPMEM_3 PROGMEM
+       #define APPMEM_4 PROGMEM
+       #define APPMEM_5 PROGMEM
+#else
+       #define APPINIT  __attribute__((section(".appinit")));
+       #define APPMEM   __attribute__((section(".appmem")))
+       #define APPMEM_0 __attribute__((section(".appmem_0")))
+       #define APPMEM_1 __attribute__((section(".appmem_1")))
+       #define APPMEM_2 __attribute__((section(".appmem_2")))
+       #define APPMEM_3 __attribute__((section(".appmem_3")))
+       #define APPMEM_4 __attribute__((section(".appmem_4")))
+       #define APPMEM_5 __attribute__((section(".appmem_5")))
+#endif
+
+extern const char APP_MSG[];
+extern const char APP_MSG_DATE[];
+extern const char APP_MSG_TIME[];
+
+struct App {
+       uint8_t taskErr;
+       uint8_t volatile event;
+};
+
+
+namespace app {
+
+       extern struct App app;
+
+       void init ();
+       void main ();
+
+       void task1ms ();
+       void task2ms ();
+       void task4ms ();
+       void task8ms ();
+       void task16ms ();
+       void task32ms ();
+       void task64ms ();
+       void task128ms ();
+}
+
+
+#endif // APP_H
diff --git a/software/gdb-stub/src/blgdb.cpp b/software/gdb-stub/src/blgdb.cpp
new file mode 100644 (file)
index 0000000..d99f424
--- /dev/null
@@ -0,0 +1,138 @@
+#include "blgdb.h"
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+namespace blgdb {
+
+       void __attribute__((naked)) init () {
+               #ifdef SIMAVR
+                       gdb::init();
+               #else
+                       blgdb_init();
+               #endif
+               asm volatile (
+                       "ret \n"
+               );
+
+       }
+
+       void __attribute__((naked)) main () {
+               #ifdef SIMAVR
+                       bootloader:: jmpTableGdbMain();
+                       asm volatile (
+                               "ret \n"
+                       );
+               #else
+                       blgdb_main();
+               #endif
+       }
+
+       void __attribute__((naked)) setGdbConnectedAndStop () {
+               asm volatile (
+                       "lds r24, 0x08fc \n"
+                       "ori r24, 0x01   \n"
+                       "sts 0x08fc, r24 \n"  // gdb.status.isConnected = 1
+               );
+               #ifdef SIMAVR
+                       // simjmptable_stopApplication();
+                       bootloader::jmpTableGdbStopApplication();
+                       asm volatile (
+                               "ret \n"
+                       );
+               #else
+                       blgdb_stop();
+               #endif
+       }
+
+
+       void __attribute__((naked)) stop () {
+               #ifdef SIMAVR
+                       // simjmptable_stopApplication();
+                       bootloader::jmpTableGdbStopApplication();
+                       asm volatile (
+                               "ret \n"
+                       );
+               #else
+                       blgdb_stop();
+               #endif
+       }
+
+       void __attribute__((naked)) handleUartIsrByte (uint8_t b) {
+               #ifdef SIMAVR
+                       gdb::handleUartIsrByte(b);
+               #else
+                       blgdb_handleUartIsrByte(b);
+               #endif
+               // asm volatile (
+               //      "ret \n"
+               // );
+
+       }
+
+       void serve500msTimer () {
+               #ifdef SIMAVR
+                       gdb::serve500msTimer();
+               #else
+                       blgdb_serve500msTimer();
+               #endif
+       }
+
+       void printWelcomeMessage () {
+               #ifdef SIMAVR
+                       bootloader::printWelcomeMessage();
+               #else
+                       blgdb_printWelcomeMessage();
+               #endif
+       }
+
+       void printChar (char c) {
+               #ifdef SIMAVR
+                       bootloader::printChar(stdoutUart, c);
+               #else
+                       blgdb_putchar(c);
+               #endif
+       }
+
+       void puts (const char *s) {
+               #ifdef SIMAVR
+                       bootloader::puts(stdoutUart, s);
+               #else
+                       blgdb_puts(s);
+               #endif
+       }
+
+       void putUint8Hex (uint8_t value) {
+               #ifdef SIMAVR
+                       bootloader::putUint8Hex(stdoutUart, value);
+               #else
+                       blgdb_putUint8Hex(value);
+               #endif
+       }
+
+       void memputc (PGM_P p) {
+               #ifdef SIMAVR
+                       bootloader::memputc(stdoutUart, p);
+               #else
+                       blgdb_memputc(p);
+               #endif
+       }
+
+       void memputs (PGM_P p) {
+               #ifdef SIMAVR
+                       bootloader::memputs(stdoutUart, p);
+               #else
+                       blgdb_memputs(p);
+               #endif
+       }
+
+}
+#ifdef SIMAVR
+       ISR (USART1_RX_vect) {
+               gdb::handleUartIsrByte(UDR1);
+       }
+#else
+       ISR (USART1_RX_vect) ISR_NAKED;
+       ISR (USART1_RX_vect) {
+               blgdb_handleUartIsrByte();
+       }
+#endif
diff --git a/software/gdb-stub/src/blgdb.h b/software/gdb-stub/src/blgdb.h
new file mode 100644 (file)
index 0000000..92c53b4
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef BLGDB_H
+#define BLGDB_H
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+#ifndef F_CPU
+       #define F_CPU 20000000L
+#endif
+
+#ifdef SIMAVR
+       #include "bootloader.h"
+       #include "gdb.h"
+#else
+       // #define stdoutUart 0
+       // #define stderrUart 0
+       // #define stdinUart  0
+       // #define gdboutUart 1
+       // #define gdbinUart  1
+#endif
+
+
+
+#define blgdb_init()                 asm volatile ( "jmp 0x7002" )
+#define blgdb_main()                 asm volatile ( "call 0x7004 \n  ret \n" )
+#define blgdb_stop()                 asm volatile ( "call 0x7006 \n  ret \n" )
+#define blgdb_handleUartIsrByte(b)   asm volatile ( "jmp 0x7008" )
+#define blgdb_printWelcomeMessage()  asm volatile ( "jmp 0x700a" )
+#define blgdb_putchar(c)             ( (*(( void (*)(uint8_t) ) (0x700c / 2) )) (c) )
+#define blgdb_puts(s)                ( (*(( void (*)(const char *) ) (0x700e / 2) )) (s) );
+#define blgdb_putUint8Hex(value)     ( (*(( void (*)(uint8_t) ) (0x7010 / 2) )) (value) )
+#define blgdb_memputc(p)             ( (*(( void (*)(PGM_P) ) (0x7012 / 2) )) (p) )
+#define blgdb_memputs(p)             ( (*(( void (*)(PGM_P) ) (0x7014 / 2) )) (p) )
+#define blgdb_serve500msTimer()      asm volatile ( "jmp 0x7016" )
+
+namespace blgdb {
+
+       void init ();
+       void main ();
+       void stop ();
+       void setGdbConnectedAndStop ();
+       void handleUartIsrByte (uint8_t b);
+       void serve500msTimer ();
+       void printWelcomeMessage ();
+       void printChar (char c);
+       void puts (const char *s);
+    void putUint8Hex (uint8_t value);
+       void memputc (PGM_P p);
+       void memputs (PGM_P p);
+}
+
+#endif // BLGDB_H
\ No newline at end of file
diff --git a/software/gdb-stub/src/bootloader.cpp b/software/gdb-stub/src/bootloader.cpp
new file mode 100644 (file)
index 0000000..6f965e8
--- /dev/null
@@ -0,0 +1,531 @@
+#include <string.h>
+#include <stdarg.h>
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/wdt.h>
+
+#include "bootloader.h"
+#include "gdb.h"
+
+#ifdef SIMAVR
+       #include "app.h"
+#endif
+
+#define GLOBAL_UART0_BITRATE 115200
+#define GLOBAL_UART1_BITRATE 115200
+#ifndef F_CPU
+       #define F_CPU 20000000L
+#endif
+// #define GLOBAL_GDB_UART0
+#define GLOBAL_GDB_UART1
+
+// #define ATT_SECTION_BOOTLOADER
+// __attribute__((optimize("O0")))
+
+#define ATT_SECTION_APP_START __attribute__((section(".app_start"))) __attribute__((strong))
+
+// extern const char BOOTLOADER_MSG[]      BOOTLOADERMEM_0 = "gdb-stub V0.1";
+// extern const char BOOTLOADER_MSG_SEP1[] BOOTLOADERMEM_1 = " (";
+// extern const char BOOTLOADER_MSG_DATE[] BOOTLOADERMEM_2 = __DATE__;
+// extern const char BOOTLOADER_MSG_SEP2[] BOOTLOADERMEM_3 = ",";
+// extern const char BOOTLOADER_MSG_TIME[] BOOTLOADERMEM_4 = __TIME__;
+// extern const char BOOTLOADER_MSG_END[]  BOOTLOADERMEM_5 = ")\0";
+
+extern const char BOOTLOADER_MSG_TEXT[] BOOTLOADERMEM_0 = "gdb-stub V0.1";
+// const char BOOTLOADER_MSG_SEP1[] PROGMEM = " (";
+extern const char BOOTLOADER_MSG_DATE[] BOOTLOADERMEM_1 = __DATE__;
+// const char BOOTLOADER_MSG_SEP2[] PROGMEM = ",";
+extern const char BOOTLOADER_MSG_TIME[] BOOTLOADERMEM_2 = __TIME__;
+// const char BOOTLOADER_MSG_END[]  PROGMEM = ")";
+
+uint8_t eeprom[1] __attribute__((section(".eeprom"))) = { 0x80 };
+uint8_t fusex[3] __attribute__((section(".fuse"))) = { 0xe7, 0xd8, 0xff };
+uint8_t lock[1] __attribute__((section(".lock"))) = { 0xff };
+
+extern int main ();
+
+
+
+
+
+namespace bootloader {
+
+       void __attribute__ ((naked)) bootloaderStart () {
+               asm volatile (
+                       "__bootloader_start:                \n"
+                       "rjmp __bootloader_start_from_reset \n"  // 0x7000
+                       "rjmp __bootloader_start_from_app   \n"  // 0x7002
+                       "rjmp __gdb_main                    \n"  // 0x7004
+                       "rjmp __gdb_stopApplication         \n"  // 0x7006
+                       "rjmp __vector_jmpTableIsrUsart1    \n"  // 0x7008
+                       "rjmp __print_welcome_message       \n"  // 0x700a
+                       "rjmp __bootloader_printChar        \n"  // 0x700c
+                       "rjmp __bootloader_puts             \n"  // 0x701e
+                       "rjmp __bootloader_put_uint_8_hex   \n"  // 0x7010
+                       "rjmp __bootloader_memputc          \n"  // 0x7012
+                       "rjmp __bootloader_memputs          \n"  // 0x7014
+            "rjmp __gdb_serve500msTimer         \n"  // 0x7016
+               );
+       }
+
+       void __attribute__((naked)) bootloaderStartFromApp () {
+               asm volatile (
+                       "__bootloader_start_from_app: \n"
+               );
+               bootloaderInit(sizeof(struct gdb::Gdb));
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               pgdb->status.isAppStarted = 1;
+               // pgdb->status.isStopped = 0;
+               asm volatile (
+                       "ret"
+               );
+       }
+
+       void __attribute__((naked)) bootloaderStartFromReset () {
+               asm volatile (
+                       "__bootloader_start_from_reset: \n"
+                       "eor   r1, r1     \n"
+                       "out  0x3f, r1    \n"  // SREG = 0
+                       "ldi   r28, 0xFF  \n"  // reset SP to 0x08ff (RAMEND)
+                       "ldi   r29, 0x08  \n"
+                       "out  0x3e, r29   \n"  // SPH = 0x08
+                       "out  0x3d, r28   \n"  // SPL = 0xFF
+                       "nop              \n"
+               );
+
+               bootloaderStartFromReset2();
+               bootloaderLoop();
+       }
+
+       void __attribute__((naked)) bootloaderStartFromReset2 () {
+               bootloaderInit(sizeof(struct gdb::Gdb));
+       }
+
+       extern "C" void __attribute__ ((signal)) __vector_jmpTableIsrUsart1 () {
+               gdb::handleUartIsrByte(UDR1);
+       }
+
+       // void jmpTablePutc (char c) {
+       //      asm volatile (
+       //              "__bootloader_putc: \n"
+       //      );
+       //      putc(stdoutUart, c);
+       // }
+
+       void jmpTablePuts (const char *s) {
+               asm volatile (
+                       "__bootloader_puts: \n"
+               );
+               puts(stdoutUart, s);
+       }
+
+       void jmpTablePutUint8Hex (uint8_t value) {
+               asm volatile (
+                       "__bootloader_put_uint_8_hex: \n"
+               );
+               putUint8Hex(stdoutUart, value);
+       }
+
+       void jmpTableMemputc (PGM_P p) {
+               asm volatile (
+                       "__bootloader_memputc: \n"
+               );
+               memputc(stdoutUart, p);
+       }
+
+       void jmpTableMemputs (PGM_P p) {
+               asm volatile (
+                       "__bootloader_memputs: \n"
+               );
+               memputs(stdoutUart, p);
+       }
+
+       void jmpTableGdbServe500msTimer () {
+               asm volatile (
+                       "__gdb_serve500msTimer: \n"
+               );
+               gdb::serve500msTimer();
+       }
+
+
+
+
+       void bootloaderLoop () {
+               // asm volatile (
+               //      "__bootloader_loop: \n"
+               // );
+               // init();
+
+               #ifdef SIMAVR
+                       eepromWriteByte(0, 0x80);
+               #else
+                       // eepromWriteByte(0, 0xf0);
+               #endif
+
+               if (prepareAppStart()) {
+                       putln(stdoutUart);
+                       #ifdef SIMAVR
+                               main();
+                       #else
+                               asm volatile (
+                                       "jmp 0x0000" // start application
+                               );
+                       #endif
+
+               }
+               asm volatile (
+                       "rjmp __bootloader_start \n"
+               );
+       }
+
+       // void __attribute__((naked)) bootloaderInit () {
+       //      asm volatile (
+       //              "eor   r1, r1     \n"
+       //              "out  0x3f, r1    \n"  // SREG = 0
+       //              "pop   r23        \n"  // return address to r23:r22
+       //              "pop   r22        \n"
+       //              "ldi   r28, 0xFF  \n"  // reset SP to 0x08ff (RAMEND)
+       //              "ldi   r29, 0x08  \n"
+       //              "out  0x3e, r29   \n"  // SPH = 0x08
+       //              "out  0x3d, r28   \n"  // SPL = 0xFF
+       //       );
+       //       bootloaderInit2 (sizeof(struct gdb::Gdb));
+       // }
+
+       void __attribute__((naked))  bootloaderInit (size_t gdbSize) {
+               asm volatile (
+                       "      pop   r23         \n" // get two return addresses from stack
+                       "      pop   r22         \n"
+                       "      pop   r21         \n"
+                       "      pop   r20         \n"
+
+                       "      movw  r26, r28    \n"
+            "      ldi   r30,0xfe    \n"  // gdb.magic
+                       "      st    X, r30      \n"
+                       "      ldi   r30,0x01    \n"  // gdb.version
+                       "      st    -X, r30     \n"
+
+                       "      sub   r28, r24    \n"  // allocate struct Gdb on stack
+                       "      sbc   r29, r25    \n"
+                       "      out   0x3e, r29   \n"  // SPH = ...
+                       "      out   0x3d, r28   \n"  // SPL = ...
+
+                       "loop: st    Y+, r1      \n"  // initialize struct Gdb
+                       "      cp    r28, r26    \n"
+                       "      cpc   r29, r27    \n"
+                       "      brne  loop        \n"
+
+                       "      push  r20         \n"  // restore the two return addresses on stack
+                       "      push  r21         \n"
+                       "      push  r22         \n"
+                       "      push  r23         \n"
+               );
+
+               // disable watchdog (maybe enabled from restart command)
+               // WDE is overridden by WDRF in MCUSR -> as long as WDRF == 1 the watchdog is enabled
+               MCUSR &= ~(1 << WDRF);
+               wdt_disable();
+
+               init();
+               asm volatile (
+                       "ret"
+               );
+
+       }
+
+       void __attribute__((naked)) jmpTableGdbMain () {
+               asm volatile (
+                       "__gdb_main: \n"
+               );
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               if (pgdb->ctrl.interrupt) {
+                       pgdb->ctrl.interrupt = 0;
+                       asm volatile (
+                               "jmp __gdb_stopApplication"
+                       );
+               }
+               gdb::main();
+               asm volatile (
+                       "ret"
+               );
+       }
+
+       void __attribute__((naked)) jmpTableGdbStopApplication () {
+       // void jmpTableGdbStopApplication () {
+               asm volatile (
+                       "__gdb_stopApplication: \n"
+                       "push  r25       \n"  // save r25 (used for address of gdb::gdb.breakpoint)
+                       "lds r25, 0x08fc \n"  // gdb.status
+                       "andi r25, 0x01  \n"  // gdb.status.isConnected
+                       "breq __gdb_stopApplication_end \n"
+                       "in    r25, 0x3f \n"  // SFR -> r25
+                       "cli             \n"  // disable interrupts while saveBreakpoints()
+                       "push  r25       \n"  // save original SFR
+                       "push  r24       \n"  // save parameter register
+               );
+               gdb::saveBreakpointRegs(GDB_BREAKPOINT_PTR);
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               pgdb->status.isBreakpointValid = 1;
+               asm volatile (
+                       "pop  r24        \n"  // restore r24
+               );
+               gdb::stopApplication();
+               asm volatile (
+                       "pop  r25        \n"  // restore SFR
+                       "out  0x3f, r25  \n"
+                       "__gdb_stopApplication_end: \n"
+                       "pop  r25        \n"  // restore r25
+                       "ret             \n"
+               );
+       }
+
+
+    void init () {
+               DDRB |= (1 << PB0); // ~K1-ON via SW6D or Life-LED via JP9
+               setLifeLed(1);
+
+               UBRR0L = (F_CPU / GLOBAL_UART0_BITRATE + 4) / 8 - 1;
+               UBRR0H = 0x00;
+               UCSR0A = (1 << U2X0);
+               UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8 Bit Mode
+               UCSR0B = (1 << TXEN0) | (1 << RXEN0);
+
+               UBRR1L = (F_CPU / GLOBAL_UART1_BITRATE + 4) / 8 - 1;
+               UBRR1H = 0x00;
+               UCSR1A = (1 << U2X1);
+               UCSR1B = (1 << UCSZ11) | (1 << UCSZ10);  // 8 Bit Mode
+               UCSR1B = (1 << TXEN1) | (1 << RXEN1);
+
+               gdb::init();
+               // if (SPL == 0xfb) { // init called from main() via blgdb::init()
+               //      struct gdb::Gdb *pgdb = GDB_PTR;
+               //      pgdb->status.isAppStarted = 1;
+               //      pgdb->status.isStopped = 0;
+               // }
+               setLifeLed(0);
+       }
+
+       uint8_t prepareAppStart () {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               TCCR1B = (1 << CS12) | (1 << CS10); // fCPU/1024 = 19,53125kHz@20MHz = 51.2µs/Tick -> 3.36s to 0xffff
+               uint8_t eepromByteAddrZero = eepromReadByte(0);
+
+               do {
+                       putln(stdoutUart);
+                       uint8_t startProgram = 0xff - eepromByteAddrZero;
+                       while (startProgram > 0 ) { // never start bootloader wait when eeprom.0 = 0xff
+                               gdb::checkByteFromGdb();
+                               gdb::executeControl();
+                               gdb::handleGdbRequest();
+                               if (pgdb->ctrl.start) {
+                                       pgdb->ctrl.start = 0;
+                                       startProgram = 0;
+                               }
+                               if (startProgram == 0 || TCNT1 >= 0x2626) { // 500,0192ms
+                                       TCNT1 = 0;
+                                       gdb::serve500msTimer();
+                                       if (startProgram > 0 && !pgdb->status.isStopped) {
+                                               startProgram--;
+                                       }
+                                       printChar(stdoutUart, '\r');
+                                       putUint8Hex(stdoutUart, startProgram);
+                                       printChar(stdoutUart, ' ');
+                                       printWelcomeMessage();
+                                       toggleLifeLed();
+                               }
+                               int b = getc(stdinUart);
+                               if ( b == 27) { // escape pressed
+                                       break;
+                               }
+                       }
+               } while (eepromByteAddrZero == 0); // never leave bootloader when eeprom.0 == 0
+
+               uint8_t b = pgm_read_byte(0x0000); // check if app in non bootloader flash
+
+               if (b != 0xff) {
+                       struct gdb::Gdb *pgdb = GDB_PTR;
+                       pgdb->status.isAppStarted = 1;
+                       pgdb->status.isStopped = 0;
+                       while (pgdb->status.isConnected && pgdb->status.isStopped) {
+                               gdb::checkByteFromGdb();
+                               gdb::handleGdbRequest();
+                       }
+               }
+               putln(stdoutUart);
+               // make sure that last UART Bytes are sent completely
+               TCNT1 = 0;
+               while (TCNT1 < 0x2000) {} // delay startup app
+
+               #ifndef SIMAVR
+                       UCSR0B = 0; // disable UART0
+                       UCSR1B = 0; // disable UART1
+               #endif
+               TCCR1B = 0; // disable Timer 1
+
+               return b != 0xff;
+
+       }
+
+       void putUint8Hex (int8_t uart, uint8_t value) {
+               char s[3];
+               s[0] = gdb::dec2hex((value >> 4) & 0x0f);
+               s[1] = gdb::dec2hex(value & 0x0f);
+               s[2] = 0;
+               puts(uart, s);
+       }
+
+       void printWelcomeMessage () {
+               asm volatile (
+                       "__print_welcome_message: \n"
+               );
+               memputs(stdoutUart, BOOTLOADER_MSG_TEXT);
+               printChar(stdoutUart, ' ');
+               printChar(stdoutUart, '(');
+               memputs(stdoutUart, BOOTLOADER_MSG_DATE);
+               printChar(stdoutUart, ',');
+               memputs(stdoutUart, BOOTLOADER_MSG_TIME);
+               printChar(stdoutUart, ')');
+               printChar(stdoutUart, '\r');
+       }
+
+       void setLifeLed (bool on) {
+               if (on) {
+                       PORTB |= (1 << PB0);
+               } else {
+                       PORTB &= ~(1 << PB0);
+               }
+       }
+
+       void toggleLifeLed () {
+               PORTB ^= (1 << PB0);
+       }
+
+       int getUart0Byte () {
+               if ( !(UCSR0A & (1 << RXC0)) ) {
+                       return -1;
+               }
+               return UDR0;
+       }
+
+       int getUart1Byte () {
+               if ( !(UCSR1A & (1 << RXC1)) ) {
+                       return -1;
+               }
+               return UDR1;
+       }
+
+       void putUart0Byte (char c) {
+               while (!(UCSR0A & (1 << UDRE0))) {
+                       gdb::checkByteFromGdb();
+                       if ( !(UCSR0B & (1 << TXEN0)) ) {
+                               return;
+                       }
+               }
+               UDR0 = c;
+       }
+
+       void putUart1Byte (char c) {
+               while (!(UCSR1A & (1 << UDRE1))) {
+                       gdb::checkByteFromGdb();
+                       if ( !(UCSR1B & (1 << TXEN1)) ) {
+                               return;
+                       }
+               }
+               UDR1 = c;
+       }
+
+       void printChar (int8_t uart, char c) {
+               asm volatile (
+                       "__bootloader_printChar: \n"
+               );
+               // switch (uart) {
+               //      case 0: putUart0Byte(c); break;
+               //      case 1: putUart1Byte(c); break;
+               // }
+               if (uart == 0) {
+                       putUart0Byte(c);
+               } else {
+                       putUart1Byte(c);
+               }
+       }
+
+       void putnc (int8_t uart, char c, uint8_t n) {
+               while (n-- > 0) {
+                       printChar(uart, c);
+               }
+       }
+
+       void putln (int8_t uart) {
+               printChar(uart, '\r');
+               printChar(uart, '\n');
+       }
+
+       void puts (int8_t uart, const char *s) {
+               uint8_t b;
+               while ( (b = *s++) ) {
+                       printChar(uart, b);
+               }
+       }
+
+       void memputc (int8_t uart, PGM_P p) {
+               char c = pgm_read_byte(p);
+               printChar(uart, c);
+       }
+
+       void memputs (int8_t uart, PGM_P p) {
+               if (uart < 0) {
+                       return;
+               }
+               while (1) {
+                       char c = pgm_read_byte(p++);
+                       if (c == 0) {
+                               break;
+                       }
+                       printChar(uart, c);
+               }
+       }
+
+       int getc (int8_t uart) {
+               switch (uart) {
+                       case 0: return getUart0Byte();
+                       case 1: return getUart1Byte();
+               }
+               return -1;
+       }
+
+       uint8_t eepromReadByte (const uint8_t *p) {
+               asm volatile (
+                       "sbic   0x1f, 1    \n"  // 0x1f = EECR.EEPE
+                       "rjmp   .-4        \n"
+                       "out    0x22, r25  \n"
+                       "out    0x21, r24  \n"
+                       "sbi    0x1f, 0    \n"
+                       "eor    r25, r25   \n"
+                       "in     r24, 0x20  \n"
+                       "ret               \n"
+               );
+       }
+
+       void eepromWriteByte (uint8_t *p, uint8_t value) {
+               // eeprom_write_byte(p, value)
+               asm volatile (
+                       "mov    r18, r22  \n"
+                       "sbic   0x1f, 1   \n"
+                       "rjmp   .-4       \n"
+                       "out    0x1f, r1  \n"
+                       "out    0x22, r25 \n"
+                       "out    0x21, r24 \n"
+                       "out    0x20, r18 \n"
+                       "in     r0, 0x3f  \n"
+                       "cli              \n"
+                       "sbi    0x1f, 2   \n"
+                       "sbi    0x1f, 1   \n"
+                       "out    0x3f, r0  \n"
+                       "adiw   r24, 0x01 \n"
+                       "ret              \n"
+               );
+
+       }
+
+}
diff --git a/software/gdb-stub/src/bootloader.h b/software/gdb-stub/src/bootloader.h
new file mode 100644 (file)
index 0000000..213b83c
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef BOOTLOADER_H
+#define BOOTLOADER_H
+
+#define stdoutUart 0
+#define stderrUart 0
+#define stdinUart 0
+#define gdboutUart 1
+#define gdbinUart 1
+
+#include <avr/pgmspace.h>
+#include "blgdb.h"
+
+
+#ifdef SIMAVR
+       // #define ATT_OPTIMIZE __attribute__((optimize("O0")))
+       #define ATT_OPTIMIZE
+       #define ATT_SECTION_BOOTLOADER_START
+       #define ATT_SECTION_BOOTLOADER_TABLE
+       #define ATT_SECTION_BOOTLOADER
+       #define BOOTLOADERMEM PROGMEM
+       #define BOOTLOADERMEM_0 PROGMEM
+       #define BOOTLOADERMEM_1 PROGMEM
+       #define BOOTLOADERMEM_2 PROGMEM
+       #define BOOTLOADERMEM_3 PROGMEM
+       #define BOOTLOADERMEM_4 PROGMEM
+       #define BOOTLOADERMEM_5 PROGMEM
+#else
+       #define ATT_OPTIMIZE
+       #define ATT_SECTION_BOOTLOADER_START __attribute__((section(".bootloader_start")))
+       #define ATT_SECTION_BOOTLOADER_TABLE __attribute__((section(".bootloader_table")))
+       #define ATT_SECTION_BOOTLOADER       __attribute__((section(".bootloader")))
+       #define BOOTLOADERMEM                __attribute__((section(".bootloadermem")))
+       #define BOOTLOADERMEM_0              __attribute__((section(".bootloadermem_0")))
+       #define BOOTLOADERMEM_1              __attribute__((section(".bootloadermem_1")))
+       #define BOOTLOADERMEM_2              __attribute__((section(".bootloadermem_2")))
+       #define BOOTLOADERMEM_3              __attribute__((section(".bootloadermem_3")))
+       #define BOOTLOADERMEM_4              __attribute__((section(".bootloadermem_4")))
+       #define BOOTLOADERMEM_5              __attribute__((section(".bootloadermem_5")))
+#endif
+
+
+namespace bootloader {
+
+       void bootloaderStart ()                           ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+       void bootloaderStartFromApp ()                    ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+       void bootloaderStartFromReset ()                  ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+       void bootloaderStartFromReset2 ()                 ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+
+       void bootloaderInit (size_t size)                 ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+       void bootloaderLoop ()                            ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_START;
+
+       void jmpTableGdbInit ()                           ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       void jmpTableGdbMain ()                           ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       void jmpTableGdbStopApplication ()                ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       extern "C" void __vector_jmpTableIsrUsart1 ()     ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void jmpTablePuts (const char *s)                 ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       void jmpTablePutUint8Hex (uint8_t value)          ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       void jmpTableMemputc (PGM_P p)                    ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+       void jmpTableMemputs (PGM_P p)                    ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+    void jmpTableGdbServe500msTimer ()                ATT_OPTIMIZE ATT_SECTION_BOOTLOADER_TABLE;
+
+       void init ()                                      ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       uint8_t prepareAppStart ()                        ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+
+    void printStringInFlash (int8_t uart, PGM_P s)    ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void printWelcomeMessage ()                       ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void setLifeLed (bool on)                         ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void toggleLifeLed ()                             ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+
+       int getUart0Byte ()                               ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       int getUart1Byte ()                               ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void putUart0Byte (char c)                        ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void putUart1Byte (char c)                        ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void printChar (int8_t uart, char c)              ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void putnc (int8_t uart, char c, uint8_t n)       ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void putln (int8_t uart)                          ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void puts (int8_t uart, const char *s)            ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void putUint8Hex (int8_t uart, uint8_t value)     ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void memputc (int8_t uart, PGM_P p)               ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       void memputs (int8_t uart, PGM_P p)               ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+       int getc (int8_t uart)                            ATT_OPTIMIZE ATT_SECTION_BOOTLOADER;
+
+    uint8_t eepromReadByte (const uint8_t *p)         ATT_OPTIMIZE ATT_SECTION_BOOTLOADER __attribute__ ((naked));
+       void eepromWriteByte (uint8_t *p, uint8_t value)  ATT_OPTIMIZE ATT_SECTION_BOOTLOADER __attribute__ ((naked));
+
+} // namespace bootloader
+
+#endif // BOOTLOADER_H
\ No newline at end of file
diff --git a/software/gdb-stub/src/gdb.cpp b/software/gdb-stub/src/gdb.cpp
new file mode 100644 (file)
index 0000000..6fb9e90
--- /dev/null
@@ -0,0 +1,821 @@
+#include "gdb.h"
+#include "bootloader.h"
+
+#include <avr/boot.h>
+#include <avr/interrupt.h>
+#include <avr/wdt.h>
+#include <avr/pgmspace.h>
+
+#include <util/delay.h>
+
+#include <string.h>
+
+
+
+#define GDB_DEBUG_UART 0
+// #define GDB_DEBUG_UART_REQUEST GDB_DEBUG_UART
+// #define GDB_DEBUG_UART_FLASHERASE GDB_DEBUG_UART
+// #define GDB_DEBUG_UART_FLASHWRITE GDB_DEBUG_UART
+// #define GDB_DEBUG_UART_REQUEST_PACKET GDB_DEBUG_UART
+#define GDB_DEBUG_UART_STOP_APPLICATION
+
+#define GDB_DEBUG_ID_RESTART_BOOTLOADER   'B'
+#define GDB_DEBUG_ID_FLASH_ERASE          'E'
+#define GDB_DEBUG_ID_FLASH_WRITE          'F'
+#define GDB_DEBUG_ID_KILL_APPLICATION     'K'
+#define GDB_DEBUG_ID_REQUEST              'R'
+#define GDB_DEBUG_ID_STOP_APPLICATION     'S'
+#define GDB_DEBUG_ID_FLASH_WATCHDOG_RESET 'W'
+
+namespace gdb {
+
+       const char gdb_OK[]                 GDBMEM = "$OK#";
+       const char gdb_E00[]                GDBMEM = "$E00#";
+
+       // struct Gdb gdb;
+       // struct Buffer buf;
+
+       // uint16_t cnt = 0;
+
+       void init () {
+       }
+
+       void main () {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               if (pgdb->status.isAppStarted && pgdb->status.isStopped) {
+                       asm volatile (
+                               "in r0, 0x3f  ; SREG -> r0 \n"
+                               "cli \n"
+                               "push r0 \n"
+                       );
+                       while (pgdb->status.isAppStarted && pgdb->status.isStopped) {
+                               checkByteFromGdb();
+                               executeControl();
+                               handleGdbRequest();
+                       }
+                       if (pgdb->status.isAppStarted) {
+                               // enable interrupts if app not killed and interrupts were enabled before
+                               asm volatile (
+                                       "pop r0 \n"
+                                       "out 0x3f, r0;  restore SREG \n"
+                               );
+                       } else {
+                               asm volatile (
+                                       "pop r0 \n"
+                               );
+                       }
+
+               } else {
+                       executeControl();
+                       handleGdbRequest();
+               }
+
+               if (!pgdb->status.isAppStarted) {
+                       #ifdef GDB_DEBUG_UART
+                               printdbgln(GDB_DEBUG_ID_RESTART_BOOTLOADER);
+                               _delay_ms(1);
+                       #endif
+                       bootloader::bootloaderStart();
+               }
+       }
+
+       __attribute__((noinline, naked)) void saveBreakpointRegs (struct Breakpoint *p) {
+               asm volatile (
+                       "push  r28          \n"
+                       "push  r29          \n"
+                       "movw  r28, r24     \n"  // bp -> Y
+                       "std   Y+31, r31    \n"  // save original r29
+                       "std   Y+30, r30    \n"  // save original r28
+                       "std   Y+27, r27    \n"  // save original r27
+                       "std   Y+26, r26    \n"  // save original r26
+
+                       "in    r30, 0x3d    \n"  // SPL -> ZL
+               "in    r31, 0x3e    \n"  // SPH -> ZH
+                       "ldd   r27, Z+1     \n"  // save original r29
+                       "std   Y+29, r27    \n"
+                       "ldd   r27, Z+2     \n"  // save original r28
+                       "std   Y+28, r27    \n"
+                       "ldd   r24, Z+5     \n"  // restore original r24
+                       "ldd   r27, Z+6     \n"  // save original SFR
+                       "std   Y+36, r27    \n"
+                       "ldd   r25, Z+7     \n"  // restore original r25
+
+                       "ldd   r27, Z+10     \n"  // original (PCH/2) -> r27 (XH)
+                       "ldd   r26, Z+11    \n"  // original (PCL/2) -> r26 (XL)
+                       "adiw  r30, 11      \n"  // restore SP in stop() (4x push + 3x call)
+                       "std   Y+32, r30    \n"  // save SPL
+                       "std   Y+33, r31    \n"  // save SPH
+                       "add   r26, r26     \n"  // X = X * 2
+                       "adc   r27, r27     \n"
+                       "clc                \n"
+                       "sbci  r26, 4       \n"  // X = X - 4 (restore PC of stop)
+                       "sbci  r27, 0       \n"
+                       "std   Y+34, r26    \n"  // save PC in stop()
+                       "std   Y+35, r27    \n"  // save PC in stop()
+
+                       "ldi   r30, 0x00    \n"  // 0 (I/O-reg r0) -> ZL
+                       "ldi   r31, 0x00    \n"  // 0 (I/O-reg r0) -> ZH
+
+               "loop: ld r27, Z+   \n"  // save r0..r26 to bp->reg[...]
+                       "st    Y+, r27      \n"
+            "cpi   r30, 25      \n"
+                       "brne  loop         \n"
+
+                       "pop   r29          \n"
+                       "pop   r28          \n"
+                       "ret                \n"
+               );
+       }
+
+       void stopApplication () {
+               #ifdef GDB_DEBUG_UART_STOP_APPLICATION
+                       printdbgln(GDB_DEBUG_ID_STOP_APPLICATION);
+               #endif
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               pgdb->ctrl.stop = 1;
+               main();
+       }
+
+       void printdbg (char id) {
+               #ifdef GDB_DEBUG_UART
+                       bootloader::putln(GDB_DEBUG_UART);
+                       bootloader::printChar(GDB_DEBUG_UART, '@');
+                       bootloader::printChar(GDB_DEBUG_UART, id);
+                       bootloader::printChar(GDB_DEBUG_UART, ' ');
+               #endif
+       }
+
+       void printdbgln (char id) {
+               #ifdef GDB_DEBUG_UART
+                       printdbg(id);
+                       bootloader::putln(GDB_DEBUG_UART);
+               #endif
+       }
+
+
+       void reset () {
+               printdbgln(GDB_DEBUG_ID_FLASH_WATCHDOG_RESET);
+               cli();
+               wdt_enable(WDTO_500MS);
+               wdt_reset();
+               do {} while(1);
+       }
+
+       void xputsStop () {
+               xputc('%');
+               xputc('#');
+       }
+
+       // ATTENTION: static data not initialized when application not started !!
+       // ---> xputs('hello'); not working!!!
+
+       void serve500msTimer () {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               if (pgdb->timer > 0) {
+                       pgdb->timer--;
+               }
+       }
+
+       uint8_t createFlashCrc (PGM_P startAddress, size_t size) {
+               uint8_t crc = 0xff;
+               uint8_t i;
+               while (size-- > 0) {
+                       crc ^= pgm_read_byte(startAddress++);
+                       for (i = 0; i < 8; i++) {
+                               if (crc & 0x01) {
+                                       crc = (crc >> 1) ^ 0x8c;
+                               } else {
+                                       crc = crc >> 1;
+                               }
+                       }
+               }
+               return crc;
+       }
+
+       // uint16_t updateModbusCRC (uint16_t crc, uint8_t b) {
+       //      crc = crc ^ b;
+       //      for (uint8_t i = 0; i < 8; i++) {
+       //              // eslint-disable-next-line unicorn/prefer-ternary
+       //              if (crc & 0x0001) {
+       //                      crc = (crc >> 1) ^ 0xa001;
+       //              } else {
+       //                      crc = crc >> 1;
+       //              }
+       //      }
+       //      return crc;
+       // }
+
+       // uint16_t flashCrc (uint16_t startAddress, uint16_t endAddress) {
+       //      PGM_P p = (PGM_P) startAddress;
+       //      uint16_t crc = 0xffff;
+       //      while (p <= (PGM_P)endAddress) {
+       //              uint8_t b = pgm_read_byte(p);
+       //              // crc = updateModbusCRC(crc, b);
+       //              crc += b;
+       //              p++;
+       //      }
+       //      return crc;
+       // }
+
+       void eraseFlash (uint16_t addressStart, uint16_t addressEnd) {
+               // do {} while ((SPMCSR & (1 << SPMEN)) == 1); // = boot_spm_busy_wait()
+               // do {} while ((EECR & (1 << EEPE)) == 1);    // = eeprom_busy_wait()
+               bootloader::putln(0);
+               for (uint16_t addr = addressStart; addr < 0x7000 && addr <= addressEnd; addr += SPM_PAGESIZE) {
+                       boot_spm_busy_wait();
+                       eeprom_busy_wait();
+                       boot_page_erase(addr);
+                       #ifdef GDB_DEBUG_UART_FLASHERASE
+                               printdbg(GDB_DEBUG_ID_FLASH_ERASE);
+                               bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(addr >> 8));
+                               bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(addr));
+                               bootloader::putln(GDB_DEBUG_UART);
+                       #endif
+               }
+               #ifdef GDB_DEBUG_UART_FLASHERASE
+                       bootloader::printChar(GDB_DEBUG_UART, '@');
+                       bootloader::putln(GDB_DEBUG_UART);
+               #endif
+       }
+
+       void writeFlash (uint8_t *from, uint8_t size, uint16_t toPage) {
+               #ifdef GDB_DEBUG_UART_FLASHWRITE
+                       printdbg(GDB_DEBUG_ID_FLASH_WRITE);
+               #endif
+               uint8_t i;
+               for (i = size; i < SPM_PAGESIZE; i++ ) {
+                       from[i] = 0xff;
+               }
+               uint16_t toAddress = (toPage * SPM_PAGESIZE);
+               for (i = 0; i < SPM_PAGESIZE; i++ ) {
+                       uint8_t bFrom = pgm_read_byte((PGM_P)(toAddress + i));
+                       if (bFrom != from[i]) {
+                               break;
+                       }
+               }
+               if (i < SPM_PAGESIZE) {
+                       #ifdef GDB_DEBUG_UART_FLASHERASE
+                               printdbg(GDB_DEBUG_ID_FLASH_ERASE);
+                               bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(toAddress >> 8));
+                               bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(toAddress));
+                               #endif
+                       eeprom_busy_wait();
+                       boot_page_erase(toAddress);
+                       boot_spm_busy_wait();
+                       for (i = 0; i < SPM_PAGESIZE; i += 2) {
+                               uint16_t w = *from++;
+                               w += (*from++) << 8;
+                               boot_page_fill(toAddress + i, w);
+                               #ifdef GDB_DEBUG_UART_FLASHWRITE
+                                       bootloader::printChar(GDB_DEBUG_UART, ' ');
+                                       bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(w >> 8));
+                                       bootloader::printCharUint8Hex(GDB_DEBUG_UART, (uint8_t)(w));
+                               #endif
+                       }
+                       boot_page_write(toAddress);
+                       #ifdef GDB_DEBUG_UART_FLASHWRITE
+                               bootloader::printChar(GDB_DEBUG_UART, 'W');
+                       #endif
+                       boot_spm_busy_wait();
+               }
+
+               #ifdef GDB_DEBUG_UART_FLASHWRITE
+                       bootloader::printChar(GDB_DEBUG_UART, '@');
+                       bootloader::putln(GDB_DEBUG_UART);
+               #endif
+
+       }
+
+       void executeControl () {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               if (*((uint8_t *)&pgdb->ctrl) == 0) {
+                       return;
+               }
+
+               if (pgdb->ctrl.reset) {
+                       reset();
+
+               } else if (pgdb->ctrl.kill) {
+                       pgdb->ctrl.kill = 0;
+                       #ifdef GDB_DEBUG_UART
+                               printdbgln(GDB_DEBUG_ID_KILL_APPLICATION);
+                       #endif
+                       if (pgdb->status.isAppStarted) {
+                               cli();
+                               // pgdb->status.isStopped = 0;
+                               pgdb->status.isAppStarted = 0;
+                       }
+
+               } else if (pgdb->ctrl.stop) {
+                       pgdb->ctrl.stop = 0;
+                       if (!pgdb->status.isStopped) {
+                               if (pgdb->status.isAppStarted) {
+                               #ifdef GDB_DEBUG_UART
+                                       printdbgln(GDB_DEBUG_ID_STOP_APPLICATION);
+                               #endif
+                               }
+                               pgdb->status.isStopped = 1;
+                               pgdb->timer = 20;
+                               xputsStop();
+                       }
+
+               } else if (pgdb->ctrl.proceed) {
+                       pgdb->ctrl.proceed = 0;
+                       pgdb->status.isBreakpointValid = 0;
+                       pgdb->status.isStopped = 0;
+
+               }  else if (pgdb->ctrl.clearErrors) {
+                       pgdb->status.errorFlags = 0;
+               }
+       }
+
+       void handleGdbRequest () {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               struct Buffer *p = &pgdb->buffer;
+               if (p->state == execerr) {
+                       xputc('-');
+                       p->state = idle;
+
+               } else if (p->state == exec) {
+                       xputc('+');
+                       #ifdef GDB_DEBUG_UART_REQUEST
+                               #ifdef GDB_DEBUG_UART_REQUEST_PACKET
+                                       printdbg(GDB_DEBUG_ID_REQUEST);
+                                       bootloader::printChar(0, ' ');
+                                       for (uint8_t i = 0; i < p->rpos; i++) {
+                                               bootloader::printChar(0, p->buffer[i]);
+                                       }
+                                       bootloader::putln(GDB_DEBUG_UART);
+                               #else
+                                       printdbgln(GDB_DEBUG_ID_REQUEST);
+                               #endif
+                       #endif
+                       pgdb->status.isConnected = 1;
+                       p->buffer[(p->rpos < sizeof(p->buffer) - 1) ? p->rpos : sizeof(p->buffer) - 1] = 0;
+                       p->state = send;
+                       uint8_t i;
+
+                       switch(*p->buffer) {
+
+                               // case '?': {
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-_003f-packet
+                               //      // This is sent when connection is first established to query the reason the target halted.
+                               //      xputsmem(gdb_OK);
+                               //      // if (gdb.appInfo.isStarted && !gdb.appInfo.isRunning) {
+                               //      //      xputsStop(0);
+                               //      // } else {
+                               //      //      xputsmem(gdb_OK);
+                               //      // }
+                               //      return;
+                               // }
+
+                               case 'D': {
+                                       // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-D-packet
+                                       // The packet is used to detach GDB from the remote system
+                                       pgdb->status.isConnected = 0;
+                                       pgdb->status.isStopped = 0;
+                                       xputsmem(gdb_OK);
+                                       return;
+                               }
+
+                               // case 'T': {
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-T-packet
+                               //      // Find out if the thread thread-id is alive.
+                               //      uint8_t ok = 0;
+                               //      uint8_t threadId = p->buffer[1] - '0';
+                               //      switch (threadId) {
+                               //              case 1: ok = 1; break;
+                               //              case 2: ok = gdb.status.isAppStarted; break;
+                               //              case 3: ok = gdb.status.isAppStarted; break;
+                               //      }
+                               //      if (ok) {
+                               //              gdb.status.currentThread = threadId; // ??? notwendig?
+                               //              xputsmem(gdb_OK);
+                               //      } else {
+                               //              xputsmem(gdb_E00);
+                               //      }
+                               //      return;
+                               // }
+
+
+                               case 'm': {
+                                       // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-m-packet
+                                       // Read length addressable memory units starting at address addr
+                                       xputc('$');
+                                       i = 1;
+                                       uint32_t address, length;
+                                       i += parseHex(p->buffer, i, &address);
+                                       if (p->buffer[i++] == ',') {
+                                               if (parseHex(p->buffer, i, &length) > 0) {
+                                                       uint8_t l = length > BUFFER_SIZE / 2 ? BUFFER_SIZE / 2 : length;
+                                                       volatile uint8_t *px = (volatile uint8_t *)(address & 0xffff);
+                                                       uint8_t addH = (address >> 16) & 0xff;
+                                                       for (uint8_t j = 0; j < l; j++) {
+                                                               uint8_t vx = 0;
+                                                               if (addH == 0) {
+                                                                       // flash
+                                                                       vx = pgm_read_byte( (PGM_P)px );
+                                                               } else if ( (uint16_t)px >= 0x900) {
+                                                                       // eeprom
+                                                                       vx = bootloader::eepromReadByte((uint8_t *)(px - 0x900));
+
+                                                               } else if (addH == 0x82) {
+                                                                       // crc8 from flash
+                                                                       vx = createFlashCrc((PGM_P)((uint16_t)px * SPM_PAGESIZE), SPM_PAGESIZE);
+
+                                                               } else {
+                                                                       // io-regs (0x000 - 0x0ff), sram (0x100 -  0x8ff)
+                                                                       vx = *px;
+
+                                                               }
+                                                               px++;
+                                                               xputUint8Hex(vx);
+                                                       }
+                                               }
+                                       }
+                                       xputc('#');
+                                       return;
+                               }
+
+                               case 'X': {
+                                       // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-X-packet
+                                       // Write data to memory, where the data is transmitted in binary.
+                                       i = 1;
+                                       uint32_t address, length;
+                                       i += parseHex(p->buffer, i, &address);
+                                       if (p->buffer[i++] == ',') {
+                                               uint8_t j = parseHex(p->buffer, i, &length);
+                                               if (j > 0) {
+                                                       uint8_t l = length > BUFFER_SIZE / 2 ? BUFFER_SIZE / 2 : length;
+                                                       volatile uint8_t *pFrom = (volatile uint8_t *)(p->buffer + i + j + 1);
+                                                       volatile uint8_t *pTo = (volatile uint8_t *)(address & 0xffff);
+                                                       uint8_t addH = (address >> 16) & 0xff;
+                                                       for (j = 0; j < l; j++) {
+                                                               uint8_t vx = *pFrom++;
+                                                               if (addH == 0) {
+                                                                       // flash
+                                                                       xputsmem(gdb_E00);
+                                                                       return;
+                                                               } else if (addH == 0xa0) {
+                                                                       xputsmem(gdb_OK);
+                                                                       return;
+                                                               }
+                                                               if ( (uint16_t)pTo >= 0x900) {
+                                                                       // eeprom
+                                                                       bootloader::eepromWriteByte((uint8_t *)(pTo - 0x900), vx);
+
+                                                               } else  if ( (uint16_t)pTo >= 0x100) {
+                                                                       // sram
+                                                                       *pTo = vx;
+
+                                                               } else {
+                                                                       xputsmem(gdb_E00);
+                                                                       return;
+                                                               }
+                                                               pTo++;
+                                                       }
+                                                       xputsmem(gdb_OK);
+                                                       return;
+                                               }
+                                       }
+                                       xputsmem(gdb_E00);
+                                       return;
+                               }
+
+                       }
+
+                       uint8_t sum = 0;
+                       for (i = 0; i < p->rpos; i++) {
+                               char c = p->buffer[i];
+                               sum += c;
+
+                               if (i == 10 && sum == 0x71) { // qSupported:
+                                       // https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html#index-qSupported-packet
+                                       // Tell the remote stub about features supported by GDB, and query the stub for features it supports.
+                                       xputc('$');
+                                       xputc('#');
+                                       return;
+                               } else if (
+                                       (i == 7 && sum == 0x55)  // vStopped
+                                                                                               // // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vStopped-packet
+                                                                                               // Notification Packet, send queued events, if not events pending send OK
+                               ) {
+                                       xputsmem(gdb_OK);
+                                       return;
+
+                               } else if (i == 11 && sum == 0x8e) { // vFlashErase:
+                                       i = 12;
+                                       uint32_t addressStart, addressEnd;
+                                       i += parseHex(p->buffer, i, &addressStart);
+                                       i++;
+                                       i += parseHex(p->buffer, i, &addressEnd);
+                                       pgdb->ctrl.kill = 1;
+                                       executeControl();
+                                       eraseFlash((uint16_t)addressStart, (uint16_t)addressEnd);
+                                       xputsmem(gdb_OK);
+                                       return;
+
+                               } else if (i == 9 && sum == 0xea) { // vFlashDone
+                                       asm volatile (
+                                               "nop \n"
+                                       );
+                                       boot_rww_enable();
+                                       xputsmem(gdb_OK);
+                                       return;
+
+                               } else if (i == 11 && sum == 0xa9) { // vFlashWrite:
+                                       pgdb->ctrl.kill = 1;
+                                       executeControl();
+                                       uint8_t i = 12;
+                                       uint32_t addressStart;
+                                       i += parseHex(p->buffer, i, &addressStart);
+                                       if (p->buffer[i++] != ':') {
+                                               xputsmem(gdb_E00);
+                                       } else {
+                                               asm volatile (
+                                                       "nop \n"
+                                               );
+                                               writeFlash((uint8_t *)&p->buffer[i], p->rpos - i, (uint16_t)addressStart / SPM_PAGESIZE);
+                                               xputsmem(gdb_OK);
+                                       }
+                                       return;
+                               }
+                               // } else if (i == 11 && sum == 0xbb) {    // qfThreadInfo
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html#index-qfThreadInfo-packet
+                               //      // Start to obtain a list of all active thread IDs from the target
+                               //      // !! don't user xputs here, because dgb_stub does not initialize static data in sram
+                               //      xputsmem(gdb_m1_);
+                               //      if (gdb.status.isAppStarted) {
+                               //              xputc(',');
+                               //              xputc('2');
+                               //              xputc(',');
+                               //              xputc('3');
+                               //      }
+                               //      xputc('#');
+                               //      return;
+
+                               // } else if (i == 11 && sum == 0xc8) {   // qsThreadInfo
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html#index-qfThreadInfo-packet
+                               //      // Continue to obtain a list of all active thread IDs from the target
+                               //      // !! don't user xputs here, because dgb_stub does not initialize static data in sram
+                               //      xputsmem(gdb_l);
+                               //      // xputc('$');
+                               //      // xputc('l');
+                               //      // xputc('#');
+                               //      return;
+
+                               // } else if (i == 5 && sum == 0x49) { // vCont?
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vCont_003f-packet
+                               //      // Request a list of actions supported by the â€˜vCont’ packet.
+                               //      xputsmem(gdb_vCont);
+                               //      return;
+
+                               // } else if (i == 6 && sum == 0xa8) { // vCont;c
+                               //      // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vCont-packet
+                               //      // Resume the inferior, specifying different actions for each thread.
+                               //      xputsmem(gdb_OK);
+                               //      return;
+
+                               // } else if (
+                               //      (i == 6 && sum == 0xb9)         // vCont;t
+                               //                                                              // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vCont-packet
+                               //                                                              // Resume the inferior, specifying different actions for each thread.
+                               //      || (i == 5 && sum == 0x4e)  // vCtrlC
+                               //                                                              // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vCtrlC-packet
+                               //                                                              // Interrupt remote target as if a control-C was pressed on the remote terminal.
+                               // ) {
+                               //      uint8_t threadId = p->buffer[8] - '0';
+                               //      gdb.status.currentThread = threadId & 0x03;
+                               //      switch (threadId) {
+                               //              case 1: gdb.ctrl.continueGdbStub = 1; break;
+                               //              case 2: gdb.ctrl.continueApplication = 1; break;
+                               //              case 3: gdb.ctrl.continueInterrupts = 1; break;
+                               //      }
+                               //      xputsmem(gdb_OK);
+                               //      return;
+                               // }
+                       }
+
+                       // request not supported
+                       xputc('$');
+                       xputc('#');
+
+               }
+       }
+
+
+       // void reset () {
+       //      struct gdb::Gdb *pgdb = GDB_PTR;
+       //      memset((void *)&pgdb->buffer, 0, sizeof(pgdb->buffer) - BUFFER_SIZE);
+       // }
+
+       void checkByteFromGdb () {
+               // don't use bootloader::printChar here, because checkByteFromGdb called from there
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               if (!(SREG & 0x80)) {
+                       // check incoming byte only when interrupts disabled
+                       if (!pgdb->status.isAppStarted || pgdb->status.isStopped) {
+                               int b = bootloader::getc(gdbinUart);
+                               if (b >= 0) {
+                                       handleUartIsrByte((char)b);
+                               }
+                       }
+               }
+       }
+
+       uint8_t parseHex (const char *s, uint8_t offset, uint32_t *value) {
+               *value = 0;
+               const char *p = s + offset;
+               uint8_t j;
+               for (j = 0; j < 8; j++, p++) {
+                       uint8_t v;
+                       if (*p >= '0' && *p <= '9') {
+                               v = ((*p) - '0');
+                       } else if (*p >= 'a' && *p <= 'f') {
+                               v = ((*p) - 'a' + 10);
+                       } else {
+                               break;
+                       }
+                       *value = ((*value) << 4) + v;
+               }
+               return j;
+       }
+
+       char dec2hex (uint8_t value) {
+               return value < 10
+                       ? value + '0'
+                       : value - 10  + 'a';
+       }
+
+       void gputc (char c) {
+               bootloader::printChar(gdboutUart, c);
+       }
+
+       void xputc (char c) {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               struct Buffer *pbuf = &pgdb->buffer;
+               bootloader::printChar(gdboutUart, c);
+               switch (c) {
+                       case '$': pbuf->chkSumToGdb = 0; pgdb->status.sendingNotification = 0; break;
+                       case '%': pbuf->chkSumToGdb = 0; pgdb->status.sendingNotification = 1; break;
+                       case '#': {
+                               gputc(dec2hex((pbuf->chkSumToGdb >> 4) & 0x0f));
+                               gputc(dec2hex(pbuf->chkSumToGdb & 0x0f));
+                               if (!pgdb->status.sendingNotification ) {
+                                       pbuf->state = waitack;
+                               }
+                               break;
+                       }
+                       default: pbuf->chkSumToGdb += c; break;
+               }
+
+       }
+
+       void xputs (const char *s) {
+               uint8_t b;
+               while ( (b = *s++) ) {
+                       xputc(b);
+               }
+       }
+
+       void xputsmem (PGM_P p) {
+               uint8_t b;
+               while ( (b = pgm_read_byte(p++)) ) {
+                       xputc(b);
+               }
+       }
+
+       void xputUint8Hex (uint8_t value) {
+               char s[3];
+               s[0] = dec2hex((value >> 4) & 0x0f);
+               s[1] = dec2hex(value & 0x0f);
+               s[2] = 0;
+               xputs(s);
+       }
+
+
+       void incUint8Cnt (uint8_t *cnt) {
+               if ((*cnt) < 0xff) {
+                       (*cnt)++;
+               }
+       }
+
+       int8_t hexValueFromChar (char c) {
+               if (c >= '0' && c <= '9') {
+                       return c - '0';
+               } else if (c >= 'a' && c <= 'f') {
+                       return c - 'a' + 10;
+               } else if (c >= 'A' && c <= 'F') {
+                       return c - 'A' + 10;
+               } else {
+                       return -1;
+               }
+       }
+
+       void pushReceivedByte (uint8_t b) {
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               struct Buffer *p = &pgdb->buffer;
+               if (p->rpos >= BUFFER_SIZE ) {
+                       // incUint8Cnt(&gdb.status.errCnt);
+                       pgdb->status.errorFlags |= 0x01;
+               } else {
+                       p->buffer[p->rpos++] = b;
+               }
+       }
+
+       void handleUartIsrByte (char c) {
+               // bootloader::printChar(stdoutUart, c);
+               struct gdb::Gdb *pgdb = GDB_PTR;
+               struct Buffer *p = &pgdb->buffer;
+               if (c == '$') {
+                       if (p->state != idle) {
+                               // incUint8Cnt(&gdb.status.errCnt);
+                               pgdb->status.errorFlags |= 0x02;
+                       }
+                       p->chkSumFromGdb = 0;
+                       p->rpos = 0;
+                       p->state = data;
+
+               } else {
+                       switch (p->state) {
+                               case data: {
+                                       if (c == '#') {
+                                               p->state = chk1;
+                                       } else {
+                                               p->chkSumFromGdb += c;
+                                               if (c == '}') {
+                                                       p->state = esc;
+
+                                               } else {
+                                                       pushReceivedByte(c);
+                                               }
+                                       }
+                                       break;
+                               }
+
+                               case esc: {
+                                       p->chkSumFromGdb += c;
+                                       pushReceivedByte(c ^ 0x20);
+                                       p->state = data;
+                                       break;
+                               }
+
+                               case chk1: {
+                                       int8_t v = hexValueFromChar(c);
+                                       if (v < 0) {
+                                               p->state = chk2err;
+                                       } else {
+                                               p->chkSumFromGdb -= (v << 4);
+                                               p->state = chk2;
+                                       }
+                                       break;
+                               }
+
+                               case chk2err: {
+                                       // incUint8Cnt(&gdb.status.errCnt);
+                                       pgdb->status.errorFlags |= 0x04;
+                                       p->state = execerr;
+                                       break;
+                               }
+
+                               case chk2: {
+                                       int8_t v = hexValueFromChar(c);
+                                       if (v >= 0) {
+                                               p->chkSumFromGdb -= v;
+                                       }
+                                       if (v < 0 || p->chkSumFromGdb != 0) {
+                                               // incUint8Cnt(&gdb.status.errCnt);
+                                               pgdb->status.errorFlags |= 0x08;
+                                               p->state = execerr;
+
+                                       } else {
+                                               p->state = p->rpos <= BUFFER_SIZE ? exec : execerr;
+                                       }
+                                       break;
+                               }
+
+                               case waitack: {
+                                       if (c == '-') {
+                                               p->state = send;
+                                       } else {
+                                               if (c != '+') {
+                                                       // incUint8Cnt(&gdb.status.errCnt);
+                                                       pgdb->status.errorFlags |= 0x10;
+                                               }
+                                               p->state = idle;
+                                       }
+                                       break;
+                               }
+
+
+                               default: case exec: case execerr: case send: {
+                                       // incUint8Cnt(&gdb.status.errCnt);
+                                       pgdb->status.errorFlags |= 0x20;
+                                       break;
+                               }
+                       }
+               }
+
+       }
+
+}
diff --git a/software/gdb-stub/src/gdb.h b/software/gdb-stub/src/gdb.h
new file mode 100644 (file)
index 0000000..02e8955
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef GDB_H
+#define GDB_H
+
+#include <avr/pgmspace.h>
+
+#ifdef SIMAVR
+       // #define ATT_OPTIMIZE_GDB __attribute__((optimize("O0")))
+       #define ATT_OPTIMIZE_GDB
+       #define ATT_SECTION_GDB
+       #define GDBMEM PROGMEM
+#else
+       #define ATT_OPTIMIZE_GDB
+       #define ATT_SECTION_GDB   __attribute__((section(".gdb")))
+       #define GDBMEM            __attribute__((section(".gdbmem")))
+#endif
+
+
+#define GDB_PTR (gdb::Gdb *)(RAMEND - sizeof(gdb::Gdb) + 1)
+//#define GDB_BREAKPOINT_PTR (struct gdb::Breakpoint *)(RAMEND - 2 - sizeof(gdb::Control) - sizeof(gdb::Status) - sizeof(gdb::Breakpoint) + 1)
+#define GDB_BREAKPOINT_PTR (struct gdb::Breakpoint *)(RAMEND - 4 - sizeof(gdb::Breakpoint))
+
+namespace gdb {
+
+       const uint8_t BUFFER_SIZE = 13 + 5 + 128 + 3; // "$vFlashWrite:" + "ffff:" + 128 Bytes  + "#00"
+
+       enum BufferState { idle = 0, data, esc, chk1, chk2, chk2err, exec, execerr, send, waitack };
+
+
+       struct Status {
+               uint8_t errorFlags;             // @0x08fb
+               uint8_t isConnected:1;          // @0x08fc.0x01, address used in bootloader::jmpTableGdbStopApplication()
+               uint8_t isAppStarted:1;         // 0x02
+               uint8_t isStopped:1;            // 0x04
+               uint8_t isBreakpointValid:1;    // 0x08
+               uint8_t sendingNotification:1;  // 0x10
+       };
+
+       struct Control {
+               uint8_t clearErrors:1; // 0x01
+               uint8_t interrupt:1;   // 0x02
+               uint8_t stop:1;        // 0x04
+               uint8_t proceed:1;     // 0x08
+               uint8_t kill:1;        // 0x10
+               uint8_t start:1;       // 0x20
+               uint8_t reset:1;       // 0x40
+       };
+
+       struct Buffer {
+               enum BufferState state;
+               uint8_t rpos;
+               uint8_t chkSumFromGdb;
+               uint8_t chkSumToGdb;
+               char    buffer[BUFFER_SIZE];
+       };
+
+       struct Breakpoint {
+               uint8_t regs[32];
+               uint16_t sp;
+               uint16_t pc;
+               uint8_t sfr;
+       };
+
+       struct Gdb {
+               uint8_t timer;
+               struct Buffer buffer;
+               struct Breakpoint breakpoint;
+               struct Status status;
+               struct Control ctrl;
+               uint8_t version;
+               uint8_t magic;
+       };
+
+       // extern struct Gdb gdb;
+
+
+       void init ()                                                      ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void main ()                                                      ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void stopApplication ()                                           ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+
+       void printdbg (char id)                                           ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void printdbgln (char id)                                         ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void handleGdbRequest ()                                          ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void serve500msTimer ()                                           ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+
+       void reset ()                                                     ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       // void restart ()                                                   ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void saveBreakpointRegs (struct Breakpoint *p)                    ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void checkByteFromGdb ()                                          ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void eraseFlash (uint16_t addressStart, uint16_t addressEnd)      ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void writeFlash (uint8_t *from, uint8_t size, uint16_t toPage)    ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       uint16_t updateModbusCRC (uint16_t crc, uint8_t b)                ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       uint16_t flashCrc (uint16_t startAddress, uint16_t endAddress)    ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       uint8_t createFlashCrc (PGM_P startAddress, size_t size)          ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       uint8_t parseHex (const char *s, uint8_t offset, uint32_t *value) ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       char dec2hex (uint8_t value)                                      ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void gputc (char c)                                               ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void xputc (char c)                                               ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void xputs (const char *s)                                        ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void xputsmem (PGM_P p)                                           ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void xputsStop ()                                                 ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void xputUint8Hex (uint8_t value)                                 ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void incUint8Cnt (uint8_t *cnt)                                   ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       int8_t hexValueFromChar (char c)                                  ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void pushReceivedByte (uint8_t b)                                 ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void executeControl ()                                            ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+       void handleUartIsrByte (char c)                                   ATT_OPTIMIZE_GDB ATT_SECTION_GDB;
+}
+
+#endif // GDB_H
diff --git a/software/gdb-stub/src/main.cpp b/software/gdb-stub/src/main.cpp
new file mode 100644 (file)
index 0000000..b4b1332
--- /dev/null
@@ -0,0 +1,46 @@
+#include "app.h"
+#include "blgdb.h"
+#include "gdb.h"
+
+volatile uint16_t mainTest = 2;
+
+int __attribute__((naked)) main ()  {
+
+       // normal target startup:
+       //    bootloader section
+       //    ... start app ...
+       //    jmp 0
+       //    startup code ( call main -> 0x08fe: 00 89 )
+       //    main()
+       //    *0x8ff != 0xff ->
+       //        blgdb_init() ( 0xff -> 0x08ff)
+       //    main()
+       //    *0x8ff == 0xff
+       //        continue main()
+
+       // simulation target startup:
+       //    address 0
+       //    startup code ( call main -> 0x08fe: 00 89 )
+       //    main()
+       //    *0x8ff != 0xff ->
+       //        blgdb_init() ( 0xff -> 0x08ff)
+       //    main()
+       //    *0x8ff == 0xff
+       //        continue main()
+
+       #ifdef SIMAVR
+               if (*((uint16_t*)(RAMEND - 1)) != 0xfe01) { // check magic:version of struct gdb
+                       // coming from startup code -> start gdb bootloader
+                       bootloader::bootloaderStart();
+               }
+               // otherwise coming from bootloader -> proceed with blgdb::init()
+       #endif
+
+       blgdb::init();
+       app::init();
+       while (1) {
+               blgdb::main();
+               app::main();
+       }
+}
+