This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new c858f3cc44c arch/tricore: Add hardware debug breakpoint and watchpoint 
support.
c858f3cc44c is described below

commit c858f3cc44c4a051a4b4319d4c22a1e3cc92967b
Author: zhangyu117 <[email protected]>
AuthorDate: Tue Sep 30 15:54:47 2025 +0800

    arch/tricore: Add hardware debug breakpoint and watchpoint support.
    
    Implement hardware breakpoint and watchpoint support for TriCore
    architecture using the Trigger Event (TREVT) registers. This enables
    the standard NuttX debugpoint API (up_debugpoint_add/remove) on TriCore
    processors, supporting read/write/execute watchpoints and breakpoints
    via the on-chip debug unit.
    
    Signed-off-by: zhangyu117 <[email protected]>
---
 arch/tricore/Kconfig                         |   2 +
 arch/tricore/src/common/CMakeLists.txt       |   4 +
 arch/tricore/src/common/Make.defs            |   4 +
 arch/tricore/src/common/tricore_hwdebug.c    | 412 +++++++++++++++++++++++++++
 arch/tricore/src/common/tricore_initialize.c |   4 +
 arch/tricore/src/common/tricore_internal.h   |   4 +
 6 files changed, 430 insertions(+)

diff --git a/arch/tricore/Kconfig b/arch/tricore/Kconfig
index 2feb737ec74..0974cc18fe3 100644
--- a/arch/tricore/Kconfig
+++ b/arch/tricore/Kconfig
@@ -24,6 +24,7 @@ endchoice # Tricore Toolchain Selection
 
 config ARCH_TC1V6
        bool
+       select ARCH_HAVE_DEBUG
        select ARCH_HAVE_MPU
        select ARCH_HAVE_IRQTRIGGER
        select ARCH_HAVE_PERF_EVENTS
@@ -38,6 +39,7 @@ config ARCH_TC1V6
 config ARCH_TC1V8
        bool
        select ARCH_DCACHE
+       select ARCH_HAVE_DEBUG
        select ARCH_ICACHE
        select ARCH_HAVE_MPU
        select ARCH_HAVE_IRQTRIGGER
diff --git a/arch/tricore/src/common/CMakeLists.txt 
b/arch/tricore/src/common/CMakeLists.txt
index fb5caa6fd75..1c51d7ef35b 100644
--- a/arch/tricore/src/common/CMakeLists.txt
+++ b/arch/tricore/src/common/CMakeLists.txt
@@ -65,6 +65,10 @@ if(CONFIG_ARCH_HAVE_FPU)
   list(APPEND SRCS tricore_fpu.c)
 endif()
 
+if(CONFIG_ARCH_HAVE_DEBUG)
+  list(APPEND SRCS tricore_hwdebug.c)
+endif()
+
 set(IFXFLAGS -DIFX_CFG_EXTEND_TRAP_HOOKS -DIFX_USE_SW_MANAGED_INT)
 
 target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/tricore/src/common/Make.defs 
b/arch/tricore/src/common/Make.defs
index 8c1379e3596..a73d35c5765 100644
--- a/arch/tricore/src/common/Make.defs
+++ b/arch/tricore/src/common/Make.defs
@@ -66,5 +66,9 @@ ifeq ($(CONFIG_ARCH_HAVE_FPU),y)
   CMN_CSRCS += tricore_fpu.c
 endif
 
+ifeq ($(CONFIG_ARCH_HAVE_DEBUG),y)
+  CMN_CSRCS += tricore_hwdebug.c
+endif
+
 CFLAGS += -DIFX_CFG_EXTEND_TRAP_HOOKS
 CFLAGS += -DIFX_USE_SW_MANAGED_INT
diff --git a/arch/tricore/src/common/tricore_hwdebug.c 
b/arch/tricore/src/common/tricore_hwdebug.c
new file mode 100644
index 00000000000..16b0a93a7d6
--- /dev/null
+++ b/arch/tricore/src/common/tricore_hwdebug.c
@@ -0,0 +1,412 @@
+/****************************************************************************
+ * arch/tricore/src/common/tricore_hwdebug.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+
+#include <IfxCpu_bf.h>
+#include <IfxCbs_reg.h>
+
+#include "tricore_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Watchpoint and breakpoint share a set of trigger events */
+
+#define TREVT_DEBUG_NUM               8
+#define TREVT_DEBUG_REGS              4
+#define TREVT_DEBUG_MATCH_TRAPMODE    0x03
+#define TREVT_DEBUG_EVTSRC_BASE       0x10
+#ifdef CONFIG_ARCH_TC1V8
+#  define IFX_CPU_TR_EVT_BBM_OFF      IFX_CPU_TREVT_BBM_OFF
+#  define IFX_CPU_TR_EVT_TYP_OFF      IFX_CPU_TREVT_TYP_OFF
+#  define IFX_CPU_TR_EVT_AST_OFF      IFX_CPU_TREVT_AST_OFF
+#  define IFX_CPU_TR_EVT_ALD_OFF      IFX_CPU_TREVT_ALD_OFF
+#endif
+
+#define TREVT_DEBUG_BBM               (1 << IFX_CPU_TR_EVT_BBM_OFF)
+#define TREVT_DEBUG_WP                (0 << IFX_CPU_TR_EVT_TYP_OFF)
+#define TREVT_DEBUG_BP                (1 << IFX_CPU_TR_EVT_TYP_OFF)
+#define TREVT_DEBUG_WP_AST            (1 << IFX_CPU_TR_EVT_AST_OFF)
+#define TREVT_DEBUG_WP_ALD            (1 << IFX_CPU_TR_EVT_ALD_OFF)
+#define TREVT_DEBUG_WP_ASTLD          (TREVT_DEBUG_WP_AST | TREVT_DEBUG_WP_ALD)
+
+/* Register TREVT[2:0] have difference between tc3xx and tc4xx */
+
+#ifdef CONFIG_ARCH_TC1V6
+#  define TREVT_CFG_REG_EN_MASK       IFX_CPU_TR_EVT_EVTA_MSK
+#  define TREVT_CFG_REG_EN_VALUE      TREVT_DEBUG_MATCH_TRAPMODE
+#elif defined(CONFIG_ARCH_TC1V8)
+#  define TREVT_CFG_REG_EN_MASK       IFX_CPU_TREVT_EN_MSK
+#  define TREVT_CFG_REG_EN_VALUE      0x01
+#endif
+
+#define TREVT_SET_CASE(reg, n, val) \
+  case n: __mtcr(CPU_TR##n##_##reg, val); break;
+#define TREVT_GET_CASE(reg, n, val) \
+  case n: val = __mfcr(CPU_TR##n##_##reg); break;
+
+#define TREVT_GET_CFG_REG(n)          TREVT_GET(EVT, n)
+#define TREVT_SET_CFG_REG(n, val)     TREVT_SET(EVT, n, val)
+#define TREVT_GET_ADDR_REG(n)         TREVT_GET(ADR, n)
+#define TREVT_SET_ADDR_REG(n, val)    TREVT_SET(ADR, n, val)
+
+#define TREVT_SET(reg, n, val)                    \
+  ({                                              \
+    switch (n)                                    \
+    {                                             \
+      TREVT_SET_CASE(reg, 0, val)                 \
+      TREVT_SET_CASE(reg, 1, val)                 \
+      TREVT_SET_CASE(reg, 2, val)                 \
+      TREVT_SET_CASE(reg, 3, val)                 \
+      TREVT_SET_CASE(reg, 4, val)                 \
+      TREVT_SET_CASE(reg, 5, val)                 \
+      TREVT_SET_CASE(reg, 6, val)                 \
+      TREVT_SET_CASE(reg, 7, val)                 \
+    }                                             \
+  })
+
+#define TREVT_GET(reg, n)                         \
+  ({                                              \
+    uint32_t _val = 0;                            \
+    switch (n)                                    \
+    {                                             \
+      TREVT_GET_CASE(reg, 0, _val)                \
+      TREVT_GET_CASE(reg, 1, _val)                \
+      TREVT_GET_CASE(reg, 2, _val)                \
+      TREVT_GET_CASE(reg, 3, _val)                \
+      TREVT_GET_CASE(reg, 4, _val)                \
+      TREVT_GET_CASE(reg, 5, _val)                \
+      TREVT_GET_CASE(reg, 6, _val)                \
+      TREVT_GET_CASE(reg, 7, _val)                \
+    }                                             \
+   _val;                                          \
+  })
+
+/****************************************************************************
+ * Private Type
+ ****************************************************************************/
+
+struct tricore_debugpoint_s
+{
+  int type;
+  void *addr;
+  size_t size;
+  debug_callback_t callback;
+  void *arg;
+};
+
+struct tricore_debug_s
+{
+  uintptr_t aligned_data(XCPTCONTEXT_SIZE) dcx[TREVT_DEBUG_REGS];
+  struct tricore_debugpoint_s dp[TREVT_DEBUG_NUM];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct tricore_debug_s g_trevt_debug;
+
+/****************************************************************************
+ * Private Function
+ ****************************************************************************/
+
+static uint32_t tricore_convert_type(int type)
+{
+  switch (type)
+    {
+      case DEBUGPOINT_WATCHPOINT_RO:
+        return TREVT_DEBUG_WP | TREVT_DEBUG_WP_ALD;
+
+      case DEBUGPOINT_WATCHPOINT_WO:
+        return TREVT_DEBUG_WP | TREVT_DEBUG_WP_AST;
+
+      case DEBUGPOINT_WATCHPOINT_RW:
+        return TREVT_DEBUG_WP | TREVT_DEBUG_WP_ASTLD;
+
+      case DEBUGPOINT_BREAKPOINT:
+      case DEBUGPOINT_STEPPOINT:
+      default:
+        return TREVT_DEBUG_BP;
+    }
+}
+
+/****************************************************************************
+ * Name: tricore_trevt_add
+ *
+ * Description:
+ *   Add a watchpoint on the address.
+ *
+ * Input Parameters:
+ *  type - The type of the watchpoint
+ *  addr - The address to be watched
+ *  size - The size of the address to be watched
+ *
+ * Returned Value:
+ *  Index in wprs array on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int tricore_trevt_add(int type, uint32_t addr, size_t size)
+{
+  int i;
+
+  for (i = 0; i < TREVT_DEBUG_NUM; i++)
+    {
+      if (!(TREVT_GET_CFG_REG(i) & TREVT_CFG_REG_EN_MASK))
+        {
+          TREVT_SET_ADDR_REG(i, addr);
+          TREVT_SET_CFG_REG(i, tricore_convert_type(type) |
+                               TREVT_CFG_REG_EN_VALUE);
+          return i;
+        }
+    }
+
+  return -ENOSPC;
+}
+
+/****************************************************************************
+ * Name: tricore_trevt_remove
+ *
+ * Description:
+ *   Remove a trevt on the address.
+ *
+ * Input Parameters:
+ *   addr - The address to be debugged.
+ *
+ * Returned Value:
+ *  Index of trevt on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int tricore_trevt_remove(uint32_t addr)
+{
+  int i;
+
+  for (i = 0; i < TREVT_DEBUG_NUM; i++)
+    {
+      if (TREVT_GET_ADDR_REG(i) == addr)
+        {
+          TREVT_SET_CFG_REG(i, 0);
+          TREVT_SET_ADDR_REG(i, 0);
+          return i;
+        }
+    }
+
+  return -ENOENT;
+}
+
+/****************************************************************************
+ * Name: tricore_dbgmonitor
+ *
+ * Description:
+ *   This is Debug Monitor exception handler.  This function is entered when
+ *   the processor enters debug mode.  The debug monitor handler will handle
+ *   debug events, and resume execution.
+ *
+ ****************************************************************************/
+
+static void tricore_dbgmonitor(void)
+{
+  __asm__ __volatile__ (
+    "svlcx\n\t"
+    "call  tricore_trevt_match\n\t"
+    "rslcx\n\t"
+    "rfm\n\t"
+  );
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tricore_trevt_match
+ ****************************************************************************/
+
+void tricore_trevt_match(void)
+{
+  struct tricore_debugpoint_s *dp;
+  int evtsrc;
+
+  dp = g_trevt_debug.dp;
+
+  evtsrc = ((__mfcr(CPU_DBGSR) >> IFX_CPU_DBGSR_EVTSRC_OFF) &
+            IFX_CPU_DBGSR_EVTSRC_MSK) - TREVT_DEBUG_EVTSRC_BASE;
+
+  dp[evtsrc].callback(dp[evtsrc].type, dp[evtsrc].addr,
+                      dp[evtsrc].size, dp[evtsrc].arg);
+}
+
+/****************************************************************************
+ * Name: tricore_init_dbgmonitor
+ *
+ * Description:
+ *   This function init the debug monitor exception.
+ *
+ ****************************************************************************/
+
+int tricore_init_dbgmonitor(void)
+{
+  Ifx_CPU_DBGTCR dbgtcr;
+
+  dbgtcr.B.DTA = 0;
+
+  if (!(__mfcr(CPU_DBGSR) & 0x1))
+    {
+      CBS_OEC.U = 0xa1;
+      CBS_OEC.U = 0x5e;
+      CBS_OEC.U = 0xa1;
+      CBS_OEC.U = 0x5e;
+    }
+
+#ifdef CONFIG_ARCH_TC1V8
+  Ifx_CPU_DBGCFG dbgcfg;
+  Ifx_CPU_DBGACT dbgact;
+
+  dbgcfg.B.EN = 1;
+  dbgcfg.B.TC = 0;
+  dbgcfg.B.TCP = 0;
+  dbgact.B.EVTA = TREVT_DEBUG_MATCH_TRAPMODE;
+
+  /* Set debug configuration register */
+
+  __mtcr(CPU_DBGCFG, dbgcfg.U);
+
+  /* Set debug action configuration register */
+
+  __mtcr(CPU_DBGACT, dbgact.U);
+#endif
+
+  /* Set debug trap control register */
+
+  __mtcr(CPU_DBGTCR, dbgtcr.U);
+
+  /* Set trevt trap handler */
+
+  __mtcr(CPU_DMS, (uintptr_t)tricore_dbgmonitor);
+
+  /* Set dcx register */
+
+  __mtcr(CPU_DCX, (uintptr_t)g_trevt_debug.dcx);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_debugpoint_add
+ *
+ * Description:
+ *   Add a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *   callback - The callback function when debugpoint triggered.
+ *              if NULL, the debugpoint will be removed.
+ *   arg      - The argument of callback function.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_add(int type, void *addr, size_t size,
+                      debug_callback_t callback, void *arg)
+{
+  struct tricore_debugpoint_s *dp;
+  int ret;
+
+  ret = tricore_trevt_add(type, (uint32_t)addr, size);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  dp = g_trevt_debug.dp;
+  dp[ret].type = type;
+  dp[ret].addr = addr;
+  dp[ret].size = size;
+  dp[ret].callback = callback;
+  dp[ret].arg = arg;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_debugpoint_remove
+ *
+ * Description:
+ *   Remove a debugpoint.
+ *
+ * Input Parameters:
+ *   type     - The debugpoint type. optional value:
+ *              DEBUGPOINT_WATCHPOINT_RO - Read only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_WO - Write only watchpoint.
+ *              DEBUGPOINT_WATCHPOINT_RW - Read and write watchpoint.
+ *              DEBUGPOINT_BREAKPOINT    - Breakpoint.
+ *              DEBUGPOINT_STEPPOINT     - Single step.
+ *   addr     - The address to be debugged.
+ *   size     - The watchpoint size. only for watchpoint.
+ *
+ * Returned Value:
+ *  Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int up_debugpoint_remove(int type, void *addr, size_t size)
+{
+  struct tricore_debugpoint_s *dp;
+  int ret;
+
+  ret = tricore_trevt_remove((uintptr_t)addr);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  dp = g_trevt_debug.dp;
+  dp[ret].type = 0;
+  dp[ret].addr = 0;
+  dp[ret].size = 0;
+  dp[ret].callback = NULL;
+  dp[ret].arg = NULL;
+
+  return OK;
+}
diff --git a/arch/tricore/src/common/tricore_initialize.c 
b/arch/tricore/src/common/tricore_initialize.c
index 8420b934521..86880f2c3a2 100644
--- a/arch/tricore/src/common/tricore_initialize.c
+++ b/arch/tricore/src/common/tricore_initialize.c
@@ -81,4 +81,8 @@ void up_initialize(void)
 #ifdef USE_SERIALDRIVER
   tricore_serialinit();
 #endif
+
+#ifdef CONFIG_ARCH_HAVE_DEBUG
+  tricore_init_dbgmonitor();
+#endif
 }
diff --git a/arch/tricore/src/common/tricore_internal.h 
b/arch/tricore/src/common/tricore_internal.h
index 8c583d2ad0f..ac8aab260dd 100644
--- a/arch/tricore/src/common/tricore_internal.h
+++ b/arch/tricore/src/common/tricore_internal.h
@@ -212,6 +212,10 @@ void tricore_earlyserialinit(void);
 void tricore_fpuinit(void);
 #endif
 
+#ifdef CONFIG_ARCH_HAVE_DEBUG
+int tricore_init_dbgmonitor(void);
+#endif
+
 /* System Timer *************************************************************/
 
 struct oneshot_lowerhalf_s *

Reply via email to