aboutsummaryrefslogtreecommitdiff
path: root/riscv/debug_module.cc
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2019-03-04 09:17:00 -0800
committerGitHub <noreply@github.com>2019-03-04 09:17:00 -0800
commitf9d2be538b134ac42bf33b4b04e97d182ced5e36 (patch)
treed0f991124d73bc89ae12507d482bf9c69b9a5f5c /riscv/debug_module.cc
parent5b08bf5c3cc236ed6baf6d4f2964d8efe5b1705c (diff)
downloadspike-f9d2be538b134ac42bf33b4b04e97d182ced5e36.zip
spike-f9d2be538b134ac42bf33b4b04e97d182ced5e36.tar.gz
spike-f9d2be538b134ac42bf33b4b04e97d182ced5e36.tar.bz2
Implement halt groups (#280)
* Update debug_defines from latest spec. * Implement halt groups. This lets the debugger halt multiple harts near simultaneously. * Revert encoding, which I updated accidentally.
Diffstat (limited to 'riscv/debug_module.cc')
-rw-r--r--riscv/debug_module.cc76
1 files changed, 59 insertions, 17 deletions
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc
index 18a7a64..f746a72 100644
--- a/riscv/debug_module.cc
+++ b/riscv/debug_module.cc
@@ -15,10 +15,25 @@
# define D(x)
#endif
+// Return the number of bits wide that a field has to be to encode up to n
+// different values.
+// 1->0, 2->1, 3->2, 4->2
+static unsigned field_width(unsigned n)
+{
+ unsigned i = 0;
+ n -= 1;
+ while (n) {
+ i++;
+ n >>= 1;
+ }
+ return i;
+}
+
///////////////////////// debug_module_t
debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits,
bool require_authentication, unsigned abstract_rti) :
+ nprocs(sim->nprocs()),
progbufsize(progbufsize),
program_buffer_bytes(4 + 4*progbufsize),
max_bus_master_bits(max_bus_master_bits),
@@ -27,18 +42,21 @@ debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bu
debug_progbuf_start(debug_data_start - program_buffer_bytes),
debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
custom_base(0),
- sim(sim)
+ 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()))
{
D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
D(fprintf(stderr, "debug_progbuf_start=0x%x\n", debug_progbuf_start));
D(fprintf(stderr, "debug_abstract_start=0x%x\n", debug_abstract_start));
+ assert(nprocs <= 1024);
+
program_buffer = new uint8_t[program_buffer_bytes];
- memset(halted, 0, sizeof(halted));
memset(debug_rom_flags, 0, sizeof(debug_rom_flags));
- memset(resumeack, 0, sizeof(resumeack));
- memset(havereset, 0, sizeof(havereset));
memset(program_buffer, 0, program_buffer_bytes);
program_buffer[4*progbufsize] = ebreak();
program_buffer[4*progbufsize+1] = ebreak() >> 8;
@@ -180,7 +198,20 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
if (addr == DEBUG_ROM_HALTED) {
assert (len == 4);
- halted[id] = true;
+ 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 = true;
+ // TODO: What if the debugger comes and writes dmcontrol before the
+ // halt occurs?
+ }
+ }
+ }
+ }
if (dmcontrol.hartsel == id) {
if (0 == (debug_rom_flags[id] & (1 << DEBUG_ROM_FLAG_GO))){
if (dmcontrol.hartsel == id) {
@@ -198,8 +229,8 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
if (addr == DEBUG_ROM_RESUMING) {
assert (len == 4);
- halted[id] = false;
- resumeack[id] = true;
+ hart_state[id].halted = false;
+ hart_state[id].resumeack = true;
debug_rom_flags[id] &= ~(1 << DEBUG_ROM_FLAG_RESUME);
return true;
}
@@ -368,7 +399,7 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
dmstatus.allhalted = false;
dmstatus.allresumeack = false;
if (proc) {
- if (halted[dmcontrol.hartsel]) {
+ if (hart_state[dmcontrol.hartsel].halted) {
dmstatus.allhalted = true;
} else {
dmstatus.allrunning = true;
@@ -381,7 +412,7 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
dmstatus.anyrunning = dmstatus.allrunning;
dmstatus.anyhalted = dmstatus.allhalted;
if (proc) {
- if (resumeack[dmcontrol.hartsel]) {
+ if (hart_state[dmcontrol.hartsel].resumeack) {
dmstatus.allresumeack = true;
} else {
dmstatus.allresumeack = false;
@@ -393,9 +424,9 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
result = set_field(result, DMI_DMSTATUS_IMPEBREAK,
dmstatus.impebreak);
result = set_field(result, DMI_DMSTATUS_ALLHAVERESET,
- havereset[dmcontrol.hartsel]);
+ hart_state[dmcontrol.hartsel].havereset);
result = set_field(result, DMI_DMSTATUS_ANYHAVERESET,
- havereset[dmcontrol.hartsel]);
+ hart_state[dmcontrol.hartsel].havereset);
result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
@@ -480,6 +511,10 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
case DMI_AUTHDATA:
result = challenge;
break;
+ case DMI_DMCS2:
+ result = set_field(result, DMI_DMCS2_HALTGROUP,
+ hart_state[dmcontrol.hartsel].haltgroup);
+ break;
default:
result = 0;
D(fprintf(stderr, "Unexpected. Returning Error."));
@@ -512,11 +547,11 @@ bool debug_module_t::perform_abstract_command()
if ((command >> 24) == 0) {
// register access
- unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
+ unsigned size = get_field(command, AC_ACCESS_REGISTER_AARSIZE);
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
- if (!halted[dmcontrol.hartsel]) {
+ if (!hart_state[dmcontrol.hartsel].halted) {
abstractcs.cmderr = CMDERR_HALTRESUME;
return true;
}
@@ -704,7 +739,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
dmcontrol.hartsel |= get_field(value, DMI_DMCONTROL_HARTSELLO);
dmcontrol.hartsel &= (1L<<hartsellen) - 1;
if (get_field(value, DMI_DMCONTROL_ACKHAVERESET)) {
- havereset[dmcontrol.hartsel] = false;
+ hart_state[dmcontrol.hartsel].havereset = false;
}
}
processor_t *proc = current_proc();
@@ -712,7 +747,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
proc->halt_request = dmcontrol.haltreq;
if (dmcontrol.resumereq) {
debug_rom_flags[dmcontrol.hartsel] |= (1 << DEBUG_ROM_FLAG_RESUME);
- resumeack[dmcontrol.hartsel] = false;
+ hart_state[dmcontrol.hartsel].resumeack = false;
}
if (dmcontrol.hartreset) {
proc->reset();
@@ -794,6 +829,12 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
}
}
return true;
+ case DMI_DMCS2:
+ if (get_field(value, DMI_DMCS2_HGWRITE)) {
+ hart_state[dmcontrol.hartsel].haltgroup = get_field(value,
+ DMI_DMCS2_HALTGROUP);
+ }
+ return true;
}
}
return false;
@@ -801,6 +842,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
void debug_module_t::proc_reset(unsigned id)
{
- havereset[id] = true;
- halted[id] = false;
+ hart_state[id].havereset = true;
+ hart_state[id].halted = false;
+ hart_state[id].haltgroup = 0;
}