diff options
author | Tim Newsome <tim@sifive.com> | 2018-02-19 11:55:19 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-19 11:55:19 -0800 |
commit | c746388b542eacd2586acfbc0a742b08a5c0bd6f (patch) | |
tree | 2f933877da643a4ba9e72fb169869e2e6e634a0d | |
parent | 4c1c92f59f7b021eb2fa3b373b60f0e8b7c08a17 (diff) | |
parent | b2672e5d5271b346a71ec33ab42c88437b9b60d1 (diff) | |
download | riscv-isa-sim-c746388b542eacd2586acfbc0a742b08a5c0bd6f.zip riscv-isa-sim-c746388b542eacd2586acfbc0a742b08a5c0bd6f.tar.gz riscv-isa-sim-c746388b542eacd2586acfbc0a742b08a5c0bd6f.tar.bz2 |
Merge pull request #171 from riscv/sysbusbits
Add support for debug bus mastering
-rw-r--r-- | riscv/debug_defines.h | 143 | ||||
-rw-r--r-- | riscv/debug_module.cc | 190 | ||||
-rw-r--r-- | riscv/debug_module.h | 29 | ||||
-rw-r--r-- | riscv/sim.cc | 10 | ||||
-rw-r--r-- | riscv/sim.h | 11 | ||||
-rw-r--r-- | spike_main/spike.cc | 7 |
6 files changed, 299 insertions, 91 deletions
diff --git a/riscv/debug_defines.h b/riscv/debug_defines.h index 1d3e1c0..04500e5 100644 --- a/riscv/debug_defines.h +++ b/riscv/debug_defines.h @@ -295,7 +295,7 @@ * * Other values are reserved for future use. */ -#define CSR_TDATA1_TYPE_OFFSET XLEN-4 +#define CSR_TDATA1_TYPE_OFFSET (XLEN-4) #define CSR_TDATA1_TYPE_LENGTH 4 #define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET) /* @@ -307,14 +307,14 @@ * * This bit is only writable from Debug Mode. */ -#define CSR_TDATA1_DMODE_OFFSET XLEN-5 +#define CSR_TDATA1_DMODE_OFFSET (XLEN-5) #define CSR_TDATA1_DMODE_LENGTH 1 #define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET) /* * Trigger-specific data. */ #define CSR_TDATA1_DATA_OFFSET 0 -#define CSR_TDATA1_DATA_LENGTH XLEN - 5 +#define CSR_TDATA1_DATA_LENGTH (XLEN - 5) #define CSR_TDATA1_DATA (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET) #define CSR_TDATA2 0x7a2 #define CSR_TDATA2_DATA_OFFSET 0 @@ -325,10 +325,10 @@ #define CSR_TDATA3_DATA_LENGTH XLEN #define CSR_TDATA3_DATA (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET) #define CSR_MCONTROL 0x7a1 -#define CSR_MCONTROL_TYPE_OFFSET XLEN-4 +#define CSR_MCONTROL_TYPE_OFFSET (XLEN-4) #define CSR_MCONTROL_TYPE_LENGTH 4 #define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET) -#define CSR_MCONTROL_DMODE_OFFSET XLEN-5 +#define CSR_MCONTROL_DMODE_OFFSET (XLEN-5) #define CSR_MCONTROL_DMODE_LENGTH 1 #define CSR_MCONTROL_DMODE (0x1ULL << CSR_MCONTROL_DMODE_OFFSET) /* @@ -339,7 +339,7 @@ * corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in * size. */ -#define CSR_MCONTROL_MASKMAX_OFFSET XLEN-11 +#define CSR_MCONTROL_MASKMAX_OFFSET (XLEN-11) #define CSR_MCONTROL_MASKMAX_LENGTH 6 #define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET) /* @@ -441,12 +441,6 @@ #define CSR_MCONTROL_M_LENGTH 1 #define CSR_MCONTROL_M (0x1ULL << CSR_MCONTROL_M_OFFSET) /* -* When set, enable this trigger in H mode. - */ -#define CSR_MCONTROL_H_OFFSET 5 -#define CSR_MCONTROL_H_LENGTH 1 -#define CSR_MCONTROL_H (0x1ULL << CSR_MCONTROL_H_OFFSET) -/* * When set, enable this trigger in S mode. */ #define CSR_MCONTROL_S_OFFSET 4 @@ -478,16 +472,16 @@ #define CSR_MCONTROL_LOAD_LENGTH 1 #define CSR_MCONTROL_LOAD (0x1ULL << CSR_MCONTROL_LOAD_OFFSET) #define CSR_ICOUNT 0x7a1 -#define CSR_ICOUNT_TYPE_OFFSET XLEN-4 +#define CSR_ICOUNT_TYPE_OFFSET (XLEN-4) #define CSR_ICOUNT_TYPE_LENGTH 4 #define CSR_ICOUNT_TYPE (0xfULL << CSR_ICOUNT_TYPE_OFFSET) -#define CSR_ICOUNT_DMODE_OFFSET XLEN-5 +#define CSR_ICOUNT_DMODE_OFFSET (XLEN-5) #define CSR_ICOUNT_DMODE_LENGTH 1 #define CSR_ICOUNT_DMODE (0x1ULL << CSR_ICOUNT_DMODE_OFFSET) /* * When count is decremented to 0, the trigger fires. Instead of * changing \Fcount from 1 to 0, it is also acceptable for hardware to -* clear \Fm, \Fh, \Fs, and \Fu. This allows \Fcount to be hard-wired +* clear \Fm, \Fs, and \Fu. This allows \Fcount to be hard-wired * to 1 if this register just exists for single step. */ #define CSR_ICOUNT_COUNT_OFFSET 10 @@ -501,13 +495,6 @@ #define CSR_ICOUNT_M_LENGTH 1 #define CSR_ICOUNT_M (0x1ULL << CSR_ICOUNT_M_OFFSET) /* -* When set, every instruction completed or exception taken in in H mode decrements \Fcount -* by 1. - */ -#define CSR_ICOUNT_H_OFFSET 8 -#define CSR_ICOUNT_H_LENGTH 1 -#define CSR_ICOUNT_H (0x1ULL << CSR_ICOUNT_H_OFFSET) -/* * When set, every instruction completed or exception taken in S mode decrements \Fcount * by 1. */ @@ -544,19 +531,6 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* -* Gets set if the Debug Module was accessed incorrectly. -* -* 0 (none): No error. -* -* 1 (badaddr): There was an access to an unimplemented Debug Module -* address. -* -* 7 (other): An access failed for another reason. - */ -#define DMI_DMSTATUS_DMERR_OFFSET 24 -#define DMI_DMSTATUS_DMERR_LENGTH 3 -#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) -/* * If 1, then there is an implicit {\tt ebreak} instruction at the * non-existent word immediately after the Program Buffer. This saves * the debugger from having to write the {\tt ebreak} itself, and @@ -700,7 +674,7 @@ */ #define DMI_DMCONTROL_HALTREQ_OFFSET 31 #define DMI_DMCONTROL_HALTREQ_LENGTH 1 -#define DMI_DMCONTROL_HALTREQ (0x1U << DMI_DMCONTROL_HALTREQ_OFFSET) +#define DMI_DMCONTROL_HALTREQ (0x1ULL << DMI_DMCONTROL_HALTREQ_OFFSET) /* * Writes the resume request bit for all currently selected harts. * When set to 1, each selected hart will resume if it is currently @@ -713,7 +687,7 @@ */ #define DMI_DMCONTROL_RESUMEREQ_OFFSET 30 #define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 -#define DMI_DMCONTROL_RESUMEREQ (0x1U << DMI_DMCONTROL_RESUMEREQ_OFFSET) +#define DMI_DMCONTROL_RESUMEREQ (0x1ULL << DMI_DMCONTROL_RESUMEREQ_OFFSET) /* * This optional field writes the reset bit for all the currently * selected harts. To perform a reset the debugger writes 1, and then @@ -727,7 +701,7 @@ */ #define DMI_DMCONTROL_HARTRESET_OFFSET 29 #define DMI_DMCONTROL_HARTRESET_LENGTH 1 -#define DMI_DMCONTROL_HARTRESET (0x1U << DMI_DMCONTROL_HARTRESET_OFFSET) +#define DMI_DMCONTROL_HARTRESET (0x1ULL << DMI_DMCONTROL_HARTRESET_OFFSET) /* * Writing 1 to this bit clears the {\tt havereset} bits for * any selected harts. @@ -736,7 +710,7 @@ */ #define DMI_DMCONTROL_ACKHAVERESET_OFFSET 28 #define DMI_DMCONTROL_ACKHAVERESET_LENGTH 1 -#define DMI_DMCONTROL_ACKHAVERESET (0x1U << DMI_DMCONTROL_ACKHAVERESET_OFFSET) +#define DMI_DMCONTROL_ACKHAVERESET (0x1ULL << DMI_DMCONTROL_ACKHAVERESET_OFFSET) /* * Selects the definition of currently selected harts. * @@ -752,14 +726,14 @@ */ #define DMI_DMCONTROL_HASEL_OFFSET 26 #define DMI_DMCONTROL_HASEL_LENGTH 1 -#define DMI_DMCONTROL_HASEL (0x1U << DMI_DMCONTROL_HASEL_OFFSET) +#define DMI_DMCONTROL_HASEL (0x1ULL << DMI_DMCONTROL_HASEL_OFFSET) /* * The DM-specific index of the hart to select. This hart is always part of the * currently selected harts. */ #define DMI_DMCONTROL_HARTSEL_OFFSET 16 -#define DMI_DMCONTROL_HARTSEL_LENGTH 10 -#define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET) +#define DMI_DMCONTROL_HARTSEL_LENGTH HARTSELLEN +#define DMI_DMCONTROL_HARTSEL (((1L<<HARTSELLEN)-1) << DMI_DMCONTROL_HARTSEL_OFFSET) /* * This bit controls the reset signal from the DM to the rest of the * system. The signal should reset every part of the system, including @@ -771,7 +745,7 @@ */ #define DMI_DMCONTROL_NDMRESET_OFFSET 1 #define DMI_DMCONTROL_NDMRESET_LENGTH 1 -#define DMI_DMCONTROL_NDMRESET (0x1U << DMI_DMCONTROL_NDMRESET_OFFSET) +#define DMI_DMCONTROL_NDMRESET (0x1ULL << DMI_DMCONTROL_NDMRESET_OFFSET) /* * This bit serves as a reset signal for the Debug Module itself. * @@ -794,7 +768,7 @@ */ #define DMI_DMCONTROL_DMACTIVE_OFFSET 0 #define DMI_DMCONTROL_DMACTIVE_LENGTH 1 -#define DMI_DMCONTROL_DMACTIVE (0x1U << DMI_DMCONTROL_DMACTIVE_OFFSET) +#define DMI_DMCONTROL_DMACTIVE (0x1ULL << DMI_DMCONTROL_DMACTIVE_OFFSET) #define DMI_HARTINFO 0x12 /* * Number of {\tt dscratch} registers available for the debugger @@ -822,6 +796,9 @@ * * If \Fdataaccess is 1: Number of 32-bit words in the memory map * dedicated to shadowing the {\tt data} registers. +* +* Since there are at most 12 {\tt data} registers, the value in this +* register must be 12 or smaller. */ #define DMI_HARTINFO_DATASIZE_OFFSET 12 #define DMI_HARTINFO_DATASIZE_LENGTH 4 @@ -988,8 +965,8 @@ * abstract command interface. Valid sizes are 0 - 12. */ #define DMI_ABSTRACTCS_DATACOUNT_OFFSET 0 -#define DMI_ABSTRACTCS_DATACOUNT_LENGTH 5 -#define DMI_ABSTRACTCS_DATACOUNT (0x1fU << DMI_ABSTRACTCS_DATACOUNT_OFFSET) +#define DMI_ABSTRACTCS_DATACOUNT_LENGTH 4 +#define DMI_ABSTRACTCS_DATACOUNT (0xfU << DMI_ABSTRACTCS_DATACOUNT_OFFSET) #define DMI_COMMAND 0x17 /* * The type determines the overall functionality of this @@ -1007,14 +984,14 @@ #define DMI_COMMAND_CONTROL (0xffffffU << DMI_COMMAND_CONTROL_OFFSET) #define DMI_ABSTRACTAUTO 0x18 /* -* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word +* When a bit in this field is 1, read or write accesses to the corresponding {\tt progbuf} word * cause the command in \Rcommand to be executed again. */ #define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 16 #define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 16 #define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF (0xffffU << DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET) /* -* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word +* When a bit in this field is 1, read or write accesses to the corresponding {\tt data} word * cause the command in \Rcommand to be executed again. */ #define DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0 @@ -1041,17 +1018,59 @@ #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 /* -* When a 1 is written here, triggers a read at the address in {\tt -* sbaddress} using the access size set by \Fsbaccess. +* 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_SBVERSION_OFFSET 29 +#define DMI_SBCS_SBVERSION_LENGTH 3 +#define DMI_SBCS_SBVERSION (0x7U << DMI_SBCS_SBVERSION_OFFSET) +/* +* Set when the debugger attempts to read data while a read is in +* progress, or when the debugger initiates a new access while one is +* already in progress (while \Fsbbusy is set). It remains set until +* it's explicitly cleared by the debugger. +* +* While this field is non-zero, no more system bus accesses can be +* initiated by the debug module. + */ +#define DMI_SBCS_SBBUSYERROR_OFFSET 22 +#define DMI_SBCS_SBBUSYERROR_LENGTH 1 +#define DMI_SBCS_SBBUSYERROR (0x1U << DMI_SBCS_SBBUSYERROR_OFFSET) +/* +* When 1, indicates the system bus master is busy. (Whether the +* system bus itself is busy is related, but not the same thing.) This +* bit goes high immediately when a read or write is requested for any +* reason, and does not go low until the access is fully completed. +* +* To avoid race conditions, debuggers must not try to clear \Fsberror +* until they read \Fsbbusy as 0. */ -#define DMI_SBCS_SBSINGLEREAD_OFFSET 20 -#define DMI_SBCS_SBSINGLEREAD_LENGTH 1 -#define DMI_SBCS_SBSINGLEREAD (0x1U << DMI_SBCS_SBSINGLEREAD_OFFSET) +#define DMI_SBCS_SBBUSY_OFFSET 21 +#define DMI_SBCS_SBBUSY_LENGTH 1 +#define DMI_SBCS_SBBUSY (0x1U << DMI_SBCS_SBBUSY_OFFSET) /* -* Select the access size to use for system bus accesses triggered by -* writes to the {\tt sbaddress} registers or \Rsbdatazero. +* When 1, every write to \Rsbaddresszero automatically triggers a +* system bus read at the new address. + */ +#define DMI_SBCS_SBREADONADDR_OFFSET 20 +#define DMI_SBCS_SBREADONADDR_LENGTH 1 +#define DMI_SBCS_SBREADONADDR (0x1U << DMI_SBCS_SBREADONADDR_OFFSET) +/* +* Select the access size to use for system bus accesses. * * 0: 8-bit * @@ -1063,8 +1082,8 @@ * * 4: 128-bit * -* If an unsupported system bus access size is written here, the DM -* does not perform the access and sberror is set to 3. +* If \Fsbaccess has an unsupported value when the DM starts a bus +* access, the access is not performed and \Fsberror is set to 3. */ #define DMI_SBCS_SBACCESS_OFFSET 17 #define DMI_SBCS_SBACCESS_LENGTH 3 @@ -1080,9 +1099,9 @@ * When 1, every read from \Rsbdatazero automatically triggers a * system bus read at the (possibly auto-incremented) address. */ -#define DMI_SBCS_SBAUTOREAD_OFFSET 15 -#define DMI_SBCS_SBAUTOREAD_LENGTH 1 -#define DMI_SBCS_SBAUTOREAD (0x1U << DMI_SBCS_SBAUTOREAD_OFFSET) +#define DMI_SBCS_SBREADONDATA_OFFSET 15 +#define DMI_SBCS_SBREADONDATA_LENGTH 1 +#define DMI_SBCS_SBREADONDATA (0x1U << DMI_SBCS_SBREADONDATA_OFFSET) /* * When the debug module's system bus * master causes a bus error, this field gets set. The bits in this @@ -1097,10 +1116,6 @@ * 2: A bad address was accessed. * * 3: There was some other error (eg. alignment). -* -* 4: The system bus master was busy when one of the -* {\tt sbaddress} or {\tt sbdata} registers was written, -* or \Rsbdatazero was read when it had stale data. */ #define DMI_SBCS_SBERROR_OFFSET 12 #define DMI_SBCS_SBERROR_LENGTH 3 diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 981e991..12956a5 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -16,25 +16,14 @@ ///////////////////////// debug_module_t -debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize) : +debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits) : progbufsize(progbufsize), program_buffer_bytes(4 + 4*progbufsize), + max_bus_master_bits(max_bus_master_bits), 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.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 +40,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 +69,20 @@ void debug_module_t::reset() 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; } void debug_module_t::add_device(bus_t *bus) { @@ -228,6 +233,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; @@ -268,7 +338,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<<hartsellen)-1) << + DMI_DMCONTROL_HARTSEL_OFFSET, dmcontrol.hartsel); result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset); result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset); result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive); @@ -343,6 +414,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_SBVERSION, 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,15 +577,16 @@ 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); 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<<hartsellen)-1) << + DMI_DMCONTROL_HARTSEL_OFFSET); } processor_t *proc = current_proc(); if (proc) { @@ -506,6 +622,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..36037b4 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -56,10 +56,25 @@ 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: - debug_module_t(sim_t *sim, unsigned progbufsize); + debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits); ~debug_module_t(); void add_device(bus_t *bus); @@ -81,12 +96,15 @@ class debug_module_t : public abstract_device_t // Actual size of the program buffer, which is 1 word bigger than we let on // to implement the implicit ebreak at the end. unsigned program_buffer_bytes; + unsigned max_bus_master_bits ; static const unsigned debug_data_start = 0x380; unsigned debug_progbuf_start; static const unsigned debug_abstract_size = 2; unsigned debug_abstract_start; + static const unsigned hartsellen = 10; + sim_t *sim; uint8_t debug_rom_whereto[4]; @@ -101,12 +119,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..009bb98 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -26,11 +26,11 @@ static void handle_signal(int sig) sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc, std::vector<std::pair<reg_t, mem_t*>> mems, const std::vector<std::string>& args, - std::vector<int> 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) + std::vector<int> const hartids, unsigned progsize, + unsigned max_bus_master_bits) + : 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, max_bus_master_bits) { signal(SIGINT, &handle_signal); diff --git a/riscv/sim.h b/riscv/sim.h index ce5fe19..47f3a45 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -22,7 +22,7 @@ public: sim_t(const char* isa, size_t _nprocs, bool halted, reg_t start_pc, std::vector<std::pair<reg_t, mem_t*>> mems, const std::vector<std::string>& args, const std::vector<int> hartids, - unsigned progsize); + unsigned progsize, unsigned max_bus_master_bits); ~sim_t(); // run the simulation to completion @@ -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<std::pair<reg_t, mem_t*>> 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; diff --git a/spike_main/spike.cc b/spike_main/spike.cc index d3caa22..f77d488 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -37,6 +37,8 @@ static void help() fprintf(stderr, " --rbb-port=<port> Listen on <port> for remote bitbang connection\n"); fprintf(stderr, " --dump-dts Print device tree string and exit\n"); fprintf(stderr, " --progsize=<words> progsize for the debug module [default 2]\n"); + fprintf(stderr, " --debug-sba=<bits> debug bus master supports up to " + "<bits> wide accesses [default 0]\n"); exit(1); } @@ -89,6 +91,7 @@ int main(int argc, char** argv) uint16_t rbb_port = 0; bool use_rbb = false; unsigned progsize = 2; + unsigned max_bus_master_bits = 0; std::vector<int> hartids; auto const hartids_parser = [&](const char *s) { @@ -130,6 +133,8 @@ int main(int argc, char** argv) } }); parser.option(0, "progsize", 1, [&](const char* s){progsize = atoi(s);}); + parser.option(0, "debug-sba", 1, + [&](const char* s){max_bus_master_bits = atoi(s);}); auto argv1 = parser.parse(argv); std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc); @@ -137,7 +142,7 @@ int main(int argc, char** argv) mems = make_mems("2048"); sim_t s(isa, nprocs, halted, start_pc, mems, htif_args, std::move(hartids), - progsize); + progsize, max_bus_master_bits); std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL); std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module)); if (use_rbb) { |