* 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
****************************************************************************/
#define TREVT_DEBUG_NUM 8
#define TREVT_DEBUG_REGS 4
#define TREVT_DEBUG_MATCH_TRAPMODE 0x03
#define TREVT_DEBUG_EVTSRC_BASE 0x10
#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)
#ifdef CONFIG_ARCH_CHIP_TC3XX
#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_CHIP_TC4XX)
#define TREVT_CFG_REG_EN_MASK IFX_CPU_TR_EVT_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(TC_CONTEXT_SIZE) dcx[TREVT_DEBUG_REGS];
struct tricore_debugpoint_s dp[TREVT_DEBUG_NUM];
};
* Private Data
****************************************************************************/
static DEFINE_PER_CPU(struct tricore_debug_s, g_trevt_debugs);
#define g_trevt_debug this_cpu_var(g_trevt_debugs)
* 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
*
* Notes:
* The size of the watchpoint is determined by the hardware.
*
****************************************************************************/
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_CHIP_TC4XX
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;
__mtcr(CPU_DBGCFG, dbgcfg.U);
__mtcr(CPU_DBGACT, dbgact.U);
#endif
__mtcr(CPU_DBGTCR, dbgtcr.U);
__mtcr(CPU_DMS, (uintptr_t)tricore_dbgmonitor);
__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;
}