Browse Source

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.
pull/218/head
Tim Newsome 7 years ago
committed by GitHub
parent
commit
f9d2be538b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 733
      riscv/debug_defines.h
  2. 76
      riscv/debug_module.cc
  3. 14
      riscv/debug_module.h

733
riscv/debug_defines.h

File diff suppressed because it is too large

76
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;
}

14
riscv/debug_module.h

@ -73,6 +73,13 @@ typedef struct {
bool access8;
} sbcs_t;
typedef struct {
bool halted;
bool resumeack;
bool havereset;
uint8_t haltgroup;
} hart_debug_state_t;
class debug_module_t : public abstract_device_t
{
public:
@ -109,6 +116,7 @@ class debug_module_t : public abstract_device_t
private:
static const unsigned datasize = 2;
unsigned nprocs;
// Size of program_buffer in 32-bit words, as exposed to the rest of the
// world.
unsigned progbufsize;
@ -129,7 +137,7 @@ class debug_module_t : public abstract_device_t
// We only support 1024 harts currently. More requires at least resizing
// the arrays below, and their corresponding special memory regions.
static const unsigned hartsellen = 10;
unsigned hartsellen = 10;
sim_t *sim;
@ -138,9 +146,7 @@ class debug_module_t : public abstract_device_t
uint8_t *program_buffer;
uint8_t dmdata[datasize * 4];
bool halted[1024];
bool resumeack[1024];
bool havereset[1024];
std::vector<hart_debug_state_t> hart_state;
uint8_t debug_rom_flags[1024];
void write32(uint8_t *rom, unsigned int index, uint32_t value);

Loading…
Cancel
Save