From cd1e73b4eda7ec555f2cb832fe98d618c377ea65 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 12 Jan 2018 15:26:00 -0800 Subject: [PATCH] Support debug system bus access. --- riscv/debug_defines.h | 19 +++++ riscv/debug_module.cc | 191 ++++++++++++++++++++++++++++++++++++++---- riscv/debug_module.h | 24 ++++++ riscv/sim.cc | 7 +- riscv/sim.h | 9 +- 5 files changed, 230 insertions(+), 20 deletions(-) diff --git a/riscv/debug_defines.h b/riscv/debug_defines.h index 58826f0..0d843b0 100644 --- a/riscv/debug_defines.h +++ b/riscv/debug_defines.h @@ -1041,8 +1041,27 @@ #define DMI_AUTHDATA_DATA_OFFSET 0 #define DMI_AUTHDATA_DATA_LENGTH 32 #define DMI_AUTHDATA_DATA (0xffffffffU << DMI_AUTHDATA_DATA_OFFSET) +#define DMI_SBADDRESS3 0x37 +/* +* Accesses bits 127:96 of the physical address in {\tt sbaddress} (if +* the system address bus is that wide). + */ +#define DMI_SBADDRESS3_ADDRESS_OFFSET 0 +#define DMI_SBADDRESS3_ADDRESS_LENGTH 32 +#define DMI_SBADDRESS3_ADDRESS (0xffffffffU << DMI_SBADDRESS3_ADDRESS_OFFSET) #define DMI_SBCS 0x38 /* +* 0: The System Bus interface conforms to mainline drafts of this +* spec older than 1 January, 2018. +* +* 1: The System Bus interface conforms to this version of the spec. +* +* Other values are reserved for future versions. + */ +#define DMI_SBCS_VERSION_OFFSET 29 +#define DMI_SBCS_VERSION_LENGTH 3 +#define DMI_SBCS_VERSION (0x7U << DMI_SBCS_VERSION_OFFSET) +/* * When a 1, every write to \Rsbaddresszero automatically triggers a * system bus read at the new address. */ diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 981e991..2bc480a 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -23,18 +23,6 @@ debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize) : debug_abstract_start(debug_progbuf_start - debug_abstract_size*4), sim(sim) { - dmcontrol = {0}; - - dmstatus = {0}; - dmstatus.impebreak = true; - dmstatus.authenticated = 1; - dmstatus.version = 2; - - abstractcs = {0}; - abstractcs.progbufsize = progbufsize; - - abstractauto = {0}; - program_buffer = new uint8_t[program_buffer_bytes]; memset(halted, 0, sizeof(halted)); @@ -51,6 +39,8 @@ debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize) : jal(ZERO, debug_abstract_start - DEBUG_ROM_WHERETO)); memset(debug_abstract, 0, sizeof(debug_abstract)); + + reset(); } debug_module_t::~debug_module_t() @@ -78,6 +68,14 @@ void debug_module_t::reset() abstractcs.progbufsize = progbufsize; abstractauto = {0}; + + sbcs = {0}; + sbcs.version = 1; + sbcs.access64 = true; + sbcs.access32 = true; + sbcs.access16 = true; + sbcs.access8 = true; + sbcs.asize = sizeof(reg_t) * 8; } void debug_module_t::add_device(bus_t *bus) { @@ -228,6 +226,87 @@ 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) + 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]; + D(fprintf(stderr, "sb_read() @ 0x%lx\n", address)); + try { + switch (sbcs.sbaccess) { + case 0: + sbdata[0] = sim->debug_mmu->load_uint8(address); + break; + case 1: + sbdata[0] = sim->debug_mmu->load_uint16(address); + break; + case 2: + sbdata[0] = sim->debug_mmu->load_uint32(address); + D(fprintf(stderr, " -> 0x%x\n", sbdata[0])); + break; + case 3: + { + uint64_t value = sim->debug_mmu->load_uint32(address); + sbdata[0] = value; + sbdata[1] = value >> 32; + break; + } + default: + sbcs.error = 3; + break; + } + } 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)); + switch (sbcs.sbaccess) { + case 0: + sim->debug_mmu->store_uint8(address, sbdata[0]); + break; + case 1: + sim->debug_mmu->store_uint16(address, sbdata[0]); + break; + case 2: + sim->debug_mmu->store_uint32(address, sbdata[0]); + break; + case 3: + sim->debug_mmu->store_uint64(address, + (((uint64_t) sbdata[1]) << 32) | sbdata[0]); + break; + default: + sbcs.error = 3; + break; + } +} + bool debug_module_t::dmi_read(unsigned address, uint32_t *value) { uint32_t result = 0; @@ -343,6 +422,50 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) result = set_field(result, DMI_HARTINFO_DATASIZE, abstractcs.datacount); result = set_field(result, DMI_HARTINFO_DATAADDR, debug_data_start); break; + case DMI_SBCS: + result = set_field(result, DMI_SBCS_VERSION, sbcs.version); + result = set_field(result, DMI_SBCS_SBREADONADDR, sbcs.readonaddr); + result = set_field(result, DMI_SBCS_SBACCESS, sbcs.sbaccess); + result = set_field(result, DMI_SBCS_SBAUTOINCREMENT, sbcs.autoincrement); + result = set_field(result, DMI_SBCS_SBREADONDATA, sbcs.readondata); + result = set_field(result, DMI_SBCS_SBERROR, sbcs.error); + result = set_field(result, DMI_SBCS_SBASIZE, sbcs.asize); + result = set_field(result, DMI_SBCS_SBACCESS128, sbcs.access128); + result = set_field(result, DMI_SBCS_SBACCESS64, sbcs.access64); + result = set_field(result, DMI_SBCS_SBACCESS32, sbcs.access32); + result = set_field(result, DMI_SBCS_SBACCESS16, sbcs.access16); + result = set_field(result, DMI_SBCS_SBACCESS8, sbcs.access8); + break; + case DMI_SBADDRESS0: + result = sbaddress[0]; + break; + case DMI_SBADDRESS1: + result = sbaddress[1]; + break; + case DMI_SBADDRESS2: + result = sbaddress[2]; + break; + case DMI_SBADDRESS3: + result = sbaddress[3]; + break; + case DMI_SBDATA0: + result = sbdata[0]; + if (sbcs.error == 0) { + sb_autoincrement(); + if (sbcs.readondata) { + sb_read(); + } + } + break; + case DMI_SBDATA1: + result = sbdata[1]; + break; + case DMI_SBDATA2: + result = sbdata[2]; + break; + case DMI_SBDATA3: + result = sbdata[3]; + break; default: result = 0; D(fprintf(stderr, "Unexpected. Returning Error.")); @@ -462,6 +585,8 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) switch (address) { case DMI_DMCONTROL: { + if (!dmcontrol.dmactive && get_field(value, DMI_DMCONTROL_DMACTIVE)) + reset(); dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE); if (dmcontrol.dmactive) { dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ); @@ -469,8 +594,6 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) 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(); } processor_t *proc = current_proc(); if (proc) { @@ -506,6 +629,46 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) 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; } } return false; diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 00c66cc..be9b8bc 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -56,6 +56,21 @@ typedef struct { unsigned autoexecdata; } abstractauto_t; +typedef struct { + unsigned version; + bool readonaddr; + unsigned sbaccess; + bool autoincrement; + bool readondata; + unsigned error; + unsigned asize; + bool access128; + bool access64; + bool access32; + bool access16; + bool access8; +} sbcs_t; + class debug_module_t : public abstract_device_t { public: @@ -101,12 +116,21 @@ class debug_module_t : public abstract_device_t void write32(uint8_t *rom, unsigned int index, uint32_t value); uint32_t read32(uint8_t *rom, unsigned int index); + void sb_autoincrement(); + void sb_read(); + void sb_write(); + unsigned sb_access_bits(); + dmcontrol_t dmcontrol; dmstatus_t dmstatus; abstractcs_t abstractcs; abstractauto_t abstractauto; uint32_t command; + sbcs_t sbcs; + uint32_t sbaddress[4]; + uint32_t sbdata[4]; + processor_t *current_proc() const; void reset(); bool perform_abstract_command(); diff --git a/riscv/sim.cc b/riscv/sim.cc index 81d1307..97697e4 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -27,10 +27,9 @@ sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc, std::vector> mems, const std::vector& args, std::vector const hartids, unsigned progsize) - : htif_t(args), debug_module(this, progsize), mems(mems), - procs(std::max(nprocs, size_t(1))), - start_pc(start_pc), - current_step(0), current_proc(0), debug(false), remote_bitbang(NULL) + : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))), + start_pc(start_pc), current_step(0), current_proc(0), debug(false), + remote_bitbang(NULL), debug_module(this, progsize) { signal(SIGINT, &handle_signal); diff --git a/riscv/sim.h b/riscv/sim.h index ce5fe19..e29cca4 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -38,8 +38,6 @@ public: processor_t* get_core(size_t i) { return procs.at(i); } unsigned nprocs() const { return procs.size(); } - debug_module_t debug_module; - private: std::vector> mems; mmu_t* debug_mmu; // debug port into main memory @@ -92,6 +90,7 @@ private: friend class processor_t; friend class mmu_t; + friend class debug_module_t; // htif friend void sim_thread_main(void*); @@ -105,6 +104,12 @@ private: void write_chunk(addr_t taddr, size_t len, const void* src); size_t chunk_align() { return 8; } size_t chunk_max_size() { return 8; } + +public: + // Initialize this after procs, because in debug_module_t::reset() we + // enumerate processors, which segfaults if procs hasn't been initialized + // yet. + debug_module_t debug_module; }; extern volatile bool ctrlc_pressed; -- 2.30.2