|
@@ -14,6 +14,7 @@
|
|
|
#include "soc/assist_debug_reg.h"
|
|
#include "soc/assist_debug_reg.h"
|
|
|
#include "esp_attr.h"
|
|
#include "esp_attr.h"
|
|
|
#include "riscv/csr.h"
|
|
#include "riscv/csr.h"
|
|
|
|
|
+#include "riscv/semihosting.h"
|
|
|
|
|
|
|
|
/*performance counter*/
|
|
/*performance counter*/
|
|
|
#define CSR_PCER_MACHINE 0x7e0
|
|
#define CSR_PCER_MACHINE 0x7e0
|
|
@@ -71,8 +72,29 @@ static inline void cpu_ll_init_hwloop(void)
|
|
|
// Nothing needed here for ESP32-C3
|
|
// Nothing needed here for ESP32-C3
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
|
|
|
|
+{
|
|
|
|
|
+ return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
|
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (cpu_ll_is_debugger_attached()) {
|
|
|
|
|
+ /* If we want to set breakpoint which when hit transfers control to debugger
|
|
|
|
|
+ * we need to set `action` in `mcontrol` to 1 (Enter Debug Mode).
|
|
|
|
|
+ * That `action` value is supported only when `dmode` of `tdata1` is set.
|
|
|
|
|
+ * But `dmode` can be modified by debugger only (from Debug Mode).
|
|
|
|
|
+ *
|
|
|
|
|
+ * So when debugger is connected we use special syscall to ask it to set breakpoint for us.
|
|
|
|
|
+ */
|
|
|
|
|
+ long args[] = {true, id, (long)pc};
|
|
|
|
|
+ int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
|
|
|
|
+ if (ret == 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ /* The code bellow sets breakpoint which will trigger `Breakpoint` exception
|
|
|
|
|
+ * instead transfering control to debugger. */
|
|
|
RV_WRITE_CSR(tselect,id);
|
|
RV_WRITE_CSR(tselect,id);
|
|
|
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
|
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
|
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
|
@@ -82,6 +104,14 @@ static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
|
|
|
|
|
|
|
static inline void cpu_ll_clear_breakpoint(int id)
|
|
static inline void cpu_ll_clear_breakpoint(int id)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (cpu_ll_is_debugger_attached()) {
|
|
|
|
|
+ /* see description in cpu_ll_set_breakpoint() */
|
|
|
|
|
+ long args[] = {false, id};
|
|
|
|
|
+ int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
|
|
|
|
+ if (ret == 0){
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
RV_WRITE_CSR(tselect,id);
|
|
RV_WRITE_CSR(tselect,id);
|
|
|
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
|
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
|
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
|
@@ -105,6 +135,17 @@ static inline void cpu_ll_set_watchpoint(int id,
|
|
|
bool on_write)
|
|
bool on_write)
|
|
|
{
|
|
{
|
|
|
uint32_t addr_napot;
|
|
uint32_t addr_napot;
|
|
|
|
|
+
|
|
|
|
|
+ if (cpu_ll_is_debugger_attached()) {
|
|
|
|
|
+ /* see description in cpu_ll_set_breakpoint() */
|
|
|
|
|
+ long args[] = {true, id, (long)addr, (long)size,
|
|
|
|
|
+ (long)((on_read ? ESP_SEMIHOSTING_WP_FLG_RD : 0) | (on_write ? ESP_SEMIHOSTING_WP_FLG_WR : 0))};
|
|
|
|
|
+ int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
|
|
|
|
+ if (ret == 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
RV_WRITE_CSR(tselect,id);
|
|
RV_WRITE_CSR(tselect,id);
|
|
|
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
|
|
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
|
|
|
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
|
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
|
@@ -123,6 +164,14 @@ static inline void cpu_ll_set_watchpoint(int id,
|
|
|
|
|
|
|
|
static inline void cpu_ll_clear_watchpoint(int id)
|
|
static inline void cpu_ll_clear_watchpoint(int id)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (cpu_ll_is_debugger_attached()) {
|
|
|
|
|
+ /* see description in cpu_ll_set_breakpoint() */
|
|
|
|
|
+ long args[] = {false, id};
|
|
|
|
|
+ int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
|
|
|
|
+ if (ret == 0){
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
RV_WRITE_CSR(tselect,id);
|
|
RV_WRITE_CSR(tselect,id);
|
|
|
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
|
|
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
|
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
|
@@ -132,11 +181,6 @@ static inline void cpu_ll_clear_watchpoint(int id)
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
|
|
|
|
-{
|
|
|
|
|
- return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
static inline void cpu_ll_break(void)
|
|
static inline void cpu_ll_break(void)
|
|
|
{
|
|
{
|
|
|
asm volatile("ebreak\n");
|
|
asm volatile("ebreak\n");
|