diff options
author | Tim Newsome <tim@sifive.com> | 2023-06-26 17:33:18 -0700 |
---|---|---|
committer | Tim Newsome <tim@sifive.com> | 2023-07-05 08:51:55 -0700 |
commit | ea6740350fcdd5fe63f299d931b6d2b9ff7797ef (patch) | |
tree | 1f0ac50a2eaa08cb6952df50030aef291de6ba78 | |
parent | 71f5a8fd1b1185b7c15151f116aa3fef058bf210 (diff) | |
download | riscv-isa-sim-ea6740350fcdd5fe63f299d931b6d2b9ff7797ef.zip riscv-isa-sim-ea6740350fcdd5fe63f299d931b6d2b9ff7797ef.tar.gz riscv-isa-sim-ea6740350fcdd5fe63f299d931b6d2b9ff7797ef.tar.bz2 |
Let debugger control hart availability
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.
-rw-r--r-- | riscv/debug_module.cc | 45 | ||||
-rw-r--r-- | riscv/debug_module.h | 6 |
2 files changed, 43 insertions, 8 deletions
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index f7163ef..4a7a802 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -73,6 +73,9 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config jal(ZERO, debug_abstract_start - DEBUG_ROM_WHERETO)); memset(debug_abstract, 0, sizeof(debug_abstract)); + for (unsigned i = 0; i < sizeof(hart_available_state) / sizeof(*hart_available_state); i++) { + hart_available_state[i] = true; + } reset(); } @@ -202,7 +205,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? @@ -337,6 +341,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; @@ -391,6 +402,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; @@ -399,12 +412,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; } } } @@ -414,9 +434,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); @@ -522,6 +539,11 @@ 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: + for (unsigned i = 0; i < sizeof(hart_available_state) / sizeof(*hart_available_state); i++) { + result |= hart_available_state[i] << i; + } + break; default: result = 0; D(fprintf(stderr, "Unexpected. Returning Error.")); @@ -790,16 +812,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(); } } @@ -903,6 +927,11 @@ 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: + for (unsigned i = 0; i < sizeof(hart_available_state) / sizeof(*hart_available_state); i++) { + hart_available_state[i] = get_field(value, 1<<i); + } + return true; } } return false; diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 518f119..73bb7fa 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -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 |