#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
}
__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
"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
do {} while(1);
}
- // void xputsStop () {
- // xputsmem(gdb_StatusStop);
- // }
-
// ATTENTION: static data not initialized when application not started !!
// ---> xputs('hello'); not working!!!
// 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) {
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);
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);
} 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) {
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
}
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);
// 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]);
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;
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;