aboutsummaryrefslogtreecommitdiff
path: root/riscv/debug_module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/debug_module.cc')
-rw-r--r--riscv/debug_module.cc137
1 files changed, 106 insertions, 31 deletions
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc
index e9aef1a..07723c5 100644
--- a/riscv/debug_module.cc
+++ b/riscv/debug_module.cc
@@ -43,7 +43,8 @@ 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),
+ sb_read_wait(0), sb_write_wait(0)
{
D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
D(fprintf(stderr, "debug_progbuf_start=0x%x\n", debug_progbuf_start));
@@ -297,6 +298,24 @@ void debug_module_t::sb_autoincrement()
sbaddress[3] += carry;
}
+bool debug_module_t::sb_busy() const
+{
+ return sb_read_wait > 0 || sb_write_wait > 0;
+}
+
+void debug_module_t::sb_read_start()
+{
+ if (sb_busy() || sbcs.sbbusyerror) {
+ if (!sbcs.sbbusyerror)
+ D(fprintf(stderr, "Set sbbusyerror because read start while busy\n"));
+ sbcs.sbbusyerror = true;
+ return;
+ }
+ /* Insert artificial delay, so debuggers can test how they handle that
+ * sbbusyerror being set. */
+ sb_read_wait = 20;
+}
+
void debug_module_t::sb_read()
{
reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0];
@@ -314,11 +333,25 @@ void debug_module_t::sb_read()
} else {
sbcs.error = 3;
}
+ D(fprintf(stderr, "sb_read() 0x%x @ 0x%lx\n", sbdata[0], address));
} catch (const mem_trap_t& ) {
sbcs.error = 2;
}
}
+void debug_module_t::sb_write_start()
+{
+ if (sb_busy() || sbcs.sbbusyerror) {
+ if (!sbcs.sbbusyerror)
+ D(fprintf(stderr, "Set sbbusyerror because write start while busy\n"));
+ sbcs.sbbusyerror = true;
+ return;
+ }
+ /* Insert artificial delay, so debuggers can test how they handle that
+ * sbbusyerror being set. */
+ sb_write_wait = 20;
+}
+
void debug_module_t::sb_write()
{
reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0];
@@ -494,6 +527,8 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
result = set_field(result, DM_SBCS_SBAUTOINCREMENT, sbcs.autoincrement);
result = set_field(result, DM_SBCS_SBREADONDATA, sbcs.readondata);
result = set_field(result, DM_SBCS_SBERROR, sbcs.error);
+ result = set_field(result, DM_SBCS_SBBUSY, sb_busy());
+ result = set_field(result, DM_SBCS_SBBUSYERROR, sbcs.sbbusyerror);
result = set_field(result, DM_SBCS_SBASIZE, sbcs.asize);
result = set_field(result, DM_SBCS_SBACCESS128, sbcs.access128);
result = set_field(result, DM_SBCS_SBACCESS64, sbcs.access64);
@@ -515,23 +550,31 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
break;
case DM_SBDATA0:
result = sbdata[0];
- if (sbcs.error == 0) {
+ if (sb_busy()) {
+ sbcs.sbbusyerror = true;
+ } else if (sbcs.error == 0) {
if (sbcs.readondata) {
- sb_read();
- }
- if (sbcs.error == 0) {
- sb_autoincrement();
+ sb_read_start();
}
}
break;
case DM_SBDATA1:
result = sbdata[1];
+ if (sb_busy()) {
+ sbcs.sbbusyerror = true;
+ }
break;
case DM_SBDATA2:
result = sbdata[2];
+ if (sb_busy()) {
+ sbcs.sbbusyerror = true;
+ }
break;
case DM_SBDATA3:
result = sbdata[3];
+ if (sb_busy()) {
+ sbcs.sbbusyerror = true;
+ }
break;
case DM_AUTHDATA:
result = challenge;
@@ -563,6 +606,24 @@ void debug_module_t::run_test_idle()
if (rti_remaining == 0 && abstractcs.busy && abstract_command_completed) {
abstractcs.busy = false;
}
+ if (sb_read_wait > 0) {
+ sb_read_wait--;
+ if (sb_read_wait == 0) {
+ sb_read();
+ if (sbcs.error == 0) {
+ sb_autoincrement();
+ }
+ }
+ }
+ if (sb_write_wait > 0) {
+ sb_write_wait--;
+ if (sb_write_wait == 0) {
+ sb_write();
+ if (sbcs.error == 0) {
+ sb_autoincrement();
+ }
+ }
+ }
}
static bool is_fpu_reg(unsigned regno)
@@ -877,40 +938,54 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
sbcs.autoincrement = get_field(value, DM_SBCS_SBAUTOINCREMENT);
sbcs.readondata = get_field(value, DM_SBCS_SBREADONDATA);
sbcs.error &= ~get_field(value, DM_SBCS_SBERROR);
+ if (get_field(value, DM_SBCS_SBBUSYERROR))
+ sbcs.sbbusyerror = false;
return true;
case DM_SBADDRESS0:
- sbaddress[0] = value;
- if (sbcs.error == 0 && sbcs.readonaddr) {
- sb_read();
- sb_autoincrement();
- }
- return true;
case DM_SBADDRESS1:
- sbaddress[1] = value;
- return true;
case DM_SBADDRESS2:
- sbaddress[2] = value;
- return true;
case DM_SBADDRESS3:
- sbaddress[3] = value;
- return true;
case DM_SBDATA0:
- sbdata[0] = value;
- if (sbcs.error == 0) {
- sb_write();
- if (sbcs.error == 0) {
- sb_autoincrement();
- }
- }
- return true;
case DM_SBDATA1:
- sbdata[1] = value;
- return true;
case DM_SBDATA2:
- sbdata[2] = value;
- return true;
case DM_SBDATA3:
- sbdata[3] = value;
+ /* These all set busyerror if already busy. */
+ if (sb_busy()) {
+ sbcs.sbbusyerror = true;
+ } else {
+ switch (address) {
+ case DM_SBADDRESS0:
+ sbaddress[0] = value;
+ if (sbcs.error == 0 && sbcs.readonaddr) {
+ sb_read_start();
+ }
+ return true;
+ case DM_SBADDRESS1:
+ sbaddress[1] = value;
+ return true;
+ case DM_SBADDRESS2:
+ sbaddress[2] = value;
+ return true;
+ case DM_SBADDRESS3:
+ sbaddress[3] = value;
+ return true;
+ case DM_SBDATA0:
+ sbdata[0] = value;
+ if (sbcs.error == 0) {
+ sb_write_start();
+ }
+ return true;
+ case DM_SBDATA1:
+ sbdata[1] = value;
+ return true;
+ case DM_SBDATA2:
+ sbdata[2] = value;
+ return true;
+ case DM_SBDATA3:
+ sbdata[3] = value;
+ return true;
+ }
+ }
return true;
case DM_AUTHDATA:
D(fprintf(stderr, "debug authentication: got 0x%x; 0x%x unlocks\n", value,