Browse Source

Make debug module tolerant of discontiguous hart IDs

The general strategy is to avoid iterating over the ID space.
pull/1246/head
Andrew Waterman 4 years ago
parent
commit
e436852d18
  1. 132
      riscv/debug_module.cc
  2. 9
      riscv/debug_module.h

132
riscv/debug_module.cc

@ -32,18 +32,16 @@ static unsigned field_width(unsigned n)
///////////////////////// debug_module_t
debug_module_t::debug_module_t(sim_t *sim, const debug_module_config_t &config) :
nprocs(sim->nprocs()),
config(config),
program_buffer_bytes((config.support_impebreak ? 4 : 0) + 4*config.progbufsize),
debug_progbuf_start(debug_data_start - program_buffer_bytes),
debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
custom_base(0),
hartsellen(field_width(sim->nprocs())),
sim(sim),
// The spec lets a debugger select nonexistent harts. Create hart_state for
// them because I'm too lazy to add the code to just ignore accesses.
hart_state(1 << field_width(sim->nprocs())),
hart_array_mask(sim->nprocs()),
hart_state(1 << field_width(sim->get_cfg().max_hartid() + 1)),
hart_array_mask(sim->get_cfg().max_hartid() + 1),
rti_remaining(0)
{
D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
@ -51,9 +49,9 @@ debug_module_t::debug_module_t(sim_t *sim, const debug_module_config_t &config)
D(fprintf(stderr, "debug_abstract_start=0x%x\n", debug_abstract_start));
const unsigned max_procs = 1024;
if (nprocs > max_procs) {
fprintf(stderr, "At most %u processors are supported (%u requested)\n",
max_procs, nprocs);
if (sim->get_cfg().max_hartid() >= max_procs) {
fprintf(stderr, "Hart IDs must not exceed %u (%zu harts with max hart ID %zu requested)\n",
max_procs - 1, sim->get_cfg().nprocs(), sim->get_cfg().max_hartid());
exit(1);
}
@ -85,11 +83,8 @@ debug_module_t::~debug_module_t()
void debug_module_t::reset()
{
assert(sim->nprocs() > 0);
for (unsigned i = 0; i < sim->nprocs(); i++) {
processor_t *proc = sim->get_core(i);
if (proc)
proc->halt_request = proc->HR_NONE;
for (const auto& [hart_id, hart] : sim->get_harts()) {
hart->halt_request = hart->HR_NONE;
}
memset(&dmcontrol, 0, sizeof(dmcontrol));
@ -208,22 +203,19 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
if (!hart_state[id].halted) {
hart_state[id].halted = true;
if (hart_state[id].haltgroup) {
for (unsigned i = 0; i < nprocs; i++) {
if (!hart_state[i].halted &&
hart_state[i].haltgroup == hart_state[id].haltgroup) {
processor_t *proc = sim->get_core(i);
proc->halt_request = proc->HR_GROUP;
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->halt_request = hart->HR_GROUP;
// TODO: What if the debugger comes and writes dmcontrol before the
// halt occurs?
}
}
}
}
if (dmcontrol.hartsel == id) {
if (selected_hart_id() == id) {
if (0 == (debug_rom_flags[id] & (1 << DEBUG_ROM_FLAG_GO))) {
if (dmcontrol.hartsel == id) {
abstract_command_completed = true;
}
abstract_command_completed = true;
}
}
return true;
@ -274,23 +266,9 @@ uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
return value;
}
processor_t *debug_module_t::processor(unsigned hartid) const
{
processor_t *proc = NULL;
try {
proc = sim->get_core(hartid);
} catch (const std::out_of_range&) {
}
return proc;
}
bool debug_module_t::hart_selected(unsigned hartid) const
{
if (dmcontrol.hasel) {
return hartid == dmcontrol.hartsel || hart_array_mask[hartid];
} else {
return hartid == dmcontrol.hartsel;
}
return hartid == selected_hart_id() || (dmcontrol.hasel && hart_array_mask[hartid]);
}
unsigned debug_module_t::sb_access_bits()
@ -412,15 +390,15 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
dmstatus.allnonexistant = true;
dmstatus.allresumeack = true;
dmstatus.anyresumeack = false;
for (unsigned i = 0; i < nprocs; i++) {
if (hart_selected(i)) {
for (const auto& [hart_id, hart] : sim->get_harts()) {
if (hart_selected(hart_id)) {
dmstatus.allnonexistant = false;
if (hart_state[i].resumeack) {
if (hart_state[hart_id].resumeack) {
dmstatus.anyresumeack = true;
} else {
dmstatus.allresumeack = false;
}
if (hart_state[i].halted) {
if (hart_state[hart_id].halted) {
dmstatus.allrunning = false;
dmstatus.anyhalted = true;
} else {
@ -433,17 +411,15 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
// We don't allow selecting non-existant harts through
// hart_array_mask, so the only way it's possible is by writing a
// non-existant hartsel.
dmstatus.anynonexistant = (dmcontrol.hartsel >= nprocs);
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,
hart_state[dmcontrol.hartsel].havereset);
result = set_field(result, DM_DMSTATUS_ANYHAVERESET,
hart_state[dmcontrol.hartsel].havereset);
result = set_field(result, DM_DMSTATUS_ALLHAVERESET, selected_hart_state().havereset);
result = set_field(result, DM_DMSTATUS_ANYHAVERESET, selected_hart_state().havereset);
result = set_field(result, DM_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
result = set_field(result, DM_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
result = set_field(result, DM_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
@ -487,7 +463,7 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
unsigned base = hawindowsel * 32;
for (unsigned i = 0; i < 32; i++) {
unsigned n = base + i;
if (n < nprocs && hart_array_mask[n]) {
if (n < sim->get_cfg().nprocs() && hart_array_mask[sim->get_cfg().hartids()[n]]) {
result |= 1 << i;
}
}
@ -543,8 +519,7 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
result = challenge;
break;
case DM_DMCS2:
result = set_field(result, DM_DMCS2_GROUP,
hart_state[dmcontrol.hartsel].haltgroup);
result = set_field(result, DM_DMCS2_GROUP, selected_hart_state().haltgroup);
break;
default:
result = 0;
@ -588,7 +563,7 @@ bool debug_module_t::perform_abstract_command()
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
if (!hart_state[dmcontrol.hartsel].halted) {
if (!selected_hart_state().halted) {
abstractcs.cmderr = CMDERR_HALTRESUME;
return true;
}
@ -743,7 +718,7 @@ bool debug_module_t::perform_abstract_command()
write32(debug_abstract, i++, ebreak());
}
debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
rti_remaining = config.abstract_rti;
abstract_command_completed = false;
@ -808,34 +783,30 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
dmcontrol.hartsel = get_field(value, DM_DMCONTROL_HARTSELHI) <<
DM_DMCONTROL_HARTSELLO_LENGTH;
dmcontrol.hartsel |= get_field(value, DM_DMCONTROL_HARTSELLO);
dmcontrol.hartsel &= (1L<<hartsellen) - 1;
for (unsigned i = 0; i < nprocs; i++) {
if (hart_selected(i)) {
dmcontrol.hartsel = std::min(size_t(dmcontrol.hartsel), sim->get_cfg().nprocs() - 1);
for (const auto& [hart_id, hart] : sim->get_harts()) {
if (hart_selected(hart_id)) {
if (get_field(value, DM_DMCONTROL_ACKHAVERESET)) {
hart_state[i].havereset = false;
hart_state[hart_id].havereset = false;
}
processor_t *proc = processor(i);
if (proc) {
proc->halt_request = dmcontrol.haltreq ? proc->HR_REGULAR : proc->HR_NONE;
if (dmcontrol.haltreq) {
D(fprintf(stderr, "halt hart %d\n", i));
}
if (dmcontrol.resumereq) {
D(fprintf(stderr, "resume hart %d\n", i));
debug_rom_flags[i] |= (1 << DEBUG_ROM_FLAG_RESUME);
hart_state[i].resumeack = false;
}
if (dmcontrol.hartreset) {
proc->reset();
}
hart->halt_request = dmcontrol.haltreq ? hart->HR_REGULAR : hart->HR_NONE;
if (dmcontrol.haltreq) {
D(fprintf(stderr, "halt hart %d\n", hart_id));
}
if (dmcontrol.resumereq) {
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) {
hart->reset();
}
}
}
if (dmcontrol.ndmreset) {
for (size_t i = 0; i < sim->nprocs(); i++) {
processor_t *proc = sim->get_core(i);
proc->reset();
for (const auto& [hart_id, hart] : sim->get_harts()) {
hart->reset();
}
}
}
@ -846,7 +817,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
return perform_abstract_command();
case DM_HAWINDOWSEL:
hawindowsel = value & ((1U<<field_width(nprocs))-1);
hawindowsel = value & ((1U<<field_width(hart_array_mask.size()))-1);
return true;
case DM_HAWINDOW:
@ -854,8 +825,8 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
unsigned base = hawindowsel * 32;
for (unsigned i = 0; i < 32; i++) {
unsigned n = base + i;
if (n < nprocs) {
hart_array_mask[n] = (value >> i) & 1;
if (n < sim->get_cfg().nprocs()) {
hart_array_mask[sim->get_cfg().hartids()[n]] = (value >> i) & 1;
}
}
}
@ -928,8 +899,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
if (config.support_haltgroups &&
get_field(value, DM_DMCS2_HGWRITE) &&
get_field(value, DM_DMCS2_GROUPTYPE) == 0) {
hart_state[dmcontrol.hartsel].haltgroup = get_field(value,
DM_DMCS2_GROUP);
selected_hart_state().haltgroup = get_field(value, DM_DMCS2_GROUP);
}
return true;
}
@ -943,3 +913,13 @@ void debug_module_t::proc_reset(unsigned id)
hart_state[id].halted = false;
hart_state[id].haltgroup = 0;
}
hart_debug_state_t& debug_module_t::selected_hart_state()
{
return hart_state[selected_hart_id()];
}
size_t debug_module_t::selected_hart_id() const
{
return sim->get_cfg().hartids().at(dmcontrol.hartsel);
}

9
riscv/debug_module.h

@ -132,7 +132,6 @@ class debug_module_t : public abstract_device_t
private:
static const unsigned datasize = 2;
unsigned nprocs;
debug_module_config_t config;
// Actual size of the program buffer, which is 1 word bigger than we let on
// to implement the implicit ebreak at the end.
@ -146,10 +145,6 @@ class debug_module_t : public abstract_device_t
// functionality.
unsigned custom_base;
// We only support 1024 harts currently. More requires at least resizing
// the arrays below, and their corresponding special memory regions.
unsigned hartsellen = 10;
sim_t *sim;
uint8_t debug_rom_whereto[4];
@ -183,13 +178,15 @@ class debug_module_t : public abstract_device_t
uint32_t challenge;
const uint32_t secret = 1;
processor_t *processor(unsigned hartid) const;
bool hart_selected(unsigned hartid) const;
void reset();
bool perform_abstract_command();
bool abstract_command_completed;
unsigned rti_remaining;
size_t selected_hart_id() const;
hart_debug_state_t& selected_hart_state();
};
#endif

Loading…
Cancel
Save