static void init_code_breakpoints(stlink_t *sl) { memset(sl->q_buf, 0, 4); stlink_write_debug32(sl, CM3_REG_FP_CTRL, 0x03 /*KEY | ENABLE4*/); printf("KARL - should read back as 0x03, not 60 02 00 00\n"); stlink_read_debug32(sl, CM3_REG_FP_CTRL); for(int i = 0; i < CODE_BREAK_NUM; i++) { code_breaks[i].type = 0; stlink_write_debug32(sl, CM3_REG_FP_COMP0 + i * 4, 0); } }
static void init_data_watchpoints(stlink_t *sl) { DLOG("init watchpoints\n"); // set trcena in debug command to turn on dwt unit stlink_write_debug32(sl, 0xE000EDFC, stlink_read_debug32(sl, 0xE000EDFC) | (1<<24)); // make sure all watchpoints are cleared for(int i = 0; i < DATA_WATCH_NUM; i++) { data_watches[i].fun = WATCHDISABLED; stlink_write_debug32(sl, 0xe0001028 + i * 16, 0); } }
static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) { stm32_addr_t fpb_addr = addr & ~0x3; int type = addr & 0x2 ? CODE_BREAK_HIGH : CODE_BREAK_LOW; if(addr & 1) { fprintf(stderr, "update_code_breakpoint: unaligned address %08x\n", addr); return -1; } int id = -1; for(int i = 0; i < CODE_BREAK_NUM; i++) { if(fpb_addr == code_breaks[i].addr || (set && code_breaks[i].type == 0)) { id = i; break; } } if(id == -1) { if(set) return -1; // Free slot not found else return 0; // Breakpoint is already removed } struct code_hw_breakpoint* brk = &code_breaks[id]; brk->addr = fpb_addr; if(set) brk->type |= type; else brk->type &= ~type; if(brk->type == 0) { #ifdef DEBUG printf("clearing hw break %d\n", id); #endif stlink_write_debug32(sl, 0xe0002008 + id * 4, 0); } else { uint32_t mask = (brk->addr) | 1 | (brk->type << 30); #ifdef DEBUG printf("setting hw break %d at %08x (%d)\n", id, brk->addr, brk->type); printf("reg %08x \n", mask); #endif stlink_write_debug32(sl, 0xe0002008 + id * 4, mask); } return 0; }
static int add_data_watchpoint(stlink_t *sl, enum watchfun wf, stm32_addr_t addr, unsigned int len) { int i = 0; uint32_t mask; // computer mask // find a free watchpoint // configure mask = -1; i = len; while(i) { i >>= 1; mask++; } if((mask != (uint32_t)-1) && (mask < 16)) { for(i = 0; i < DATA_WATCH_NUM; i++) { // is this an empty slot ? if(data_watches[i].fun == WATCHDISABLED) { #ifdef DEBUG printf("insert watchpoint %d addr %x wf %u mask %u len %d\n", i, addr, wf, mask, len); #endif data_watches[i].fun = wf; data_watches[i].addr = addr; data_watches[i].mask = mask; // insert comparator address stlink_write_debug32(sl, 0xE0001020 + i * 16, addr); // insert mask stlink_write_debug32(sl, 0xE0001024 + i * 16, mask); // insert function stlink_write_debug32(sl, 0xE0001028 + i * 16, wf); // just to make sure the matched bit is clear ! stlink_read_debug32(sl, 0xE0001028 + i * 16); return 0; } } } #ifdef DEBUG printf("failure: add watchpoints addr %x wf %u len %u\n", addr, wf, len); #endif return -1; }
static int delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr) { int i; for(i = 0 ; i < DATA_WATCH_NUM; i++) { if((data_watches[i].addr == addr) && (data_watches[i].fun != WATCHDISABLED)) { DLOG("delete watchpoint %d addr %x\n", i, addr); data_watches[i].fun = WATCHDISABLED; stlink_write_debug32(sl, 0xe0001028 + i * 16, 0); return 0; } } DLOG("failure: delete watchpoint addr %x\n", addr); return -1; }