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