Merge pull request #800 from en-sc/en-sc/try-all-trigs-in-maybe-add-trig

Try all triggers in maybe_add_trigger_t*
This commit is contained in:
Tim Newsome 2023-03-16 16:58:12 -07:00 committed by GitHub
commit 3387015af0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 247 additions and 187 deletions

View File

@ -28,6 +28,7 @@
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
#define field_value(mask, val) set_field((riscv_reg_t) 0, mask, val)
/*** JTAG registers. ***/
@ -468,36 +469,37 @@ static void trigger_from_breakpoint(struct trigger *trigger,
trigger->unique_id = breakpoint->unique_id;
}
static bool can_use_napot_match(struct trigger *trigger, riscv_reg_t *tdata2)
static bool can_use_napot_match(struct trigger *trigger)
{
riscv_reg_t addr = trigger->address;
riscv_reg_t size = trigger->length;
bool sizePowerOf2 = (size & (size - 1)) == 0;
bool addrAligned = (addr & (size - 1)) == 0;
if (size > 1 && sizePowerOf2 && addrAligned) {
if (tdata2)
*tdata2 = addr | ((size - 1) >> 1);
return true;
}
return false;
return size > 1 && sizePowerOf2 && addrAligned;
}
static int find_trigger(struct target *target, int type, bool chained, unsigned int *idx)
/* Find the next free trigger of the given type, without talking to the target. */
static int find_next_free_trigger(struct target *target, int type, bool chained,
unsigned int *idx)
{
assert(idx);
RISCV_INFO(r);
unsigned int num_found = 0;
unsigned int num_required = chained ? 2 : 1;
for (unsigned i = 0; i < r->trigger_count; i++) {
for (unsigned i = *idx; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == -1) {
if (r->trigger_tinfo[i] & (1 << type)) {
num_found++;
bool done = (num_required == num_found);
if (done) {
if (num_required == num_found) {
/* Found num_required consecutive free triggers - success, done. */
if (idx)
*idx = i - (num_required - 1);
*idx = i - (num_required - 1);
LOG_TARGET_DEBUG(target,
"%d trigger(s) of type %d found on index %u, "
"chained == %s",
num_required, type, *idx,
chained ? "true" : "false");
return ERROR_OK;
}
/* Found a trigger but need more consecutive ones */
@ -574,8 +576,8 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
const uint32_t bpcontrol_bpmatch = 0xf << 7;
const uint32_t bpcontrol_bpaction = 0xff << 11;
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx);
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx);
if (ret != ERROR_OK)
return ret;
@ -604,90 +606,227 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
return ERROR_OK;
}
static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger)
{
int ret;
riscv_reg_t tdata1, tdata2;
struct trigger_request_info {
riscv_reg_t tdata1;
riscv_reg_t tdata2;
riscv_reg_t tdata1_ignore_mask;
};
static int try_setup_single_match_trigger(struct target *target,
struct trigger *trigger, struct trigger_request_info trig_info)
{
int trigger_type =
get_field(trig_info.tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target)));
int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
RISCV_INFO(r);
tdata1 = 0;
tdata1 = set_field(tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target)), 2);
tdata1 = set_field(tdata1, CSR_MCONTROL_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, CSR_MCONTROL_M, 1);
tdata1 = set_field(tdata1, CSR_MCONTROL_S, !!(r->misa & (1 << ('S' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL_U, !!(r->misa & (1 << ('U' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL_EXECUTE, trigger->execute);
tdata1 = set_field(tdata1, CSR_MCONTROL_LOAD, trigger->read);
tdata1 = set_field(tdata1, CSR_MCONTROL_STORE, trigger->write);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_ANY & 3);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_ANY >> 2) & 3);
if (trigger->execute || trigger->length == 1)
goto MATCH_EQUAL;
if (!can_use_napot_match(trigger, &tdata2))
goto MATCH_GE_LT;
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_NAPOT);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
ret = set_trigger(target, idx, tdata1, tdata2, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
return ret;
/* Find the first trigger, supporting required tdata1 value */
for (unsigned int idx = 0;
find_next_free_trigger(target, trigger_type, false, &idx) == ERROR_OK;
++idx) {
ret = set_trigger(target, idx, trig_info.tdata1, trig_info.tdata2,
trig_info.tdata1_ignore_mask);
if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
}
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
return ret;
}
MATCH_GE_LT:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, true, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_ENABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
tdata2 = trigger->address + trigger->length;
ret = set_trigger(target, idx + 1, tdata1, tdata2, 0);
if (ret != ERROR_OK) {
/* Undo the setting of the previous trigger*/
set_trigger(target, idx, 0, 0, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
r->trigger_unique_id[idx + 1] = trigger->unique_id;
return ERROR_OK;
static int try_setup_chained_match_triggers(struct target *target,
struct trigger *trigger, struct trigger_request_info t1,
struct trigger_request_info t2)
{
int trigger_type =
get_field(t1.tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target)));
int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
RISCV_INFO(r);
MATCH_EQUAL:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL);
if (trigger->length == 1) {
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_8BIT & 3);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_8BIT >> 2) & 3);
/* Find the first 2 consecutive triggers, supporting required tdata1 values */
for (unsigned int idx = 0;
find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK;
++idx) {
ret = set_trigger(target, idx, t1.tdata1, t1.tdata2,
t1.tdata1_ignore_mask);
if (ret != ERROR_OK)
continue;
ret = set_trigger(target, idx + 1, t2.tdata1, t2.tdata2,
t2.tdata1_ignore_mask);
if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = trigger->unique_id;
r->trigger_unique_id[idx + 1] = trigger->unique_id;
return ERROR_OK;
}
/* Undo the setting of the previous trigger */
int ret_undo = set_trigger(target, idx, 0, 0, 0);
if (ret_undo != ERROR_OK)
return ret_undo;
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
return ret;
}
struct match_triggers_tdata1_fields {
riscv_reg_t common;
struct {
riscv_reg_t any;
riscv_reg_t s8bit;
} size;
struct {
riscv_reg_t enable;
riscv_reg_t disable;
} chain;
struct {
riscv_reg_t napot;
riscv_reg_t lt;
riscv_reg_t ge;
riscv_reg_t eq;
} match;
riscv_reg_t tdata1_ignore_mask;
};
static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(
struct target *target, struct trigger *trigger)
{
RISCV_INFO(r);
struct match_triggers_tdata1_fields result = {
.common =
field_value(CSR_MCONTROL_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_MCONTROL) |
field_value(CSR_MCONTROL_DMODE(riscv_xlen(target)), 1) |
field_value(CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE) |
field_value(CSR_MCONTROL_M, 1) |
field_value(CSR_MCONTROL_S, !!(r->misa & BIT('S' - 'A'))) |
field_value(CSR_MCONTROL_U, !!(r->misa & BIT('U' - 'A'))) |
field_value(CSR_MCONTROL_EXECUTE, trigger->execute) |
field_value(CSR_MCONTROL_LOAD, trigger->read) |
field_value(CSR_MCONTROL_STORE, trigger->write),
.size = {
.any =
field_value(CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_ANY & 3) |
field_value(CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_ANY >> 2) & 3),
.s8bit =
field_value(CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_8BIT & 3) |
field_value(CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_8BIT >> 2) & 3)
},
.chain = {
.enable = field_value(CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_ENABLED),
.disable = field_value(CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED)
},
.match = {
.napot = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_NAPOT),
.lt = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT),
.ge = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE),
.eq = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL)
},
.tdata1_ignore_mask = CSR_MCONTROL_MASKMAX(riscv_xlen(target))
};
return result;
}
static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6(
struct target *target, struct trigger *trigger)
{
RISCV_INFO(r);
struct match_triggers_tdata1_fields result = {
.common =
field_value(CSR_MCONTROL6_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_MCONTROL6) |
field_value(CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1) |
field_value(CSR_MCONTROL6_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE) |
field_value(CSR_MCONTROL6_M, 1) |
field_value(CSR_MCONTROL6_S, !!(r->misa & BIT('S' - 'A'))) |
field_value(CSR_MCONTROL6_U, !!(r->misa & BIT('U' - 'A'))) |
field_value(CSR_MCONTROL6_EXECUTE, trigger->execute) |
field_value(CSR_MCONTROL6_LOAD, trigger->read) |
field_value(CSR_MCONTROL6_STORE, trigger->write),
.size = {
.any = field_value(CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_ANY),
.s8bit = field_value(CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_8BIT)
},
.chain = {
.enable = field_value(CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_ENABLED),
.disable = field_value(CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED)
},
.match = {
.napot = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_NAPOT),
.lt = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT),
.ge = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE),
.eq = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL)
},
.tdata1_ignore_mask = 0
};
return result;
}
static int maybe_add_trigger_t2_t6(struct target *target,
struct trigger *trigger, struct match_triggers_tdata1_fields fields)
{
int ret = ERROR_OK;
if (!trigger->execute && trigger->length > 1) {
/* Setting a load/store trigger ("watchpoint") on a range of addresses */
if (can_use_napot_match(trigger)) {
LOG_TARGET_DEBUG(target, "trying to setup NAPOT match trigger");
struct trigger_request_info napot = {
.tdata1 = fields.common | fields.size.any |
fields.chain.disable | fields.match.napot,
.tdata2 = trigger->address | ((trigger->length - 1) >> 1),
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_single_match_trigger(target, trigger, napot);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
LOG_TARGET_DEBUG(target, "trying to setup GE+LT chained match trigger pair");
struct trigger_request_info ge_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info lt_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
LOG_TARGET_DEBUG(target, "trying to setup LT+GE chained match trigger pair");
struct trigger_request_info lt_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.lt,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info ge_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.ge,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
LOG_TARGET_DEBUG(target, "trying to setup equality match trigger");
struct trigger_request_info eq = {
.tdata1 = fields.common |
(trigger->length == 1 ? fields.size.s8bit : fields.size.any) |
fields.chain.disable | fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
return try_setup_single_match_trigger(target, trigger, eq);
}
static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
@ -711,8 +850,8 @@ static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
tdata1 = set_field(tdata1, CSR_ICOUNT_U, u);
tdata1 = set_field(tdata1, CSR_ICOUNT_COUNT, count);
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx);
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, 0, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
@ -744,8 +883,8 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu,
tdata2 = interrupts;
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx);
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
@ -776,8 +915,8 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
tdata2 = exception_codes;
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx);
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
@ -787,108 +926,29 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
return ERROR_OK;
}
static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger)
{
int ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
tdata1 = 0;
tdata1 = set_field(tdata1, CSR_MCONTROL6_TYPE(riscv_xlen(target)), 6);
tdata1 = set_field(tdata1, CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, CSR_MCONTROL6_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, CSR_MCONTROL6_M, 1);
tdata1 = set_field(tdata1, CSR_MCONTROL6_S, !!(r->misa & (1 << ('S' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL6_U, !!(r->misa & (1 << ('U' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL6_EXECUTE, trigger->execute);
tdata1 = set_field(tdata1, CSR_MCONTROL6_LOAD, trigger->read);
tdata1 = set_field(tdata1, CSR_MCONTROL6_STORE, trigger->write);
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_ANY);
if (trigger->execute || trigger->length == 1)
goto MATCH_EQUAL;
if (!can_use_napot_match(trigger, &tdata2))
goto MATCH_GE_LT;
unsigned int idx;
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_NAPOT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
MATCH_GE_LT:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, true, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_ENABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
tdata2 = trigger->address + trigger->length;
ret = set_trigger(target, idx + 1, tdata1, tdata2, 0);
if (ret != ERROR_OK) {
set_trigger(target, idx, 0, 0, 0); /* Undo the setting of the previous trigger*/
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
r->trigger_unique_id[idx + 1] = trigger->unique_id;
return ERROR_OK;
MATCH_EQUAL:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL);
if (trigger->length == 1)
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_8BIT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
}
static int add_trigger(struct target *target, struct trigger *trigger)
{
int ret;
riscv_reg_t tselect;
if (riscv_enumerate_triggers(target) != ERROR_OK)
return ERROR_FAIL;
ret = riscv_enumerate_triggers(target);
if (ret != ERROR_OK)
return ret;
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
if (result != ERROR_OK)
return result;
ret = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
if (ret != ERROR_OK)
return ret;
do {
ret = maybe_add_trigger_t1(target, trigger);
if (ret == ERROR_OK)
break;
ret = maybe_add_trigger_t2(target, trigger);
ret = maybe_add_trigger_t2_t6(target, trigger,
fill_match_triggers_tdata1_fields_t2(target, trigger));
if (ret == ERROR_OK)
break;
ret = maybe_add_trigger_t6(target, trigger);
ret = maybe_add_trigger_t2_t6(target, trigger,
fill_match_triggers_tdata1_fields_t6(target, trigger));
if (ret == ERROR_OK)
break;
} while (0);