diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index b1a714d48..90caf406f 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -248,7 +248,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet, if (strcmp(packet_stttrr, "vCont;c") == 0) { target_call_event_callbacks(target, TARGET_EVENT_GDB_START); target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); - riscv_resume_all_harts(target); + riscv_openocd_resume(target, 1, 0, 0, 0); target->state = TARGET_RUNNING; gdb_set_frontend_state_running(connection); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6b03fd966..e136c98be 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2039,8 +2039,9 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: - case CSR_DCSR_CAUSE_TRIGGER: return RISCV_HALT_BREAKPOINT; + case CSR_DCSR_CAUSE_TRIGGER: + return RISCV_HALT_TRIGGER; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; case CSR_DCSR_CAUSE_DEBUGINT: diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index f8a273958..03fa46ba9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -640,6 +640,7 @@ static int old_or_new_riscv_step( int handle_breakpoints ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_step(target, current, address, handle_breakpoints); else @@ -728,6 +729,7 @@ static int old_or_new_riscv_resume( int debug_execution ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); else @@ -1027,6 +1029,9 @@ int riscv_openocd_poll(struct target *target) case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; + case RISCV_HALT_TRIGGER: + target->debug_reason = DBG_REASON_WATCHPOINT; + break; case RISCV_HALT_INTERRUPT: target->debug_reason = DBG_REASON_DBGRQ; break; @@ -1077,13 +1082,53 @@ int riscv_openocd_resume( int current, target_addr_t address, int handle_breakpoints, - int debug_execution -) { - LOG_DEBUG("resuming all harts"); + int debug_execution) +{ + LOG_DEBUG("debug_reason=%d", target->debug_reason); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + struct watchpoint *watchpoint = target->watchpoints; + bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; + + int i = 0; + int result = ERROR_OK; + while (watchpoint && result == ERROR_OK) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); + trigger_temporarily_cleared[i] = watchpoint->set; + if (watchpoint->set) { + result = riscv_remove_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result == ERROR_OK) { + result = riscv_step_rtos_hart(target); + } + + watchpoint = target->watchpoints; + i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); + if (trigger_temporarily_cleared[i]) { + if (result == ERROR_OK) + result = riscv_add_watchpoint(target, watchpoint); + else + riscv_add_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result != ERROR_OK) + return result; + } + int out = riscv_resume_all_harts(target); if (out != ERROR_OK) { LOG_ERROR("unable to resume all harts"); @@ -1601,18 +1646,6 @@ enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) return r->halt_reason(target); } -int riscv_count_triggers(struct target *target) -{ - return riscv_count_triggers_of_hart(target, riscv_current_hartid(target)); -} - -int riscv_count_triggers_of_hart(struct target *target, int hartid) -{ - RISCV_INFO(r); - assert(hartid < riscv_count_harts(target)); - return r->trigger_count[hartid]; -} - size_t riscv_debug_buffer_size(struct target *target) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 5d3a21257..478731dd6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -30,6 +30,7 @@ enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, + RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN }; @@ -216,11 +217,6 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, bool riscv_is_halted(struct target *target); enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); -/* Returns the number of triggers availiable to either the current hart or to - * the given hart. */ -int riscv_count_triggers(struct target *target); -int riscv_count_triggers_of_hart(struct target *target, int hartid); - /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target);