riscv: fix & refactor triggers add/delete

This commit is contained in:
Alexey Lapshin 2023-04-19 20:18:11 +08:00
parent 0e5098e4a6
commit d41d12fe7a
2 changed files with 51 additions and 33 deletions

View File

@ -152,6 +152,7 @@ extern "C" {
#define TDATA1_MATCH (1<<7)
#define TDATA1_MATCH_V (0xF) /*R/W,Address match type :0 : Exact byte match 1 : NAPOT range match */
#define TDATA1_MATCH_S (7)
#define TDATA1_HIT_S (20)
/* RISC-V CSR macros

View File

@ -132,49 +132,66 @@ FORCE_INLINE_ATTR void rv_utils_set_breakpoint(int bp_num, uint32_t bp_addr)
/* The code bellow sets breakpoint which will trigger `Breakpoint` exception
* instead transfering control to debugger. */
RV_WRITE_CSR(tselect, bp_num);
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MTE);
RV_SET_CSR(CSR_TDATA1, TDATA1_USER | TDATA1_MACHINE | TDATA1_EXECUTE);
RV_WRITE_CSR(CSR_TCONTROL, TCONTROL_MTE);
RV_WRITE_CSR(CSR_TDATA1, TDATA1_USER | TDATA1_MACHINE | TDATA1_EXECUTE);
RV_WRITE_CSR(tdata2, bp_addr);
}
FORCE_INLINE_ATTR void rv_utils_set_watchpoint(int wp_num,
uint32_t wp_addr,
size_t size,
bool on_read,
bool on_write)
{
RV_WRITE_CSR(tselect, wp_num);
RV_WRITE_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
RV_WRITE_CSR(CSR_TDATA1, TDATA1_USER |
TDATA1_MACHINE |
TDATA1_MATCH |
(on_read ? TDATA1_LOAD : 0) |
(on_write ? TDATA1_STORE : 0));
/* From RISC-V Debug Specification:
* NAPOT (Naturally Aligned Power-Of-Two):
* Matches when the top M bits of any compare value match the top M bits of tdata2.
* M is XLEN 1 minus the index of the least-significant bit containing 0 in tdata2.
*
* Note: Expectng that size is number power of 2
*
* Examples for understanding how to calculate NAPOT:
*
* nnnn...nnnn0 2-byte NAPOT range
* nnnn...nnn01 4-byte NAPOT range
* nnnn...nn011 8-byte NAPOT range
* nnnn...n0111 16-byte NAPOT range
* nnnn...01111 32-byte NAPOT range
* * where n are bits from original address
*/
const uint32_t half_size = size >> 1;
uint32_t napot = wp_addr;
napot &= ~half_size; /* set the least-significant bit with zero */
napot |= half_size - 1; /* fill all bits with ones after least-significant bit */
RV_WRITE_CSR(tdata2, napot);
}
FORCE_INLINE_ATTR void rv_utils_clear_breakpoint(int bp_num)
{
RV_WRITE_CSR(tselect, bp_num);
RV_CLEAR_CSR(CSR_TCONTROL, TCONTROL_MTE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER | TDATA1_MACHINE | TDATA1_EXECUTE);
}
FORCE_INLINE_ATTR void rv_utils_set_watchpoint(int wp_num,
uint32_t wp_addr,
size_t size,
bool on_read,
bool on_write)
{
RV_WRITE_CSR(tselect, wp_num);
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
RV_SET_CSR(CSR_TDATA1, TDATA1_USER | TDATA1_MACHINE);
RV_SET_CSR_FIELD(CSR_TDATA1, (long unsigned int) TDATA1_MATCH, 1);
// add 0 in napot encoding
uint32_t addr_napot;
addr_napot = ((uint32_t) wp_addr) | ((size >> 1) - 1);
if (on_read) {
RV_SET_CSR(CSR_TDATA1, TDATA1_LOAD);
}
if (on_write) {
RV_SET_CSR(CSR_TDATA1, TDATA1_STORE);
}
RV_WRITE_CSR(tdata2, addr_napot);
/* tdata1 is a WARL(write any read legal) register
* We can just write 0 to it
*/
RV_WRITE_CSR(CSR_TDATA1, 0);
}
FORCE_INLINE_ATTR void rv_utils_clear_watchpoint(int wp_num)
{
RV_WRITE_CSR(tselect, wp_num);
RV_CLEAR_CSR(CSR_TCONTROL, TCONTROL_MTE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER | TDATA1_MACHINE);
RV_CLEAR_CSR_FIELD(CSR_TDATA1, (long unsigned int) TDATA1_MATCH);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_MACHINE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_LOAD | TDATA1_STORE | TDATA1_EXECUTE);
/* riscv have the same registers for breakpoints and watchpoints */
rv_utils_clear_breakpoint(wp_num);
}
FORCE_INLINE_ATTR bool rv_utils_is_trigger_fired(int id)
{
RV_WRITE_CSR(tselect, id);
return (RV_READ_CSR(tdata1) >> TDATA1_HIT_S) & 1;
}
// ---------------------- Debugger -------------------------