--- /dev/null
+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
+
--- /dev/null
+**/.vscode/ipch
+dist/**
+build/**
+sim/dist/**
+sim/build/**
+sim/vcd/**
+nohup.out
+**/*.vcd
+.gdb_history
--- /dev/null
+#--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
+
--- /dev/null
+$(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
--- /dev/null
+# 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
--- /dev/null
+/* 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) }
+}
--- /dev/null
+/* /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) }
+}
--- /dev/null
+/* /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) }
+}
--- /dev/null
+/* /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) }
+}
--- /dev/null
+/* /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) }
+}
--- /dev/null
+/* /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) }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+#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, },
+};
+
+
--- /dev/null
+
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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"
+ );
+
+ }
+
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+ }
+ }
+ }
+
+ }
+
+}
--- /dev/null
+#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
--- /dev/null
+#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();
+ }
+}
+