diff options
-rw-r--r-- | .github/workflows/debug-smoke.yml | 2 | ||||
-rw-r--r-- | riscv/debug_module.cc | 137 | ||||
-rw-r--r-- | riscv/debug_module.h | 14 | ||||
-rw-r--r-- | riscv/processor.cc | 10 |
4 files changed, 126 insertions, 37 deletions
diff --git a/.github/workflows/debug-smoke.yml b/.github/workflows/debug-smoke.yml index 7c24d55..1ae54ab 100644 --- a/.github/workflows/debug-smoke.yml +++ b/.github/workflows/debug-smoke.yml @@ -25,7 +25,7 @@ jobs: run: | git clone --recurse-submodules https://github.com/riscv/riscv-openocd.git cd riscv-openocd - git checkout a495dd854ce2e857a583125a31527a47320ec6b9 + git checkout d4c5d2657074613d429f57f60e939ca151ed4f32 - name: Build OpenOCD run: | 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, diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 73bb7fa..75109f6 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -89,6 +89,7 @@ typedef struct { bool access32; bool access16; bool access8; + bool sbbusyerror; } sbcs_t; typedef struct { @@ -157,8 +158,19 @@ class debug_module_t : public abstract_device_t uint32_t read32(uint8_t *rom, unsigned int index); void sb_autoincrement(); + + /* Start a system bus access. (It could be instantaneous, but to help test + * OpenOCD a delay can be added.) */ + void sb_read_start(); + void sb_write_start(); + + /* Actually read/write. */ void sb_read(); void sb_write(); + + /* Return true iff a system bus access is in progress. */ + bool sb_busy() const; + unsigned sb_access_bits(); dmcontrol_t dmcontrol; @@ -191,6 +203,8 @@ class debug_module_t : public abstract_device_t * available. Otherwise it is unavailable. */ bool hart_available_state[2]; bool hart_available(unsigned hart_id) const; + + unsigned sb_read_wait, sb_write_wait; }; #endif diff --git a/riscv/processor.cc b/riscv/processor.cc index 0ac6e67..5a43d56 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -535,14 +535,14 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) // Smcsrind / Sscsrind - csr_t_p miselect; - csr_t_p siselect; - csr_t_p vsiselect; sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg[6]; sscsrind_reg_csr_t::sscsrind_reg_csr_t_p sireg[6]; sscsrind_reg_csr_t::sscsrind_reg_csr_t_p vsireg[6]; if (proc->extension_enabled_const(EXT_SMCSRIND)) { + csr_t_p miselect = std::make_shared<basic_csr_t>(proc, CSR_MISELECT, 0); + csrmap[CSR_MISELECT] = miselect; + const reg_t mireg_csrs[] = { CSR_MIREG, CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; auto i = 0; for (auto csr : mireg_csrs) { @@ -552,9 +552,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) } if (proc->extension_enabled_const(EXT_SSCSRIND)) { - vsiselect = std::make_shared<basic_csr_t>(proc, CSR_VSISELECT, 0); + csr_t_p vsiselect = std::make_shared<basic_csr_t>(proc, CSR_VSISELECT, 0); csrmap[CSR_VSISELECT] = vsiselect; - siselect = std::make_shared<basic_csr_t>(proc, CSR_SISELECT, 0); + csr_t_p siselect = std::make_shared<basic_csr_t>(proc, CSR_SISELECT, 0); csrmap[CSR_SISELECT] = std::make_shared<virtualized_csr_t>(proc, siselect, vsiselect); const reg_t vsireg_csrs[] = { CSR_VSIREG, CSR_VSIREG2, CSR_VSIREG3, CSR_VSIREG4, CSR_VSIREG5, CSR_VSIREG6 }; |