From 4df7f6d279314ccf78d14c482a9f04e49e0e0b47 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 15 Feb 2017 15:45:20 -0800 Subject: [PATCH] Implement resume (untested). --- riscv/debug_defines.h | 75 ++++++++++++++++++++++++++----------------- riscv/debug_module.cc | 15 ++++++++- riscv/debug_module.h | 1 + riscv/opcodes.h | 3 ++ 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/riscv/debug_defines.h b/riscv/debug_defines.h index 59fa344..2a78bdf 100644 --- a/riscv/debug_defines.h +++ b/riscv/debug_defines.h @@ -28,11 +28,11 @@ #define AC_ACCESS_REGISTER_POSTEXEC_LENGTH 1 #define AC_ACCESS_REGISTER_POSTEXEC (0x1 << AC_ACCESS_REGISTER_POSTEXEC_OFFSET) /* -* 0: Copy data from \Rdatazero into the specified register. +* 0: Copy data from {\tt arg0} portion of {\tt data} into the +* specified register. * -* 1: Copy data from the specified register into \Rdatazero. -* -* (If XLEN is greater than 32, more {\tt data} registers are involved.) +* 1: Copy data from the specified register into {\tt arg0} portion +* of {\tt data}. */ #define AC_ACCESS_REGISTER_WRITE_OFFSET 16 #define AC_ACCESS_REGISTER_WRITE_LENGTH 1 @@ -169,37 +169,25 @@ #define CSR_PRIV_PRV (0x3 << CSR_PRIV_PRV_OFFSET) #define DMI_DMCONTROL 0x00 /* -* Halt request signal for the hart selected by \Fhartsel. Writes -* apply to the new value of \Fhartsel. +* Halt request signal for the hart selected by \Fhartsel. When 1, the +* hart will halt if it's not currently halted. +* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. +* +* Writes apply to the new value of \Fhartsel. */ #define DMI_DMCONTROL_HALTREQ_OFFSET 31 #define DMI_DMCONTROL_HALTREQ_LENGTH 1 #define DMI_DMCONTROL_HALTREQ (0x1 << DMI_DMCONTROL_HALTREQ_OFFSET) /* -* This bit controls the reset signal from the DM to the rest of the -* system. To perform a reset the debugger writes 1, and then writes 0 -* to deassert the reset. - */ -#define DMI_DMCONTROL_RESET_OFFSET 30 -#define DMI_DMCONTROL_RESET_LENGTH 1 -#define DMI_DMCONTROL_RESET (0x1 << DMI_DMCONTROL_RESET_OFFSET) -/* -* This bit serves as a reset signal for the Debug Module itself. -* When 0, the module is held in reset. When 1, it functions normally. -* No other mechanism should exist that may result in resetting the -* Debug Module after power up, including the platform's system reset -* or Debug Transport reset signals. -* -* A debugger should pulse this bit low to ensure that the Debug -* Module is fully reset and ready to use. +* Resume request signal for the hart selected by \Fhartsel. When 1, +* the hart will resume if it's currently halted. +* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. * -* Implementations may use this bit to aid debugging, for example by -* preventing the Debug Module from being power gated while debugging -* is active. +* Writes apply to the new value of \Fhartsel. */ -#define DMI_DMCONTROL_DMACTIVE_OFFSET 29 -#define DMI_DMCONTROL_DMACTIVE_LENGTH 1 -#define DMI_DMCONTROL_DMACTIVE (0x1 << DMI_DMCONTROL_DMACTIVE_OFFSET) +#define DMI_DMCONTROL_RESUMEREQ_OFFSET 30 +#define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 +#define DMI_DMCONTROL_RESUMEREQ (0x1 << DMI_DMCONTROL_RESUMEREQ_OFFSET) /* * The status of the currently selected hart. * @@ -221,6 +209,31 @@ #define DMI_DMCONTROL_HARTSEL_LENGTH 10 #define DMI_DMCONTROL_HARTSEL (0x3ff << DMI_DMCONTROL_HARTSEL_OFFSET) /* +* This bit serves as a reset signal for the Debug Module itself. +* When 0, the module is held in reset. When 1, it functions normally. +* No other mechanism should exist that may result in resetting the +* Debug Module after power up, including the platform's system reset +* or Debug Transport reset signals. +* +* A debugger should pulse this bit low to ensure that the Debug +* Module is fully reset and ready to use. +* +* Implementations may use this bit to aid debugging, for example by +* preventing the Debug Module from being power gated while debugging +* is active. + */ +#define DMI_DMCONTROL_DMACTIVE_OFFSET 9 +#define DMI_DMCONTROL_DMACTIVE_LENGTH 1 +#define DMI_DMCONTROL_DMACTIVE (0x1 << DMI_DMCONTROL_DMACTIVE_OFFSET) +/* +* This bit controls the reset signal from the DM to the rest of the +* system. To perform a reset the debugger writes 1, and then writes 0 +* to deassert the reset. + */ +#define DMI_DMCONTROL_RESET_OFFSET 8 +#define DMI_DMCONTROL_RESET_LENGTH 1 +#define DMI_DMCONTROL_RESET (0x1 << DMI_DMCONTROL_RESET_OFFSET) +/* * 0 when authentication is required before using the DM. 1 when the * authentication check has passed. On components that don't implement * authentication, this bit must be preset as 1. @@ -450,8 +463,10 @@ * * 3: There was some other error (eg. alignment). * -* 4: The system bus master was busy when a one of the {\tt sbaddress} or -* {\tt sbdata} registers was written. +* 4: The system bus master was busy when a one of the +* {\tt sbaddress} or {\tt sbdata} registers was written, +* or the {\tt sbdata} register 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 f672a89..df3f1f9 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -111,7 +111,7 @@ void debug_module_t::add_device(bus_t *bus) { bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) { - D(fprintf(stderr, "load 0x%lx bytes at 0x%lx\n", + D(fprintf(stderr, "debug_module_t load 0x%lx bytes at 0x%lx\n", len, addr)); addr = DEBUG_START + addr; @@ -140,6 +140,12 @@ bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) if (addr >= DEBUG_ROM_CODE && addr < DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE) { + + if (read32(debug_rom_code, 0) == dret()) { + abstractcs.busy = false; + halted[dmcontrol.hartsel] = false; + } + memcpy(bytes, debug_rom_code + addr - DEBUG_ROM_CODE, len); return true; } @@ -363,6 +369,7 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) 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.reset = get_field(value, DMI_DMCONTROL_RESET); dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL); } else { @@ -371,6 +378,12 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value) processor_t *proc = current_proc(); if (proc) { proc->halt_request = dmcontrol.haltreq; + if (dmcontrol.resumereq) { + write32(debug_rom_code, 0, dret()); + write32(debug_rom_entry, dmcontrol.hartsel, + jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel))); + abstractcs.busy = true; + } } } return true; diff --git a/riscv/debug_module.h b/riscv/debug_module.h index fdeaaac..7d9b3aa 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -10,6 +10,7 @@ class sim_t; typedef struct { bool haltreq; + bool resumereq; bool reset; bool dmactive; enum { diff --git a/riscv/opcodes.h b/riscv/opcodes.h index eb76455..34c089e 100644 --- a/riscv/opcodes.h +++ b/riscv/opcodes.h @@ -168,6 +168,9 @@ static uint32_t ebreak(void) { return MATCH_EBREAK; } static uint32_t ebreak_c(void) __attribute__ ((unused)); static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; } +static uint32_t dret(void) __attribute__ ((unused)); +static uint32_t dret(void) { return MATCH_DRET; } + static uint32_t fence_i(void) __attribute__ ((unused)); static uint32_t fence_i(void) { -- 2.30.2