Skip to content

Commit

Permalink
Let debugger control hart availability
Browse files Browse the repository at this point in the history
This change lets me test OpenOCD's behavior when harts become available.
It only affects how things look to the debugger. Harts that are
"unavailable" still execute code as usual.

Control is implemented through the 2 LSBs of the DMCUSTOM register in
the Debug Module.
  • Loading branch information
timsifive committed Jun 28, 2023
1 parent 71f5a8f commit 628820e
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 9 deletions.
42 changes: 33 additions & 9 deletions riscv/debug_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config
// them because I'm too lazy to add the code to just ignore accesses.
hart_state(1 << field_width(sim->get_cfg().max_hartid() + 1)),
hart_array_mask(sim->get_cfg().max_hartid() + 1),
rti_remaining(0)
rti_remaining(0), hart_available_state{true, true}
{
D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
D(fprintf(stderr, "debug_progbuf_start=0x%x\n", debug_progbuf_start));
Expand Down Expand Up @@ -202,7 +202,8 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
if (hart_state[id].haltgroup) {
for (const auto& [hart_id, hart] : sim->get_harts()) {
if (!hart_state[hart_id].halted &&
hart_state[hart_id].haltgroup == hart_state[id].haltgroup) {
hart_state[hart_id].haltgroup == hart_state[id].haltgroup &&
hart_available(hart_id)) {
hart->halt_request = hart->HR_GROUP;
// TODO: What if the debugger comes and writes dmcontrol before the
// halt occurs?
Expand Down Expand Up @@ -337,6 +338,13 @@ void debug_module_t::sb_write()
}
}

bool debug_module_t::hart_available(unsigned hart_id) const
{
if (hart_id < sizeof(hart_available_state) / sizeof(*hart_available_state))
return hart_available_state[hart_id];
return true;
}

bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
{
uint32_t result = 0;
Expand Down Expand Up @@ -391,6 +399,8 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
dmstatus.allnonexistant = true;
dmstatus.allresumeack = true;
dmstatus.anyresumeack = false;
dmstatus.allunavail = true;
dmstatus.anyunavail = false;
for (const auto& [hart_id, hart] : sim->get_harts()) {
if (hart_selected(hart_id)) {
dmstatus.allnonexistant = false;
Expand All @@ -399,12 +409,19 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
} else {
dmstatus.allresumeack = false;
}
auto hart = sim->get_harts().at(hart_id);
if (hart_state[hart_id].halted) {
dmstatus.allrunning = false;
dmstatus.anyhalted = true;
dmstatus.allunavail = false;
} else if (!hart_available(hart_id)) {
dmstatus.allrunning = false;
dmstatus.allhalted = false;
dmstatus.anyunavail = true;
} else {
dmstatus.allhalted = false;
dmstatus.anyrunning = true;
dmstatus.allunavail = false;
}
}
}
Expand All @@ -414,9 +431,6 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
// non-existant hartsel.
dmstatus.anynonexistant = dmcontrol.hartsel >= sim->get_cfg().nprocs();

dmstatus.allunavail = false;
dmstatus.anyunavail = false;

result = set_field(result, DM_DMSTATUS_IMPEBREAK,
dmstatus.impebreak);
result = set_field(result, DM_DMSTATUS_ALLHAVERESET, selected_hart_state().havereset);
Expand Down Expand Up @@ -522,6 +536,10 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
case DM_DMCS2:
result = set_field(result, DM_DMCS2_GROUP, selected_hart_state().haltgroup);
break;
case DM_CUSTOM:
result = set_field(result, 1, hart_available_state[0]);
result = set_field(result, 2, hart_available_state[1]);
break;
default:
result = 0;
D(fprintf(stderr, "Unexpected. Returning Error."));
Expand Down Expand Up @@ -790,16 +808,18 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
if (get_field(value, DM_DMCONTROL_ACKHAVERESET)) {
hart_state[hart_id].havereset = false;
}
hart->halt_request = dmcontrol.haltreq ? hart->HR_REGULAR : hart->HR_NONE;
if (dmcontrol.haltreq) {
if (dmcontrol.haltreq && hart_available(hart_id)) {
hart->halt_request = hart->HR_REGULAR;
D(fprintf(stderr, "halt hart %d\n", hart_id));
} else {
hart->halt_request = hart->HR_NONE;
}
if (dmcontrol.resumereq) {
if (dmcontrol.resumereq && hart_available(hart_id)) {
D(fprintf(stderr, "resume hart %d\n", hart_id));
debug_rom_flags[hart_id] |= (1 << DEBUG_ROM_FLAG_RESUME);
hart_state[hart_id].resumeack = false;
}
if (dmcontrol.hartreset) {
if (dmcontrol.hartreset && hart_available(hart_id)) {
hart->reset();
}
}
Expand Down Expand Up @@ -903,6 +923,10 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
selected_hart_state().haltgroup = get_field(value, DM_DMCS2_GROUP);
}
return true;
case DM_CUSTOM:
hart_available_state[0] = get_field(value, 1);
hart_available_state[1] = get_field(value, 2);
return true;
}
}
return false;
Expand Down
6 changes: 6 additions & 0 deletions riscv/debug_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ class debug_module_t : public abstract_device_t

size_t selected_hart_id() const;
hart_debug_state_t& selected_hart_state();

/* Whether the first 2 harts are available is controllable through DMCUSTOM,
* where bit 0 corresponds to hart 0, etc. When a bit is one the hart
* available. Otherwise it is unavailable. */
bool hart_available_state[2];
bool hart_available(unsigned hart_id) const;
};

#endif

0 comments on commit 628820e

Please sign in to comment.