X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=riscv%2Fdebug_module.cc;h=f10c866ed26e21cec0f949b82712929bce898eef;hb=aa8cbb1ccd3856fd5e0437b0e24cfd7a3b794b8e;hp=62671f67a25c8cc6b343e109b0ea9f4ec3ce1f0b;hpb=4e768d4afc8e60adb306478257c9ecbba539b958;p=riscv-isa-sim.git diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 62671f6..f10c866 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -8,7 +8,7 @@ #include "debug_rom/debug_rom.h" #include "debug_rom/debug_rom_defines.h" -#if 1 +#if 0 # define D(x) x #else # define D(x) @@ -16,30 +16,39 @@ ///////////////////////// debug_module_t -debug_module_t::debug_module_t(sim_t *sim) : sim(sim) +debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits, + bool require_authentication) : + progbufsize(progbufsize), + program_buffer_bytes(4 + 4*progbufsize), + max_bus_master_bits(max_bus_master_bits), + require_authentication(require_authentication), + debug_progbuf_start(debug_data_start - program_buffer_bytes), + debug_abstract_start(debug_progbuf_start - debug_abstract_size*4), + sim(sim) { - dmcontrol = {0}; - - dmstatus = {0}; - dmstatus.authenticated = 1; - dmstatus.versionlo = 2; - - abstractcs = {0}; - abstractcs.progsize = progsize; - - abstractauto = {0}; + 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(program_buffer, 0, sizeof(program_buffer)); + memset(program_buffer, 0, program_buffer_bytes); + program_buffer[4*progbufsize] = ebreak(); + program_buffer[4*progbufsize+1] = ebreak() >> 8; + program_buffer[4*progbufsize+2] = ebreak() >> 16; + program_buffer[4*progbufsize+3] = ebreak() >> 24; memset(dmdata, 0, sizeof(dmdata)); write32(debug_rom_whereto, 0, jal(ZERO, debug_abstract_start - DEBUG_ROM_WHERETO)); memset(debug_abstract, 0, sizeof(debug_abstract)); - + + reset(); +} + +debug_module_t::~debug_module_t() +{ + delete[] program_buffer; } void debug_module_t::reset() @@ -53,14 +62,31 @@ void debug_module_t::reset() dmcontrol = {0}; dmstatus = {0}; - dmstatus.authenticated = 1; - dmstatus.versionlo = 2; + dmstatus.impebreak = true; + dmstatus.authenticated = !require_authentication; + dmstatus.version = 2; abstractcs = {0}; abstractcs.datacount = sizeof(dmdata) / 4; - abstractcs.progsize = progsize; + abstractcs.progbufsize = progbufsize; abstractauto = {0}; + + sbcs = {0}; + if (max_bus_master_bits > 0) { + sbcs.version = 1; + sbcs.asize = sizeof(reg_t) * 8; + } + if (max_bus_master_bits >= 64) + sbcs.access64 = true; + if (max_bus_master_bits >= 32) + sbcs.access32 = true; + if (max_bus_master_bits >= 16) + sbcs.access16 = true; + if (max_bus_master_bits >= 8) + sbcs.access8 = true; + + challenge = random(); } void debug_module_t::add_device(bus_t *bus) { @@ -96,8 +122,8 @@ bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) memcpy(bytes, dmdata + addr - debug_data_start, len); return true; } - - if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + sizeof(program_buffer)))) { + + if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) { memcpy(bytes, program_buffer + addr - debug_progbuf_start, len); return true; } @@ -110,6 +136,19 @@ bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) { + D( + switch (len) { + case 4: + fprintf(stderr, "store(addr=0x%lx, len=%d, bytes=0x%08x); " + "hartsel=0x%x\n", addr, (unsigned) len, *(uint32_t *) bytes, + dmcontrol.hartsel); + break; + default: + fprintf(stderr, "store(addr=0x%lx, len=%d, bytes=...); " + "hartsel=0x%x\n", addr, (unsigned) len, dmcontrol.hartsel); + break; + } + ); uint8_t id_bytes[4]; uint32_t id = 0; @@ -119,14 +158,15 @@ 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); return true; } - - if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + sizeof(program_buffer)))) { + + if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + program_buffer_bytes))) { memcpy(program_buffer + addr - debug_progbuf_start, bytes, len); + return true; } @@ -197,6 +237,71 @@ processor_t *debug_module_t::current_proc() const return proc; } +unsigned debug_module_t::sb_access_bits() +{ + return 8 << sbcs.sbaccess; +} + +void debug_module_t::sb_autoincrement() +{ + if (!sbcs.autoincrement || !max_bus_master_bits) + return; + + uint64_t value = sbaddress[0] + sb_access_bits() / 8; + sbaddress[0] = value; + uint32_t carry = value >> 32; + + value = sbaddress[1] + carry; + sbaddress[1] = value; + carry = value >> 32; + + value = sbaddress[2] + carry; + sbaddress[2] = value; + carry = value >> 32; + + sbaddress[3] += carry; +} + +void debug_module_t::sb_read() +{ + reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0]; + try { + if (sbcs.sbaccess == 0 && max_bus_master_bits >= 8) { + sbdata[0] = sim->debug_mmu->load_uint8(address); + } else if (sbcs.sbaccess == 1 && max_bus_master_bits >= 16) { + sbdata[0] = sim->debug_mmu->load_uint16(address); + } else if (sbcs.sbaccess == 2 && max_bus_master_bits >= 32) { + sbdata[0] = sim->debug_mmu->load_uint32(address); + } else if (sbcs.sbaccess == 3 && max_bus_master_bits >= 64) { + uint64_t value = sim->debug_mmu->load_uint32(address); + sbdata[0] = value; + sbdata[1] = value >> 32; + } else { + sbcs.error = 3; + } + } catch (trap_load_access_fault& t) { + sbcs.error = 2; + } +} + +void debug_module_t::sb_write() +{ + reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0]; + D(fprintf(stderr, "sb_write() 0x%x @ 0x%lx\n", sbdata[0], address)); + if (sbcs.sbaccess == 0 && max_bus_master_bits >= 8) { + sim->debug_mmu->store_uint8(address, sbdata[0]); + } else if (sbcs.sbaccess == 1 && max_bus_master_bits >= 16) { + sim->debug_mmu->store_uint16(address, sbdata[0]); + } else if (sbcs.sbaccess == 2 && max_bus_master_bits >= 32) { + sim->debug_mmu->store_uint32(address, sbdata[0]); + } else if (sbcs.sbaccess == 3 && max_bus_master_bits >= 64) { + sim->debug_mmu->store_uint64(address, + (((uint64_t) sbdata[1]) << 32) | sbdata[0]); + } else { + sbcs.error = 3; + } +} + bool debug_module_t::dmi_read(unsigned address, uint32_t *value) { uint32_t result = 0; @@ -204,18 +309,26 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) { unsigned i = address - DMI_DATA0; result = read32(dmdata, i); + if (abstractcs.busy) { + result = -1; + fprintf(stderr, "\ndmi_read(0x%02x (data[%d]) -> -1 because abstractcs.busy==true\n", address, i); + } if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) { abstractcs.cmderr = CMDERR_BUSY; } - if ((abstractauto.autoexecdata >> i) & 1){ + if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) { perform_abstract_command(); } - } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) { - unsigned i = address = DMI_PROGBUF0; + } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progbufsize) { + unsigned i = address - DMI_PROGBUF0; result = read32(program_buffer, i); - if ((abstractauto.autoexecprogbuf >> i) & 1) { + if (abstractcs.busy) { + result = -1; + fprintf(stderr, "\ndmi_read(0x%02x (progbuf[%d]) -> -1 because abstractcs.busy==true\n", address, i); + } + if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) { perform_abstract_command(); } @@ -229,7 +342,8 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq); result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq); - result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel); + result = set_field(result, ((1L<= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) { unsigned i = address - DMI_DATA0; - write32(dmdata, address - DMI_DATA0, value); + if (!abstractcs.busy) + write32(dmdata, address - DMI_DATA0, value); if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) { abstractcs.cmderr = CMDERR_BUSY; } - if ((abstractauto.autoexecdata >> i) & 1) { + if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) { perform_abstract_command(); } return true; - } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) { + } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progbufsize) { unsigned i = address - DMI_PROGBUF0; - - write32(program_buffer, i, value); - if ((abstractauto.autoexecprogbuf >> i) & 1) { + if (!abstractcs.busy) + write32(program_buffer, i, value); + + if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) { perform_abstract_command(); } return true; - + } else { switch (address) { case DMI_DMCONTROL: { + if (!dmcontrol.dmactive && get_field(value, DMI_DMCONTROL_DMACTIVE)) + reset(); dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE); + if (!dmstatus.authenticated) + return true; if (dmcontrol.dmactive) { dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ); dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ); + dmcontrol.hartreset = get_field(value, DMI_DMCONTROL_HARTRESET); dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET); - dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL); - } else { - reset(); + dmcontrol.hartsel = get_field(value, ((1L<reset(); + } + } + if (dmcontrol.ndmreset) { + for (size_t i = 0; i < sim->nprocs(); i++) { + proc = sim->get_core(i); + proc->reset(); + } } } return true; @@ -448,9 +631,63 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) return true; case DMI_ABSTRACTAUTO: - abstractauto.autoexecprogbuf = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); - abstractauto.autoexecdata = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECDATA); - break; + abstractauto.autoexecprogbuf = get_field(value, + DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); + abstractauto.autoexecdata = get_field(value, + DMI_ABSTRACTAUTO_AUTOEXECDATA); + return true; + case DMI_SBCS: + sbcs.readonaddr = get_field(value, DMI_SBCS_SBREADONADDR); + sbcs.sbaccess = get_field(value, DMI_SBCS_SBACCESS); + sbcs.autoincrement = get_field(value, DMI_SBCS_SBAUTOINCREMENT); + sbcs.readondata = get_field(value, DMI_SBCS_SBREADONDATA); + sbcs.error &= ~get_field(value, DMI_SBCS_SBERROR); + return true; + case DMI_SBADDRESS0: + sbaddress[0] = value; + if (sbcs.error == 0 && sbcs.readonaddr) { + sb_read(); + } + return true; + case DMI_SBADDRESS1: + sbaddress[1] = value; + return true; + case DMI_SBADDRESS2: + sbaddress[2] = value; + return true; + case DMI_SBADDRESS3: + sbaddress[3] = value; + return true; + case DMI_SBDATA0: + sbdata[0] = value; + if (sbcs.error == 0) { + sb_write(); + if (sbcs.autoincrement && sbcs.error == 0) { + sb_autoincrement(); + } + } + return true; + case DMI_SBDATA1: + sbdata[1] = value; + return true; + case DMI_SBDATA2: + sbdata[2] = value; + return true; + case DMI_SBDATA3: + sbdata[3] = value; + return true; + case DMI_AUTHDATA: + D(fprintf(stderr, "debug authentication: got 0x%x; 0x%x unlocks\n", value, + challenge + secret)); + if (require_authentication) { + if (value == challenge + secret) { + dmstatus.authenticated = true; + } else { + dmstatus.authenticated = false; + challenge = random(); + } + } + return true; } } return false;