From 0637ec2d9f80d8cf8b07dd8756321d74a8f0e1b3 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sun, 21 Jul 2024 18:59:01 +0200 Subject: [PATCH] ... --- software/gdb-stub/.gdbinit-gdbstub | 4 + software/gdb-stub/src/bootloader.cpp | 14 +-- software/gdb-stub/src/gdb.cpp | 138 ++++++++++++++++++++------- software/gdb-stub/src/gdb.h | 3 +- 4 files changed, 117 insertions(+), 42 deletions(-) diff --git a/software/gdb-stub/.gdbinit-gdbstub b/software/gdb-stub/.gdbinit-gdbstub index ad7a6f7..f01898e 100644 --- a/software/gdb-stub/.gdbinit-gdbstub +++ b/software/gdb-stub/.gdbinit-gdbstub @@ -1 +1,5 @@ target remote :1234 +layout split +focus cmd +br *0 + diff --git a/software/gdb-stub/src/bootloader.cpp b/software/gdb-stub/src/bootloader.cpp index 19d7efc..cab6c1b 100644 --- a/software/gdb-stub/src/bootloader.cpp +++ b/software/gdb-stub/src/bootloader.cpp @@ -307,13 +307,15 @@ namespace bootloader { toggleLedRed(); TCNT1 = 0; gdb::serve500msTimer(); - if (startProgram > 0 && !pgdb->status.isStopped) { - startProgram--; + if (pgdb->status.flashPage < 0) { + if (startProgram > 0 && !pgdb->status.isStopped) { + startProgram--; + } + printChar(stdoutUart, '\r'); + putUint8Hex(stdoutUart, startProgram); + printChar(stdoutUart, ' '); + printWelcomeMessage(); } - printChar(stdoutUart, '\r'); - putUint8Hex(stdoutUart, startProgram); - printChar(stdoutUart, ' '); - printWelcomeMessage(); } int b = getc(stdinUart); if ( b == 27) { // escape pressed diff --git a/software/gdb-stub/src/gdb.cpp b/software/gdb-stub/src/gdb.cpp index da0ecf4..61978e2 100644 --- a/software/gdb-stub/src/gdb.cpp +++ b/software/gdb-stub/src/gdb.cpp @@ -14,8 +14,9 @@ #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_FLASHERASE GDB_DEBUG_UART +#define GDB_DEBUG_UART_FLASHWRITE GDB_DEBUG_UART +// #define GDB_DEBUG_UART_KILL_APPLICATION GDB_DEBUG_UART // #define GDB_DEBUG_UART_REQUEST_PACKET GDB_DEBUG_UART // #define GDB_DEBUG_UART_STOP_APPLICATION @@ -91,7 +92,12 @@ namespace gdb { } __attribute__((noinline, naked)) void saveBreakpointRegs (struct Breakpoint *p) { + #ifndef __AVR_ATmega644P__ + #error wrong CPU -> check RAMEND, SFR + #endif asm volatile ( + ".equ SPL, 0x3d \n" + ".equ SPH, 0x3e \n" "push r28 \n" "push r29 \n" "movw r28, r24 \n" // bp -> Y @@ -100,8 +106,8 @@ namespace gdb { "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 + "in r30, SPL \n" // SPL -> ZL + "in r31, SPH \n" // SPH -> ZH "ldd r27, Z+1 \n" // save original r29 "std Y+29, r27 \n" "ldd r27, Z+2 \n" // save original r28 @@ -172,10 +178,6 @@ namespace gdb { do {} while(1); } - // void xputsStop () { - // xputsmem(gdb_StatusStop); - // } - // ATTENTION: static data not initialized when application not started !! // ---> xputs('hello'); not working!!! @@ -227,29 +229,98 @@ namespace gdb { // return crc; // } - void eraseFlash (uint16_t addressStart, uint16_t addressEnd) { - bootloader::putln(0); - for (uint16_t addr = addressStart; addr < 0xe000 && addr <= addressEnd; addr += SPM_PAGESIZE) { + void eraseFlash (uint16_t addressStart, int32_t length) { + #ifndef __AVR_ATmega644P__ + #error wrong CPU -> check end of application flash area + #else + // 0xffff - 0x2000 (bootloader size) + #define MEM_APP_END 0xdfff + #endif + #ifdef GDB_DEBUG_UART_FLASHERASE + bootloader::putln(GDB_DEBUG_UART); + printdbg(GDB_DEBUG_ID_FLASH_ERASE); + #endif + + for (uint16_t addr = addressStart; addr <= MEM_APP_END && length > 0; addr += SPM_PAGESIZE, length -= 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); + bootloader::printChar(GDB_DEBUG_UART, ' '); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(addr >> 8)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(addr)); #endif } + #ifdef GDB_DEBUG_UART_FLASHERASE + bootloader::printChar(GDB_DEBUG_UART, ' '); bootloader::printChar(GDB_DEBUG_UART, '@'); bootloader::putln(GDB_DEBUG_UART); #endif } void writeFlash (uint16_t *from, uint8_t size, uint16_t startAddress) { - for (uint8_t i = 0; i < size; i += 2) { - boot_page_fill(startAddress + i, *from++); + #ifndef __AVR_ATmega644P__ + #error wrong CPU -> check end of application flash area + #else + // 0xffff - 0x2000 (bootloader size) + #define MEM_APP_END 0xdfff + #endif + struct gdb::Gdb *pgdb = GDB_PTR; + if (size <= 0 || startAddress > MEM_APP_END) { + return; + } + + if (pgdb->status.flashPage < 0) { + pgdb->status.flashPage = startAddress / SPM_PAGESIZE; + #ifdef GDB_DEBUG_UART_FLASHWRITE + printdbg(GDB_DEBUG_ID_FLASH_WRITE); + #endif } + + uint16_t address = startAddress; + for (uint8_t i = 0; i < size && address <= MEM_APP_END; i += 2, address += 2) { + if ( (int16_t)(address / SPM_PAGESIZE) != pgdb->status.flashPage) { + boot_page_write(pgdb->status.flashPage * SPM_PAGESIZE); + #ifdef GDB_DEBUG_UART_FLASHWRITE + bootloader::printChar(GDB_DEBUG_UART, ' '); + bootloader::printChar(GDB_DEBUG_UART, 'W'); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)pgdb->status.flashPage); + #endif + boot_spm_busy_wait(); + pgdb->status.flashPage = address / SPM_PAGESIZE; + } + boot_page_fill(address, *from++); + } + #ifdef GDB_DEBUG_UART_FLASHWRITE + bootloader::printChar(GDB_DEBUG_UART, ' '); + bootloader::printChar(GDB_DEBUG_UART, 'F'); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(startAddress >> 8)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(startAddress)); + bootloader::printChar(GDB_DEBUG_UART, '-'); + bootloader::putUint8Hex(GDB_DEBUG_UART, size); + #endif + } + + void writeFlashDone () { + struct gdb::Gdb *pgdb = GDB_PTR; + if (pgdb->status.flashPage < 0) { + return; + } + #ifdef GDB_DEBUG_UART_FLASHWRITE + bootloader::printChar(GDB_DEBUG_UART, ' '); + bootloader::printChar(GDB_DEBUG_UART, 'W'); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)pgdb->status.flashPage); + #endif + boot_page_write(pgdb->status.flashPage * SPM_PAGESIZE); + boot_spm_busy_wait(); + boot_rww_enable(); + #ifdef GDB_DEBUG_UART_FLASHWRITE + bootloader::printChar(GDB_DEBUG_UART, ' '); + bootloader::printChar(GDB_DEBUG_UART, '@'); + bootloader::putln(GDB_DEBUG_UART); + #endif + pgdb->status.flashPage = -1; } void writeFlashOld (uint8_t *from, uint8_t size, uint16_t toPage) { @@ -270,8 +341,8 @@ namespace gdb { 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)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(toAddress >> 8)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(toAddress)); #endif eeprom_busy_wait(); boot_page_erase(toAddress); @@ -282,8 +353,8 @@ namespace gdb { 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)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(w >> 8)); + bootloader::putUint8Hex(GDB_DEBUG_UART, (uint8_t)(w)); #endif } boot_page_write(toAddress); @@ -311,7 +382,7 @@ namespace gdb { } else if (pgdb->ctrl.kill) { pgdb->ctrl.kill = 0; - #ifdef GDB_DEBUG_UART + #ifdef GDB_DEBUG_UART_KILL_APPLICATION printdbgln(GDB_DEBUG_ID_KILL_APPLICATION); #endif if (pgdb->status.isAppStarted) { @@ -329,7 +400,7 @@ namespace gdb { if (!pgdb->status.isStopped) { pgdb->ctrl.stop = 0; if (pgdb->status.isAppStarted) { - #ifdef GDB_DEBUG_UART + #ifdef GDB_DEBUG_UART_STOP_APPLICATION printdbgln(GDB_DEBUG_ID_STOP_APPLICATION); #endif } @@ -351,12 +422,14 @@ namespace gdb { 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); @@ -409,10 +482,6 @@ namespace gdb { // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-g-packet // Read general registers (used on gdb command load) xputc('$'); - bootloader::putUart0Byte('B'); - bootloader::putUart0Byte('-'); - bootloader::putUint8Hex(0, pgdb->status.isBreakpointValid); - bootloader::putln(0); if (pgdb->status.isBreakpointValid) { for (uint8_t i = 0; i < 32; i++) { xputUint8Hex(pgdb->breakpoint.regs[i]); @@ -581,22 +650,21 @@ namespace gdb { return; } else if (i == 11 && sum == 0x8e) { // vFlashErase: + // https://sourceware.org/gdb/current/onlinedocs/gdb.html/Packets.html#index-vFlashErase-packet + // Direct the stub to erase length bytes of flash starting at addr. i = 12; - uint32_t addressStart, addressEnd; + uint32_t addressStart, length; i += parseHex(p->buffer, i, &addressStart); i++; - i += parseHex(p->buffer, i, &addressEnd); + i += parseHex(p->buffer, i, &length); pgdb->ctrl.kill = 1; executeControl(); - eraseFlash((uint16_t)addressStart, (uint16_t)addressEnd); + eraseFlash((uint16_t)addressStart, (int32_t)length); xputsmem(gdb_OK); return; } else if (i == 9 && sum == 0xea) { // vFlashDone - asm volatile ( - "nop \n" - ); - boot_rww_enable(); + writeFlashDone(); xputsmem(gdb_OK); return; @@ -633,7 +701,7 @@ namespace gdb { xputsmem(gdb_vCont); return; - } else if (i == 6 && sum == 0xa8) { // vCont;c + } else if (i == 6 && sum == 0xa8 && p->buffer[1] == 'C') { // vCont;c (sum conflict with vFlashDone // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#index-vCont-packet // Resume the inferior, specifying different actions for each thread. pgdb->ctrl.proceed = 1; diff --git a/software/gdb-stub/src/gdb.h b/software/gdb-stub/src/gdb.h index dc30bc6..c8dc84e 100644 --- a/software/gdb-stub/src/gdb.h +++ b/software/gdb-stub/src/gdb.h @@ -88,9 +88,10 @@ namespace 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 eraseFlash (uint16_t addressStart, int32_t length) ATT_OPTIMIZE_GDB ATT_SECTION_GDB; void writeFlashOld (uint8_t *from, uint8_t size, uint16_t toPage) ATT_OPTIMIZE_GDB ATT_SECTION_GDB; void writeFlash (uint16_t *from, uint8_t size, uint16_t startAddress) ATT_OPTIMIZE_GDB ATT_SECTION_GDB; + void writeFlashDone () 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; -- 2.39.5