diff options
Diffstat (limited to 'riscv/debug_module.cc')
| -rw-r--r-- | riscv/debug_module.cc | 518 |
1 files changed, 346 insertions, 172 deletions
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 5d49605..410e0b3 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -1,4 +1,8 @@ +#include <algorithm> +#include <array> #include <cassert> +#include <iterator> +#include <limits> #include "simif.h" #include "devices.h" @@ -13,7 +17,7 @@ #if 0 # define D(x) x #else -# define D(x) +# define D(x) (void) 0 #endif // Return the number of bits wide that a field has to be to encode up to n @@ -32,6 +36,25 @@ static unsigned field_width(unsigned n) ///////////////////////// debug_module_t +static bool region_descriptor_comparator(const region_descriptor &lhs, + const region_descriptor &rhs) { + return lhs.addr < rhs.addr; +} + +template <typename It> +static bool has_intersection(It begin, It end) { + assert(std::is_sorted(begin, end, region_descriptor_comparator)); + + // If current interval's end > next interval's start, they intersect + auto intersecion = + std::adjacent_find(begin, end, [](const auto &lhs, const auto &rhs) { + assert(std::numeric_limits<reg_t>::max() - lhs.addr >= lhs.len); + return lhs.addr + lhs.len > rhs.addr; + }); + + return intersecion != end; +} + debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config) : config(config), program_buffer_bytes((config.support_impebreak ? 4 : 0) + 4*config.progbufsize), @@ -57,11 +80,18 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config exit(1); } + constexpr unsigned max_data_reg = 12; + constexpr unsigned min_data_reg = 1; + if (config.datacount < min_data_reg || config.datacount > max_data_reg) { + fprintf(stderr, "dm-datacount must be between 1 and 12 (got %u)\n", config.datacount); + exit(1); + } + + dmdata.resize(config.datacount * dmdata_reg_size); program_buffer = new uint8_t[program_buffer_bytes]; memset(debug_rom_flags, 0, sizeof(debug_rom_flags)); memset(program_buffer, 0, program_buffer_bytes); - memset(dmdata, 0, sizeof(dmdata)); if (config.support_impebreak) { program_buffer[4*config.progbufsize] = ebreak(); @@ -78,6 +108,20 @@ debug_module_t::debug_module_t(simif_t *sim, const debug_module_config_t &config hart_available_state[i] = true; } + debug_memory_regions = { + region_descriptor{DEBUG_ROM_ENTRY, debug_rom_raw_len, debug_rom_raw}, + region_descriptor{DEBUG_ROM_WHERETO, sizeof(debug_rom_whereto), debug_rom_whereto}, + region_descriptor{DEBUG_ROM_FLAGS, sizeof(debug_rom_flags), debug_rom_flags}, + region_descriptor{debug_data_start, dmdata.size(), dmdata.data()}, + region_descriptor{debug_abstract_start, sizeof(debug_abstract), debug_abstract}, + region_descriptor{debug_progbuf_start, program_buffer_bytes, program_buffer}, + }; + + std::sort(debug_memory_regions.begin(), debug_memory_regions.end(), + region_descriptor_comparator); + assert(!has_intersection(debug_memory_regions.begin(), + debug_memory_regions.end())); + reset(); } @@ -100,7 +144,7 @@ void debug_module_t::reset() dmstatus.version = 2; memset(&abstractcs, 0, sizeof(abstractcs)); - abstractcs.datacount = sizeof(dmdata) / 4; + abstractcs.datacount = config.datacount; abstractcs.progbufsize = config.progbufsize; memset(&abstractauto, 0, sizeof(abstractauto)); @@ -122,38 +166,27 @@ void debug_module_t::reset() challenge = random(); } +static bool belongs_to_range(reg_t access_addr, size_t access_len, + reg_t range_addr, size_t range_len) +{ + assert(std::numeric_limits<reg_t>::max() - access_addr >= access_len); + assert(std::numeric_limits<reg_t>::max() - range_addr >= range_len); + return access_addr >= range_addr && (access_addr < range_addr + range_len) && + ((access_addr + access_len) <= (range_addr + range_len)); +} + bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) { addr = DEBUG_START + addr; - if (addr >= DEBUG_ROM_ENTRY && - (addr + len) <= (DEBUG_ROM_ENTRY + debug_rom_raw_len)) { - memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_ENTRY, len); - return true; - } - - if (addr >= DEBUG_ROM_WHERETO && (addr + len) <= (DEBUG_ROM_WHERETO + 4)) { - memcpy(bytes, debug_rom_whereto + addr - DEBUG_ROM_WHERETO, len); - return true; - } - - if (addr >= DEBUG_ROM_FLAGS && ((addr + len) <= DEBUG_ROM_FLAGS + 1024)) { - memcpy(bytes, debug_rom_flags + addr - DEBUG_ROM_FLAGS, len); - return true; - } + const auto interval_ptr = + std::find_if(debug_memory_regions.begin(), debug_memory_regions.end(), + [addr, len](const auto &range) { + return belongs_to_range(addr, len, range.addr, range.len); + }); - if (addr >= debug_abstract_start && ((addr + len) <= (debug_abstract_start + sizeof(debug_abstract)))) { - memcpy(bytes, debug_abstract + addr - debug_abstract_start, len); - return true; - } - - if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) { - memcpy(bytes, dmdata + addr - debug_data_start, len); - return true; - } - - if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) { - memcpy(bytes, program_buffer + addr - debug_progbuf_start, len); + if (interval_ptr != debug_memory_regions.end()) { + std::copy_n(std::next(interval_ptr->bytes, addr - interval_ptr->addr), len, bytes); return true; } @@ -163,6 +196,15 @@ bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) return false; } +static bool handle_range_store(reg_t input_addr, size_t input_len, const uint8_t *bytes, + reg_t range_addr, size_t range_len, uint8_t *data) +{ + if (!belongs_to_range(input_addr, input_len, range_addr, range_len)) + return false; + std::copy_n(bytes, input_len, std::next(data, input_addr - range_addr)); + return true; +} + bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) { D( @@ -188,16 +230,11 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) addr = DEBUG_START + addr; - if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) { - memcpy(dmdata + addr - debug_data_start, bytes, len); + if (handle_range_store(addr, len, bytes, debug_data_start, dmdata.size(), dmdata.data())) return true; - } - - if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) { - memcpy(program_buffer + addr - debug_progbuf_start, bytes, len); + if (handle_range_store(addr, len, bytes, debug_progbuf_start, program_buffer_bytes, program_buffer)) return true; - } if (addr == DEBUG_ROM_HALTED) { assert (len == 4); @@ -249,6 +286,11 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } +reg_t debug_module_t::size() +{ + return PGSIZE; +} + void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value) { uint8_t* base = memory + index * 4; @@ -278,6 +320,16 @@ unsigned debug_module_t::sb_access_bits() return 8 << sbcs.sbaccess; } +uint8_t *debug_module_t::get_dmdata_checked(size_t required_size) +{ + if(dmdata.size() < required_size) { + fprintf(stderr, "dmdata size (%ld) less then required (%ld)\n", + dmdata.size(), required_size); + exit(1); + } + return dmdata.data(); +} + void debug_module_t::sb_autoincrement() { if (!sbcs.autoincrement || !config.max_sba_data_width) @@ -387,7 +439,8 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) D(fprintf(stderr, "dmi_read(0x%x) -> ", address)); if (address >= DM_DATA0 && address < DM_DATA0 + abstractcs.datacount) { unsigned i = address - DM_DATA0; - result = read32(dmdata, i); + assert(dmdata.size() >= 4); + result = read32(get_dmdata_checked(i + 1), i); if (abstractcs.busy) { result = -1; D(fprintf(stderr, "\ndmi_read(0x%02x (data[%d]) -> -1 because abstractcs.busy==true\n", address, i)); @@ -445,7 +498,6 @@ 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_available(hart_id)) { dmstatus.allrunning = false; dmstatus.allhalted = false; @@ -462,9 +514,9 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) } } - // We don't allow selecting non-existant harts through + // We don't allow selecting non-existent harts through // hart_array_mask, so the only way it's possible is by writing a - // non-existant hartsel. + // non-existent hartsel. dmstatus.anynonexistant = dmcontrol.hartsel >= sim->get_cfg().nprocs(); result = set_field(result, DM_DMSTATUS_IMPEBREAK, @@ -645,131 +697,153 @@ bool debug_module_t::perform_abstract_command() return true; } - if ((command >> 24) == 0) { - // register access - 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); + auto cmdtype = get_field(command, DM_COMMAND_CMDTYPE); + constexpr decltype(cmdtype) CMDTYPE_ACCESS_REGISTER = 0ULL; + constexpr decltype(cmdtype) CMDTYPE_ACCESS_MEMORY = 2ULL; + + if (cmdtype == CMDTYPE_ACCESS_REGISTER) + return perform_abstract_register_access(); + + if (cmdtype == CMDTYPE_ACCESS_MEMORY) + return perform_abstract_memory_access(); + + abstractcs.cmderr = CMDERR_NOTSUP; + return true; +} + +bool debug_module_t::perform_abstract_register_access() +{ + // register access + 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 (!selected_hart_state().halted) { abstractcs.cmderr = CMDERR_HALTRESUME; return true; } - unsigned i = 0; - if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) { + assert(size < 8); + // Check if register fit in dmdata + if ((1U << size) > dmdata.size()) { + abstractcs.cmderr = CMDERR_NOTSUP; + return true; + } + + unsigned i = 0; + if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) { + + if (is_fpu_reg(regno)) { + // Save S0 + write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0)); + // Save mstatus + write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS)); + write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1)); + // Set mstatus.fs + assert((MSTATUS_FS & 0xfff) == 0); + write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12)); + write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS)); + } - if (is_fpu_reg(regno)) { - // Save S0 + if (regno < 0x1000 && config.support_abstract_csr_access) { + if (!is_fpu_reg(regno)) { write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0)); - // Save mstatus - write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS)); - write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1)); - // Set mstatus.fs - assert((MSTATUS_FS & 0xfff) == 0); - write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12)); - write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS)); } - if (regno < 0x1000 && config.support_abstract_csr_access) { - if (!is_fpu_reg(regno)) { - write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0)); - } - - if (write) { - switch (size) { - case 2: - write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start)); - break; - case 3: - write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start)); - break; - default: - abstractcs.cmderr = CMDERR_NOTSUP; - return true; - } - write32(debug_abstract, i++, csrw(S0, regno)); - - } else { - write32(debug_abstract, i++, csrr(S0, regno)); - switch (size) { - case 2: - write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start)); - break; - case 3: - write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start)); - break; - default: - abstractcs.cmderr = CMDERR_NOTSUP; - return true; - } - } - if (!is_fpu_reg(regno)) { - write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0)); + if (write) { + switch (size) { + case 2: + write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start)); + break; + case 3: + write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start)); + break; + default: + abstractcs.cmderr = CMDERR_NOTSUP; + return true; } + write32(debug_abstract, i++, csrw(S0, regno)); - } else if (regno >= 0x1000 && regno < 0x1020) { - unsigned regnum = regno - 0x1000; - + } else { + write32(debug_abstract, i++, csrr(S0, regno)); switch (size) { case 2: - if (write) - write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start)); - else - write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start)); + write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start)); break; case 3: - if (write) - write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start)); - else - write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start)); + write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start)); break; default: abstractcs.cmderr = CMDERR_NOTSUP; return true; } + } + if (!is_fpu_reg(regno)) { + write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0)); + } - if (regno == 0x1000 + S0 && write) { - /* - * The exception handler starts out be restoring dscratch to s0, - * which was saved before executing the abstract memory region. Since - * we just wrote s0, also make sure to write that same value to - * dscratch in case an exception occurs in a program buffer that - * might be executed later. - */ - write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0)); - } + } else if (regno >= 0x1000 && regno < 0x1020) { + unsigned regnum = regno - 0x1000; - } else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) { - unsigned fprnum = regno - 0x1020; + switch (size) { + case 2: + if (write) + write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start)); + else + write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start)); + break; + case 3: + if (write) + write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start)); + else + write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start)); + break; + default: + abstractcs.cmderr = CMDERR_NOTSUP; + return true; + } - if (write) { - switch (size) { - case 2: - write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start)); - break; - case 3: - write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start)); - break; - default: - abstractcs.cmderr = CMDERR_NOTSUP; - return true; - } + if (regno == 0x1000 + S0 && write) { + /* + * The exception handler starts out be restoring dscratch to s0, + * which was saved before executing the abstract memory region. Since + * we just wrote s0, also make sure to write that same value to + * dscratch in case an exception occurs in a program buffer that + * might be executed later. + */ + write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0)); + } - } else { - switch (size) { - case 2: - write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start)); - break; - case 3: - write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start)); - break; - default: - abstractcs.cmderr = CMDERR_NOTSUP; - return true; - } + } else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) { + unsigned fprnum = regno - 0x1020; + + if (write) { + switch (size) { + case 2: + write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start)); + break; + case 3: + write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start)); + break; + default: + abstractcs.cmderr = CMDERR_NOTSUP; + return true; } + } else { + switch (size) { + case 2: + write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start)); + break; + case 3: + write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start)); + break; + default: + abstractcs.cmderr = CMDERR_NOTSUP; + return true; + } + } + } else if (regno >= 0xc000 && (regno & 1) == 1) { // Support odd-numbered custom registers, to allow for debugger testing. unsigned custom_number = regno - 0xc000; @@ -777,46 +851,146 @@ bool debug_module_t::perform_abstract_command() if (write) { // Writing V to custom register N will cause future reads of N to // return V, reads of N-1 will return V-1, etc. - custom_base = read32(dmdata, 0) - custom_number; + assert(dmdata.size() >= 4); + custom_base = read32(get_dmdata_checked(1), 0) - custom_number; } else { - write32(dmdata, 0, custom_number + custom_base); - write32(dmdata, 1, 0); + write32(get_dmdata_checked(1), 0, custom_number + custom_base); + write32(get_dmdata_checked(2), 1, 0); } return true; - } else { - abstractcs.cmderr = CMDERR_NOTSUP; - return true; - } - - if (is_fpu_reg(regno)) { - // restore mstatus - write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1)); - write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS)); - // restore s0 - write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0)); - } - } - - if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) { - write32(debug_abstract, i, - jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i)); - i++; } else { - write32(debug_abstract, i++, ebreak()); + abstractcs.cmderr = CMDERR_NOTSUP; + return true; } - debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO; - rti_remaining = config.abstract_rti; - abstract_command_completed = false; + if (is_fpu_reg(regno)) { + // restore mstatus + write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1)); + write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS)); + // restore s0 + write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0)); + } + } - abstractcs.busy = true; + if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) { + write32(debug_abstract, i, + jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i)); + i++; } else { + write32(debug_abstract, i++, ebreak()); + } + + debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO; + rti_remaining = config.abstract_rti; + abstract_command_completed = false; + + abstractcs.busy = true; + return true; +} + +static unsigned idx(unsigned xlen) +{ + return field_width(xlen) - 3U; +} + +bool debug_module_t::perform_abstract_memory_access() { + unsigned aamsize = get_field(command, AC_ACCESS_MEMORY_AAMSIZE); + bool aampostincrement = get_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT); + bool aamvirtual = get_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL); + bool is_write = get_field(command, AC_ACCESS_MEMORY_WRITE); + auto xlen = sim->get_harts().at(selected_hart_id())->get_xlen(); + + if (!selected_hart_state().halted) { + abstractcs.cmderr = CMDERR_HALTRESUME; + return true; + } + + if (aamsize > idx(xlen)) { abstractcs.cmderr = CMDERR_NOTSUP; + return true; } + + unsigned offset = 0; + generate_initial_sequence(aamvirtual, offset); + is_write ? handle_memory_write(xlen, aamsize, offset) + : handle_memory_read(xlen, aamsize, offset); + + if (aampostincrement) + handle_post_increment(xlen, aamsize, offset); + + generate_termination_sequence(offset); + start_command_execution(); + + abstractcs.cmderr = CMDERR_NONE; return true; } +using handle_memory_func = uint32_t (*)(unsigned rd_src, unsigned base, uint16_t offset); +using handle_mstatus_func = uint32_t(*)(unsigned rd, unsigned rs1, unsigned csr); +static constexpr std::array<handle_memory_func, 4> lx = {&lb, &lh, &lw, &ld}; +static constexpr std::array<handle_memory_func, 4> sx = {&sb, &sh, &sw, &sd}; +static constexpr std::array<handle_mstatus_func, 2> csrrx = {&csrrc, &csrrs}; + +unsigned debug_module_t::arg(unsigned xlen, unsigned idx) +{ + return debug_data_start + idx * xlen / 8; +} + +void debug_module_t::handle_memory_read(size_t xlen, unsigned aamsize, unsigned &offset) +{ + write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1))); + write32(debug_abstract, offset++, lx[aamsize](S1, S1, 0)); + write32(debug_abstract, offset++, sx[idx(xlen)](S1, ZERO, arg(xlen, 0))); +} + +void debug_module_t::handle_memory_write(size_t xlen, unsigned aamsize, unsigned &offset) +{ + // Use Arg1 as temporary storage for old mstatus value + write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1))); // Arg1 -> S1 + write32(debug_abstract, offset++, sx[idx(xlen)](S0, ZERO, arg(xlen, 1))); // S0 -> Arg1 + write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 0))); // Arg0 -> S0 + + write32(debug_abstract, offset++, sx[aamsize](S0, S1, 0)); + + write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 1))); // Restore S0 +} + +void debug_module_t::handle_post_increment(size_t xlen, unsigned aamsize, unsigned &offset) +{ + write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1))); + write32(debug_abstract, offset++, addi(S1, S1, 1U << aamsize)); + write32(debug_abstract, offset++, sx[idx(xlen)](S1, ZERO, arg(xlen, 1))); +} + +void debug_module_t::generate_initial_sequence(bool aamvirtual, unsigned &offset) +{ + write32(debug_abstract, offset++, csrw(S0, CSR_DSCRATCH0)); + write32(debug_abstract, offset++, csrw(S1, CSR_DSCRATCH1)); + + // Modify mstatus.mprv and save old mstatus + write32(debug_abstract, offset++, lui(S0, MSTATUS_MPRV >> 12)); + write32(debug_abstract, offset++, csrrx[aamvirtual](S0, S0, CSR_MSTATUS)); +} + +void debug_module_t::generate_termination_sequence(unsigned &offset) +{ + // Restore mstatus + write32(debug_abstract, offset++, csrw(S0, CSR_MSTATUS)); + + write32(debug_abstract, offset++, csrr(S0, CSR_DSCRATCH0)); + write32(debug_abstract, offset++, csrr(S1, CSR_DSCRATCH1)); + write32(debug_abstract, offset++, ebreak()); +} + +void debug_module_t::start_command_execution() +{ + debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO; + rti_remaining = config.abstract_rti; + abstract_command_completed = false; + abstractcs.busy = true; +} + bool debug_module_t::dmi_write(unsigned address, uint32_t value) { D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value)); @@ -828,7 +1002,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) if (address >= DM_DATA0 && address < DM_DATA0 + abstractcs.datacount) { unsigned i = address - DM_DATA0; if (!abstractcs.busy) - write32(dmdata, address - DM_DATA0, value); + write32(get_dmdata_checked(address - DM_DATA0), address - DM_DATA0, value); if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) { abstractcs.cmderr = CMDERR_BUSY; @@ -866,8 +1040,6 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) dmcontrol.ndmreset = get_field(value, DM_DMCONTROL_NDMRESET); if (config.support_hasel) dmcontrol.hasel = get_field(value, DM_DMCONTROL_HASEL); - else - dmcontrol.hasel = 0; dmcontrol.hartsel = get_field(value, DM_DMCONTROL_HARTSELHI) << DM_DMCONTROL_HARTSELLO_LENGTH; dmcontrol.hartsel |= get_field(value, DM_DMCONTROL_HARTSELLO); @@ -927,10 +1099,12 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) return true; case DM_ABSTRACTAUTO: - abstractauto.autoexecprogbuf = get_field(value, - DM_ABSTRACTAUTO_AUTOEXECPROGBUF); - abstractauto.autoexecdata = get_field(value, - DM_ABSTRACTAUTO_AUTOEXECDATA); + if (config.support_abstractauto) { + abstractauto.autoexecprogbuf = get_field(value, + DM_ABSTRACTAUTO_AUTOEXECPROGBUF); + abstractauto.autoexecdata = get_field(value, + DM_ABSTRACTAUTO_AUTOEXECDATA); + } return true; case DM_SBCS: sbcs.readonaddr = get_field(value, DM_SBCS_SBREADONADDR); |
