Skip to content

Commit 1225677

Browse files
committed
Update trigger behavior for memory accesses to match recommended debug specification behavior
According to the debug specification (select bit description): 0 (address): There is at least one compare value and it contains the lowest virtual address of the access. In addition, it is recommended that there are additional compare values for the other accessed virtual addresses match. (E.g. on a 32-bit read from 0x4000, the lowest address is 0x4000 and the other addresses are 0x4001, 0x4002, and 0x4003.) 1 (data): There is exactly one compare value and it contains the data value loaded or stored, or the instruction executed. Any bits beyond the size of the data access will contain 0. Previously, when select bit was 0, Spike did not follow the recommendation and provided only 1 matching value to the trigger module. This change modifies the behavior to the recommended one. The implementation follows the debug specification recommendation. Signed-off-by: Farid Khaidari <[email protected]>
1 parent 88edb8b commit 1225677

File tree

4 files changed

+43
-37
lines changed

4 files changed

+43
-37
lines changed

riscv/mmu.cc

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ mmu_t::insn_parcel_t mmu_t::fetch_slow_path(reg_t vaddr)
109109
auto access_info = generate_access_info(vaddr, FETCH, {});
110110

111111
if (check_triggers_fetch)
112-
check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt);
112+
check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt, sizeof(insn_parcel_t));
113113

114114
if (!tlb_hit) {
115115
paddr = translate(access_info, sizeof(insn_parcel_t));
@@ -129,7 +129,7 @@ mmu_t::insn_parcel_t mmu_t::fetch_slow_path(reg_t vaddr)
129129
auto res = perform_intrapage_fetch(vaddr, host_addr, paddr);
130130

131131
if (check_triggers_fetch)
132-
check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt, from_le(res));
132+
check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt, sizeof(insn_parcel_t), from_le(res));
133133

134134
return res;
135135
}
@@ -211,12 +211,12 @@ bool mmu_t::mmio(reg_t paddr, size_t len, uint8_t* bytes, access_type type)
211211
return true;
212212
}
213213

214-
void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, std::optional<reg_t> data)
214+
void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, size_t len, std::optional<reg_t> data)
215215
{
216216
if (matched_trigger || !proc)
217217
return;
218218

219-
auto match = proc->TM.detect_memory_access_match(operation, address, data);
219+
auto match = proc->TM.detect_memory_access_match(operation, address, len, data);
220220

221221
if (match.has_value())
222222
switch (match->timing) {
@@ -289,7 +289,7 @@ void mmu_t::load_slow_path(reg_t original_addr, reg_t len, uint8_t* bytes, xlate
289289
reg_t transformed_addr = access_info.transformed_vaddr;
290290

291291
if (check_triggers_load)
292-
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt);
292+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, len);
293293

294294
if ((transformed_addr & (len - 1)) == 0) {
295295
load_slow_path_intrapage(len, bytes, access_info);
@@ -309,16 +309,18 @@ void mmu_t::load_slow_path(reg_t original_addr, reg_t len, uint8_t* bytes, xlate
309309
}
310310
}
311311

312-
if (check_triggers_load) {
313-
while (len > sizeof(reg_t)) {
314-
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), bytes));
315-
len -= sizeof(reg_t);
316-
bytes += sizeof(reg_t);
312+
if (check_triggers_load && proc) {
313+
auto xlen_bytes = proc->get_xlen();
314+
while (len > xlen_bytes) {
315+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, xlen_bytes, reg_from_bytes(xlen_bytes, bytes));
316+
len -= xlen_bytes;
317+
bytes += xlen_bytes;
318+
transformed_addr += xlen_bytes;
317319
}
318-
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(len, bytes));
320+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, len, reg_from_bytes(len, bytes));
319321
}
320322

321-
if (proc && unlikely(proc->get_log_commits_enabled()))
323+
if (unlikely(proc->get_log_commits_enabled()))
322324
proc->state.log_mem_read.push_back(std::make_tuple(original_addr, 0, len));
323325
}
324326

@@ -377,15 +379,18 @@ void mmu_t::store_slow_path(reg_t original_addr, reg_t len, const uint8_t* bytes
377379
auto access_info = generate_access_info(original_addr, STORE, xlate_flags);
378380
reg_t transformed_addr = access_info.transformed_vaddr;
379381

380-
if (actually_store && check_triggers_store) {
382+
if (actually_store && check_triggers_store && proc) {
381383
reg_t trig_len = len;
382384
const uint8_t* trig_bytes = bytes;
383-
while (trig_len > sizeof(reg_t)) {
384-
check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), trig_bytes));
385-
trig_len -= sizeof(reg_t);
386-
trig_bytes += sizeof(reg_t);
385+
auto trig_addr = transformed_addr;
386+
auto xlen_bytes = proc->get_xlen();
387+
while (trig_len > xlen_bytes) {
388+
check_triggers(triggers::OPERATION_STORE, trig_addr, access_info.effective_virt, xlen_bytes, reg_from_bytes(sizeof(reg_t), trig_bytes));
389+
trig_len -= xlen_bytes;
390+
trig_bytes += xlen_bytes;
391+
trig_addr += xlen_bytes;
387392
}
388-
check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(trig_len, trig_bytes));
393+
check_triggers(triggers::OPERATION_STORE, trig_addr, access_info.effective_virt, trig_len, reg_from_bytes(trig_len, trig_bytes));
389394
}
390395

391396
if (transformed_addr & (len - 1)) {

riscv/mmu.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "triggers.h"
1515
#include "cfg.h"
1616
#include <stdlib.h>
17-
#include <vector>
1817

1918
// virtual memory configuration
2019
#define PGSHIFT 12
@@ -449,10 +448,10 @@ class mmu_t
449448
bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes);
450449
bool mmio(reg_t paddr, size_t len, uint8_t* bytes, access_type type);
451450
bool mmio_ok(reg_t paddr, access_type type);
452-
void check_triggers(triggers::operation_t operation, reg_t address, bool virt, std::optional<reg_t> data = std::nullopt) {
453-
check_triggers(operation, address, virt, address, data);
451+
void check_triggers(triggers::operation_t operation, reg_t address, bool virt, size_t len, std::optional<reg_t> data = std::nullopt) {
452+
check_triggers(operation, address, virt, address, len, data);
454453
}
455-
void check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, std::optional<reg_t> data);
454+
void check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, size_t len, std::optional<reg_t> data);
456455
bool check_svukte_qualified(reg_t addr, reg_t mode, bool forced_virt);
457456
reg_t translate(mem_access_info_t access_info, reg_t len);
458457

riscv/triggers.cc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ bool mcontrol_common_t::simple_match(unsigned xlen, reg_t value) const {
238238
assert(0);
239239
}
240240

241-
std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(processor_t * const proc, operation_t operation, reg_t address, std::optional<reg_t> data) noexcept {
241+
std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(processor_t * const proc, operation_t operation, reg_t address, size_t len, std::optional<reg_t> data) noexcept {
242242
if ((operation == triggers::OPERATION_EXECUTE && !execute) ||
243243
(operation == triggers::OPERATION_STORE && !store) ||
244244
(operation == triggers::OPERATION_LOAD && !load) ||
@@ -251,23 +251,25 @@ std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(proc
251251
if (!data.has_value())
252252
return std::nullopt;
253253
value = *data;
254+
len = 1;
254255
} else {
255256
value = address;
256257
}
257258

258259
// We need this because in 32-bit mode sometimes the PC bits get sign
259260
// extended.
260261
auto xlen = proc->get_xlen();
261-
if (xlen == 32) {
262-
value &= 0xffffffff;
263-
}
262+
auto mask = make_mask64(0, xlen);
263+
value &= mask;
264+
265+
for (std::size_t i = 0; i < len; ++i)
266+
if (simple_match(xlen, (value + i) & mask)) {
267+
/* This is OK because this function is only called if the trigger was not
268+
* inhibited by the previous trigger in the chain. */
269+
set_hit(timing ? HIT_IMMEDIATELY_AFTER : HIT_BEFORE);
270+
return match_result_t(timing_t(timing), action);
271+
}
264272

265-
if (simple_match(xlen, value)) {
266-
/* This is OK because this function is only called if the trigger was not
267-
* inhibited by the previous trigger in the chain. */
268-
set_hit(timing ? HIT_IMMEDIATELY_AFTER : HIT_BEFORE);
269-
return match_result_t(timing_t(timing), action);
270-
}
271273
return std::nullopt;
272274
}
273275

@@ -600,7 +602,7 @@ bool module_t::tdata3_write(unsigned index, const reg_t val) noexcept
600602
return true;
601603
}
602604

603-
std::optional<match_result_t> module_t::detect_memory_access_match(operation_t operation, reg_t address, std::optional<reg_t> data) noexcept
605+
std::optional<match_result_t> module_t::detect_memory_access_match(operation_t operation, reg_t address, size_t len, std::optional<reg_t> data) noexcept
604606
{
605607
state_t * const state = proc->get_state();
606608
if (state->debug_mode)
@@ -621,7 +623,7 @@ std::optional<match_result_t> module_t::detect_memory_access_match(operation_t o
621623
* entire chain did not match. This is allowed by the spec, because the final
622624
* trigger in the chain will never get `hit` set unless the entire chain
623625
* matches. */
624-
auto result = trigger->detect_memory_access_match(proc, operation, address, data);
626+
auto result = trigger->detect_memory_access_match(proc, operation, address, len, data);
625627
if (result.has_value() && !trigger->get_chain() && (!ret.has_value() || ret->action < result->action))
626628
ret = result;
627629

riscv/triggers.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class trigger_t {
9191
virtual void stash_read_values() {}
9292

9393
virtual std::optional<match_result_t> detect_memory_access_match(processor_t UNUSED * const proc,
94-
operation_t UNUSED operation, reg_t UNUSED address, std::optional<reg_t> UNUSED data) noexcept { return std::nullopt; }
94+
operation_t UNUSED operation, reg_t UNUSED address, size_t UNUSED len, std::optional<reg_t> UNUSED data) noexcept { return std::nullopt; }
9595
virtual std::optional<match_result_t> detect_icount_fire(processor_t UNUSED * const proc) { return std::nullopt; }
9696
virtual void detect_icount_decrement(processor_t UNUSED * const proc) {}
9797
virtual std::optional<match_result_t> detect_trap_match(processor_t UNUSED * const proc, const trap_t UNUSED & t) noexcept { return std::nullopt; }
@@ -214,7 +214,7 @@ class mcontrol_common_t : public trigger_t {
214214
virtual void set_hit(hit_t val) = 0;
215215

216216
virtual std::optional<match_result_t> detect_memory_access_match(processor_t * const proc,
217-
operation_t operation, reg_t address, std::optional<reg_t> data) noexcept override;
217+
operation_t operation, reg_t address, size_t len, std::optional<reg_t> data) noexcept override;
218218

219219
private:
220220
bool simple_match(unsigned xlen, reg_t value) const;
@@ -292,7 +292,7 @@ class module_t {
292292

293293
unsigned count() const { return triggers.size(); }
294294

295-
std::optional<match_result_t> detect_memory_access_match(operation_t operation, reg_t address, std::optional<reg_t> data) noexcept;
295+
std::optional<match_result_t> detect_memory_access_match(operation_t operation, reg_t address, size_t len, std::optional<reg_t> data) noexcept;
296296
std::optional<match_result_t> detect_icount_match() noexcept;
297297
std::optional<match_result_t> detect_trap_match(const trap_t& t) noexcept;
298298

0 commit comments

Comments
 (0)