Riscv Debug Specification
Riscv Debug Specification
Specification
Tim Newsome, Paul Donahue (Ventana Micro Systems)
Preface
This specification is Frozen.
Change is extremely unlikely. A high threshold will be used, and a change will only occur
because of some truly critical issue being identified during the public review cycle. Any
other desired or needed changes can be the subject of a follow-on new extension.
Contributors to all versions of the spec in alphabetical order (please contact editors to suggest
corrections): Bruce Ableidinger, Krste Asanović, Peter Ashenden, Allen Baum, Mark Beal, Alex
Bradbury, Chuanhua Chang, Yen Hao Chen, Zhong-Ho Chen, Monte Dalrymple, Paul Donahue,
Vyacheslav Dyachenko, Ernie Edgar, Peter Egold, Marc Gauthier, Markus Goehrle, Robert Golla, John
Hauser, Richard Herveille, Yung-ching Hsiao, Po-wei Huang, Scott Johnson, L. J. Madar, Grigorios
Magklis, Daniel Mangum, Alexis Marquet, Jan Matyas, Kai Meinhard, Jean-Luc Nagel, Aram
Nahidipour, Rishiyur Nikhil, Gajinder Panesar, Deepak Panwar, Antony Pavlov, Klaus Kruse Pedersen,
Ken Pettit, Darius Rad, Joe Rahmeh, Josh Scheid, Vedvyas Shanbhogue, Gavin Stark, Ben Staveley,
Wesley Terpstra, Tommy Thorn, Megan Wachs, Jan-Willem van de Waerdt, Philipp Wagner, Stefan
Wallentowitz, Ray Van De Walker, Andrew Waterman, Thomas Wicki, Andy Wright, Bryan Wyatt, and
Florian Zaruba.
This document is released under a Creative Commons Attribution 4.0 International License.
Chapter 1. Introduction
When a design progresses from simulation to hardware implementation, a user’s control and
understanding of the system’s current state drops dramatically. To help bring up and debug low level
software and hardware, it is critical to have good debugging support built into the hardware. When a
robust OS is running on a core, software can handle many debugging tasks. However, in many
scenarios, hardware support is essential.
This document outlines a standard architecture for debug support on RISC-V hardware platforms.
This architecture allows a variety of implementations and tradeoffs, which is complementary to the
wide range of RISC-V implementations. At the same time, this specification defines common
interfaces to allow debugging tools and components to target a variety of hardware platforms based on
the RISC-V ISA.
System designers may choose to add additional hardware debug support, but this specification defines
a standard interface for common functionality.
1.1. Terminology
advanced feature
An advanced feature for advanced users. Most users will not be able to take advantage of it.
AMO
Atomic Memory Operation.
BYPASS
JTAG instruction that selects a single bit data register, also called BYPASS.
component
A RISC-V core, or other part of a hardware platform. Typically all components will be connected to
a single system bus.
CSR
Control and Status Register.
DM
Debug Module (see Chapter 3).
DMI
Debug Module Interface (see Section 3.1).
DR
JTAG Data Register.
DTM
Debug Transport Module (see Chapter 6).
DXLEN
Debug XLEN, which is the widest XLEN a hart supports, ignoring the current value of mxl in misa.
ELP
Expected landing pad state, define by the Zicfilp extension.
essential feature
An essential feature must be present in order for debug to work correctly.
GPR
General Purpose Register.
hardware platform
A single system consisting of one or more components.
hart
A hardware thread in a RISC-V core.
IDCODE
32-bit Identification CODE, and a JTAG instruction that returns the IDCODE value.
IR
JTAG Instruction Register.
JTAG
Refers to work done by IEEE’s Joint Test Action Group, described in IEEE 1149.1.
legacy feature
A legacy feature should only be implemented to support legacy hardware that is present in a
system.
NAPOT
Naturally Aligned Power-Of-Two.
NMI
Non-Maskable Interrupt.
physical address
address that is directly usable on the system bus.
recommended feature
A recommended feature is not required for debug to work correctly, but it is so useful that it should
not be omitted without good reason.
SBA
System Bus Access (see Section 3.10).
specialized feature
A specialized feature, that only makes sense in the context of some specific hardware.
TAP
Test Access Port, defined in IEEE 1149.1.
TM
Trigger Module (see Chapter 5).
virtual address
An address as a hart sees it. If the hart is using address translation this may be different from the
physical address. If there is no translation then it will be the same.
xepc
The exception program counter CSR (e.g. mepc) that is appropriate for the mode being trapped to.
1.2. Context
This specification attempts to support all RISC-V ISA extensions that have, roughly, been ratified
through the first half of 2023. In particular, though, this specification specifically addresses features
in the following extensions:
1. A
2. C
3. D
4. F
5. H
6. Sm1p13
7. Smstateen
8. Ss1p13
9. V
10. Zawrs
11. Zcmp
12. Zicbom
13. Zicbop
14. Zicboz
15. Zicsr
1.2.1. Versions
Version 0.13 of this document was ratified by the RISC-V Foundation’s board. Versions 0.13. are bug
fix releases to that ratified specification.
Version 0.14 was a working version that was never officially ratified.
Version 1.0 is almost entirely forwards and backwards compatible with Version 0.13.
Changes that are not backwards-compatible. Debuggers or hardware implementations that implement
0.13 will have to change something in order to implement 1.0:
Changes that slightly modify defined behavior. Technically backwards incompatible, but unlikely to
be noticeable:
Backwards-incompatible changes between two versions that are both called 1.0 stable.
1. nmi was moved from etrigger to itrigger, and is now subject to the mode bits in that trigger.
2. #728 introduced Message Registers, which were later removed in #878.
3. It may not be possible to read the contents of the Program Buffer using the progbuf registers. #731
4. tcontrol fields apply to all traps, not just breakpoint traps. This reverts #723. #880
After the graphic follows a table which for each field lists its name, description, allowed accesses, and
reset value. The allowed accesses are listed in Table 1. The reset value is either a constant or "Preset."
The latter means it is an implementation-specific legal value.
Parts of the register which are currently unused are labeled with the number 0. Software must only
write 0 to those fields, and ignore their value while reading. Hardware must return 0 when those fields
are read, and ignore the value written to them.
This behavior enables us to use those fields later without having to increase the values in
the version fields.
Names of registers and their fields are hyperlinks to their definition, and are also listed in the Index.
0 field
24 8
1.4. Background
There are several use cases for dedicated debugging hardware, both in native debug and external
debug. Native debug (sometimes called self-hosted debug) refers to debug software running on a RISC-
V platform which debugs the same platform. The optional Trigger Module provides features that are
useful for native debug. External debug refers to debug software running somewhere else, debugging
the RISC-V platform via a debug transport like JTAG. The entire document provides features that are
useful for external debug.
This specification addresses the use cases listed below. Implementations can choose not to implement
every feature, which means some use cases might not be supported.
2. Memory can be accessed either from the hart’s point of view, through the system bus directly, or
both.
3. RV32, RV64, and future RV128 are all supported.
4. Any hart in the hardware platform can be independently debugged.
5. A debugger can discover almost [1] everything it needs to know itself, without user configuration.
6. Each hart can be debugged from the very first instruction executed.
7. A RISC-V hart can be halted when a software breakpoint instruction is executed.
8. Hardware single-step can execute one instruction at a time.
9. Debug functionality is independent of the debug transport used.
10. The debugger does not need to know anything about the microarchitecture of the harts it is
debugging.
11. Arbitrary subsets of harts can be halted and resumed simultaneously. (Optional)
12. Arbitrary instructions can be executed on a halted hart. That means no new debug functionality is
needed when a core has additional or custom instructions or state, as long as there exist programs
that can move that state into GPRs. (Optional)
13. Registers can be accessed without halting. (Optional)
14. A running hart can be directed to execute a short sequence of instructions, with little overhead.
(Optional)
15. A system bus manager allows memory access without involving any hart. (Optional)
16. A RISC-V hart can be halted when a trigger matches the PC, read/write address/data, or an
instruction opcode. (Optional)
17. Harts can be grouped, and harts in the same group will all halt when any of them halts. These
groups can also react to or notify external triggers. (Optional)
This document does not suggest a strategy or implementation for hardware test, debugging or error
detection techniques. Scan, built-in self test (BIST), etc. are out of scope of this specification, but this
specification does not intend to limit their use in RISC-V systems.
It is possible to debug code that uses software threads, but there is no special debug support for it.
[1] Notable exceptions include information about the memory map and peripherals.
The user interacts with the Debug Host (e.g. laptop), which is running a debugger (e.g. gdb). The
debugger communicates with a Debug Translator (e.g. OpenOCD, which may include a hardware
driver) to communicate with Debug Transport Hardware (e.g. Olimex USB-JTAG adapter). The Debug
Transport Hardware connects the Debug Host to the hardware platform’s Debug Transport Module
(DTM). The DTM provides access to one or more Debug Modules (DMs) using the Debug Module
Interface (DMI).
Each hart in the hardware platform is controlled by exactly one DM. Harts may be heterogeneous.
There is no further limit on the hart-DM mapping, but usually all harts in a single core are controlled
by the same DM. In most hardware platforms there will only be one DM that controls all the harts in
the hardware platform.
DMs provide run control of their harts in the hardware platform. Abstract commands provide access
to GPRs. Additional registers are accessible through abstract commands or by writing programs to the
optional Program Buffer.
The Program Buffer allows the debugger to execute arbitrary instructions on a hart. This mechanism
can also be used to access memory. An optional system bus access block allows memory accesses
without using a RISC-V hart to perform the access.
Each RISC-V hart may implement a Trigger Module. When trigger conditions are met, harts will halt
and inform the debug module that they have halted.
and one subordinate (see Table 21), or use a more full-featured bus like TileLink or the AMBA
Advanced Peripheral Bus. The details are left to the system designer.
The DMI uses between 7 and 32 address bits. Each address points at a single 32-bit register that can be
read or written. The bottom of the address space is used for the first (and usually only) DM. Extra
space can be used for custom debug devices, other cores, additional DMs, etc. If there are additional
DMs on this DMI, the base address of the next DM in the DMI address space is given in nextdm.
The Debug Module is controlled via register accesses to its DMI address space.
To perform either of these resets, the debugger first asserts the bit, and then clears it. The actual reset
may start as soon as the bit is asserted, but may start an arbitrarily long time after the bit is deasserted.
The reset itself may also take an arbitrarily long time. While the reset is on-going, harts are either in
the running state, indicating it’s possible to perform some abstract commands during this time, or in
the unavailable state, indicating it’s not possible to perform any abstract commands during this time.
Once a hart’s reset is complete, havereset becomes set. When a hart comes out of reset and haltreq or
resethaltreq are set, the hart will immediately enter Debug Mode (halted state). Otherwise, if the hart
was initially running it will execute normally (running state) and if the hart was initially halted it
should now be running but may be halted.
There is no general, reliable way for the debugger to know when reset has actually begun.
The Debug Module’s own state and registers should only be reset at power-up and while dmactive in
dmcontrol is 0. If there is another mechanism to reset the DM, this mechanism must also reset all the
harts accessible to the DM.
Due to clock and power domain crossing issues, it might not be possible to perform arbitrary DMI
accesses across hardware platform reset. While ndmreset or any external reset is asserted, the only
supported DM operations are reading/writing dmcontrol and reading ndmresetpending. The behavior
of other accesses is undefined.
When harts have been reset, they must set a sticky havereset state bit. The conceptual havereset
state bits can be read for selected harts in anyhavereset and allhavereset in dmstatus. These bits must
be set regardless of the cause of the reset. The havereset bits for the selected harts can be cleared by
writing 1 to ackhavereset in dmcontrol. The havereset bits might or might not be cleared when
dmactive is low.
To enumerate all the harts, a debugger must first determine HARTSELLEN by writing all ones to hartsel
(assuming the maximum size) and reading back the value to see which bits were actually set. Then it
selects each hart starting from 0 until either anynonexistent in dmstatus is 1, or the highest index
(depending on HARTSELLEN) is reached.
The debugger can discover the mapping between hart indices and mhartid by using the interface to
read mhartid, or by reading the hardware platform’s configuration structure.
The debugger can set bits in the hart array mask register using hawindowsel and hawindow, then
apply actions to all selected harts by setting hasel. If this feature is supported, multiple harts can be
halted, resumed, and reset simultaneously. The state of the hart array mask register is not affected by
setting or clearing hasel.
Execution of Abstract Commands ignores this mechanism and only applies to the hart selected by
hartsel.
Harts are nonexistent if they will never be part of this hardware platform, no matter how long a user
waits. E.g. in a simple single-hart hardware platform only one hart exists, and all others are
nonexistent. Debuggers may assume that a hardware platform has no harts with indexes higher than
the first nonexistent one.
Harts are unavailable if they might exist/become available at a later time, or if there are other harts
with higher indexes than this one. Harts may be unavailable for a variety of reasons including being
reset, temporarily powered down, and not being plugged into the hardware platform. That means harts
might become available or unavailable at any time, although these events should be rare in hardware
platforms built to be easily debugged. There are no guarantees about the state of the hart when it
becomes available.
Hardware platforms with very large number of harts may permanently disable some during
manufacturing, leaving holes in the otherwise continuous hart index space. In order to let the
debugger discover all harts, they must show up as unavailable even if there is no chance of them ever
becoming available.
Harts are running when they are executing normally, as if no debugger was attached. This includes
being in a low power mode or waiting for an interrupt, as long as a halt request will result in the hart
being halted.
Harts are halted when they are in Debug Mode, only performing tasks on behalf of the debugger.
Which states a hart that is reset goes through is implementation dependent. Harts may be unavailable
while reset is asserted, and some time after reset is deasserted. They might transition to running for
some time after reset is deasserted. Finally they end up either running or halted, depending on haltreq
and resethaltreq.
When a debugger writes 1 to haltreq, each selected hart’s halt request bit is set. When a running hart,
or a hart just coming out of reset, sees its halt request bit high, it responds by halting, deasserting its
running signal, and asserting its halted signal. Halted harts ignore their halt request bit.
When a debugger writes 1 to resumereq, each selected hart’s resume ack bit is cleared and each
selected, halted hart is sent a resume request. Harts respond by resuming, clearing their halted signal,
and asserting their running signal. At the end of this process the resume ack bit is set. These status
signals of all selected harts are reflected in allresumeack, anyresumeack, allrunning, and anyrunning.
Resume requests are ignored by running harts.
When halt or resume is requested, a hart must respond in less than one second, unless it is
unavailable. (How this is implemented is not further specified. A few clock cycles will be a more
typical latency).
The DM can implement optional halt-on-reset bits for each hart, which it indicates by setting
hasresethaltreq to 1. This means the DM implements the setresethaltreq and clrresethaltreq bits.
Writing 1 to setresethaltreq sets the halt-on-reset request bit for each selected hart. When a hart’s halt-
on-reset request bit is set, the hart will immediately enter debug mode on the next deassertion of its
reset. This is true regardless of the reset’s cause. The hart’s halt-on-reset request bit remains set until
cleared by the debugger writing 1 to clrresethaltreq while the hart is selected, or by DM reset.
If the DM is reset while a hart is halted, it is UNSPECIFIED whether that hart resumes. Debuggers
should use resumereq to explicitly resume harts before clearing dmactive and disconnecting.
In both halt and resume groups, group 0 is special. Harts in group 0 halt/resume as if groups aren’t
implemented at all.
1. That hart halts normally, with cause reflecting the original cause of the halt.
2. All the other harts in the halt group that are running will quickly halt. cause for those harts should
be set to 6, but may be set to 3. Other harts in the halt group that are halted but have started the
process of resuming must also quickly become halted, even if they do resume briefly.
3. Any external triggers in that group are notified.
Adding a hart to a halt group does not automatically halt that hart, even if other harts in the group are
already halted.
1. All the harts in the halt group that are running will quickly halt. cause for those harts should be set
to 6, but may be set to 3. Other harts in the halt group that are halted but have started the process
of resuming must also quickly become halted, even if they do resume briefly.
1. All the other harts in that group that are halted will quickly resume as soon as any currently
executing abstract commands have completed. Each hart in the group sets its resume ack bit as
soon as it has resumed. Harts that are in the process of halting should complete that process and
stay halted.
2. Any external triggers in that group are notified.
Adding a hart to a resume group does not automatically resume that hart, even if other harts in the
group are currently running.
1. All the harts in that group that are halted will quickly resume as soon as any currently executing
abstract commands have completed. Each hart in the group sets its resume ack bit as soon as it has
resumed. Harts that are in the process of halting should complete that process and stay halted.
External triggers are abstract concepts that can signal the DM and/or receive signals from the DM.
This configuration is done through dmcs2, where external triggers are referred to by a number.
Commonly, external triggers are capable of sending a signal from the hardware platform into the DM,
as well as receiving a signal from the DM to take their own action on. It is also allowable for an
external trigger to be input-only or output-only. By convention external triggers 0-7 are bidirectional,
triggers 8-11 are input-only, and triggers 12-15 are output-only but this is not required.
When the DM is reset, all harts must be placed in the lowest-numbered halt and resume groups that
they can be in. (This will usually be group 0.)
Some designs may choose to hardcode hart groups to a group other than group 0, meaning it is never
possible to halt or resume just a single hart. This is explicitly allowed. In that case it must be possible
to discover the groups by using dmcs2 even if it’s not possible to change the configuration.
Example: Every DM must support the Access Register command, but might not support
accessing CSRs. If the debugger requests to read a CSR in that case, the command will
return "not supported".
Debuggers execute abstract commands by writing them to command. They can determine whether an
abstract command is complete by reading busy in abstractcs. If the debugger starts a new command
while busy is set, cmderr becomes 1 (busy), the currently executing command still gets to run to
completion, but any error generated by the currently executing command is lost. After completion,
cmderr indicates whether the command was successful or not. Commands may fail because a hart is
not halted, not running, unavailable, or because they encounter an error during execution.
If the command takes arguments, the debugger must write them to the data registers before writing to
command. If a command returns results, the Debug Module must ensure they are placed in the data
registers before busy is cleared. Which data registers are used for the arguments is described in Table
2. In all cases the least-significant word is placed in the lowest-numbered data register. The argument
width depends on the command being executed, and is DXLEN where not explicitly specified.
While an abstract command is executing (busy in abstractcs is high), a debugger must not change
hartsel, and must not write 1 to haltreq, resumereq, ackhavereset, setresethaltreq, or clrresethaltreq.
The hardware should not rely on this debugger behavior, but should enforce it by ignoring writes to
these bits while busy is high.
If an abstract command does not complete in the expected time and appears to be hung, the debugger
can try to reset the hart (using hartreset or ndmreset). If that doesn’t clear busy, then it can try
resetting the Debug Module (using dmactive).
If an abstract command is started while the selected hart is unavailable or if a hart becomes
unavailable while executing an abstract command, then the Debug Module may terminate the abstract
command, setting busy low, and cmderr to 4 (halt/resume). Alternatively, the command could just
appear to be hung (busy never goes low).
Each abstract command is a 32-bit value. The top 8 bits contain cmdtype which determines the kind
of command. Table 3 lists all commands.
This command gives the debugger access to CPU registers and allows it to execute the Program Buffer.
It performs the following sequence of operations:
1. If write is clear and transfer is set, then copy data from the register specified by regno into the arg0
region of data, and perform any side effects that occur when this register is read from M-mode.
2. If write is set and transfer is set, then copy data from the arg0 region of data into the register
specified by regno, and perform any side effects that occur when this register is written from M-
mode.
3. If aarpostincrement and transfer are set, increment regno. regno may also be incremented if
aarpostincrement is set and transfer is clear.
4. Execute the Program Buffer, if postexec is set.
If any of these operations fail, cmderr is set and none of the remaining steps are executed. An
implementation may detect an upcoming failure early, and fail the overall command before it reaches
the step that would cause failure. If the failure is that the requested register does not exist in the hart,
cmderr must be set to 3 (exception).
Debug Modules must implement this command and must support read and write access to all GPRs
when the selected hart is halted. Debug Modules may optionally support accessing other registers, or
accessing registers when the hart is running. It is recommended that if one register in a group is
accessible, then all registers in that group are accessible, but each individual register (aside from
GPRs) may be supported differently across read, write, and halt status.
Registers might not be accessible if they wouldn’t be accessible by M mode code currently running.
(E.g. fflags might not be accessible when mstatus.FS is 0.) If this is the case, the debugger is
responsible for changing state to make the registers accessible. The Core Debug Registers (Section 4.9)
should be accessible if abstract CSR access is implemented.
This command modifies arg0 only when a register is read. The other data registers are not changed.
31 24 23 22 20 19 18 17 16 15 0
8 1 3 1 1 1 1 16
Field Description
cmdtype This is 0 to indicate Access Register Command.
aarsize 2 (32bit): Access the lowest 32 bits of the register.
If aarsize specifies a size larger than the register’s actual size, then the
access must fail. If a register is accessible, then reads of aarsize less than
or equal to the register’s actual size must be supported. Writing less than
the full register may be supported, but what happens to the high bits in
that case is UNSPECIFIED.
1 (enabled): Execute the program in the Program Buffer exactly once after
performing the transfer, if any. Supporting this variant is optional.
transfer 0 (disabled): Don’t do the operation specified by write.
This bit can be used to just execute the Program Buffer without having to
worry about placing valid values into aarsize or regno.
Field Description
write When transfer is set:
0 (arg0): Copy data from the specified register into arg0 portion of data.
1 (register): Copy data from arg0 portion of data into the specified
register.
regno Number of the register to access, as described in Table 4. dpc may be
used as an alias for PC if this command is supported on a non-halted
hart.
1. If the hart is halted, the command sets cmderr to ``halt/resume'' and does not continue.
2. Halt the hart. If the hart halts for some other reason (e.g. breakpoint), the command sets cmderr to
``halt/resume'' and does not continue.
3. Execute the Program Buffer. If an exception occurs, cmderr is set to ``exception,'' the Program
Buffer execution ends, and the hart is halted with cause set to 3.
4. If the Program Buffer executed without an exception, then resume the hart.
31 24 23 0
cmdtype 0
8 24
Field Description
cmdtype This is 1 to indicate Quick Access command.
This command lets the debugger perform memory accesses, with the exact same memory view and
permissions as performing loads/stores on the selected hart. This includes access to hart-local
memory-mapped registers, etc. The command performs the following sequence of operations:
1. Copy data from the memory location specified in arg1 into the arg0 portion of data, if write is
clear.
2. Copy data from the arg0 portion of data into the memory location specified in arg1, if write is set.
3. If aampostincrement is set, increment arg1.
If any of these operations fail, cmderr is set and none of the remaining steps are executed. An access
may only fail if the hart, running M-mode code, might encounter that same failure when it attempts
the same access. An implementation may detect an upcoming failure early, and fail the overall
command before it reaches the step that would cause failure.
Debug Modules may optionally implement this command and may support read and write access to
memory locations when the selected hart is running or halted. If this command supports memory
accesses while the hart is running, it must also support memory accesses while the hart is halted.
This command modifies arg0 only when memory is read. It modifies arg1 only if aampostincrement
is set. The other data registers are not changed.
31 24 23 22 20 19 18 17 16 15 14 13 0
8 1 3 1 2 1 2 14
Field Description
cmdtype This is 2 to indicate Access Memory Command.
aamvirtual An implementation does not have to implement both virtual and
physical accesses, but it must fail accesses that it doesn’t support.
0 (physical): Addresses are physical (to the hart they are performed on).
1 (virtual): Addresses are virtual, and translated the way they would be
from M-mode, with MPRV set.
1 (memory): Copy data from the low bits of arg0 into the memory
location specified in arg1.
target-specific These bits are reserved for target-specific uses.
A debugger can write a small program to the Program Buffer, and then execute it exactly once with the
Access Register Abstract Command, setting the postexec bit in command. The debugger can write
whatever program it likes (including jumps out of the Program Buffer), but the program must end with
ebreak or c.ebreak. An implementation may support an implicit ebreak that is executed when a hart
runs off the end of the Program Buffer. This is indicated by impebreak. With this feature, a Program
Buffer of just 2 32-bit words can offer efficient debugging.
While these programs are executed, the hart does not leave Debug Mode (see Section 4.1). If an
exception is encountered during execution of the Program Buffer, no more instructions are executed,
the hart remains in Debug Mode, and cmderr is set to 3 (exception error). If the debugger executes a
program that doesn’t terminate with an ebreak instruction, the hart will remain in Debug Mode and
the debugger will lose control of the hart.
1. impebreak must be 1.
2. If the debugger writes a compressed instruction into the Program Buffer, it must be placed into the
lower 16 bits and accompanied by a compressed nop in the upper 16 bits.
This requirement on the debugger for the case of progbufsize equal to 1 is to accommodate
hardware designs that prefer to stuff instructions directly into the pipeline when halted,
instead of having the Program Buffer exist in the address space somewhere.
The Program Buffer may be implemented as RAM which is accessible to the hart. A debugger can
determine if this is the case by executing small programs that attempt to write and read back relative
to pc while executing from the Program Buffer. If so, the debugger has more flexibility in what it can
do with the program buffer.
Figure 2. Run/Halt Debug State Machine for single-hart hardware platforms. As only a small amount of state is
visible to the debugger, the states and transitions are conceptual.
The System Bus Access block may support 8-, 16-, 32-, 64-, and 128-bit accesses. Table 5 shows which
bits in sbdata are used for each access size.
Depending on the microarchitecture, data accessed through System Bus Access might not always be
coherent with that observed by each hart. It is up to the debugger to enforce coherency if the
implementation does not. This specification does not define a standard way to do this. Possibilities
may include writing to special memory-mapped locations, or executing special instructions via the
Program Buffer.
Implementing a System Bus Access block has several benefits even when a Debug Module
also implements a Program Buffer. First, it is possible to access memory in a running
system with minimal impact. Second, it may improve performance when accessing
memory. Third, it may provide access to devices that a hart does not have access to.
First, an implementation may allow some abstract commands to execute without halting the hart.
Second, the Quick Access abstract command can be used to halt a hart, quickly execute the contents of
the Program Buffer, and let the hart run again. Combined with instructions that allow Program Buffer
code to access the data registers, as described in hartinfo, this can be used to quickly perform a
memory or register access. For some hardware platforms this will be too intrusive, but many hardware
platforms that can’t be halted can bear an occasional hiccup of a hundred or less cycles.
Third, if the System Bus Access block is implemented, it can be used while a hart is running to access
system memory.
3.12. Security
To protect intellectual property it may be desirable to lock access to the Debug Module. To allow access
during a manufacturing process and not afterwards, a reasonable solution could be to add a fuse bit to
the Debug Module that can be used to permanently disable it. Since this is technology specific, it is not
further addressed in this spec.
Another option is to allow the DM to be unlocked only by users who have an access key. Between
authenticated, authbusy, and authdata arbitrarily complex authentication mechanism can be
supported. When authenticated is clear, the DM must not interact with the rest of the hardware
platform, nor expose details about the harts connected to the DM. All DM registers should read 0,
while writes should be ignored, with the following mandatory exceptions:
Implementations where it’s not possible to unlock the DM by using authdata should not implement
that register.
1. Read dmcontrol.
2. If dmactive is 0 or ndmreset is 1:
a. Write dmcontrol, preserving hartreset, hasel, hartsello, and hartselhi from the value that was
read, setting dmactive, and clearing all the other bits.
b. Read dmcontrol until dmactive is high.
3. Read dmstatus, which contains version.
If it was necessary to clear ndmreset, this might have the following side effects:
1. haltreq is cleared, potentially preventing a halt request made by a previous debugger from taking
effect.
2. resumereq is cleared, potentially preventing a resume request made by a previous debugger from
taking effect.
3. ndmreset is deasserted, releasing the hardware platform from reset if a previous debugger had set
it.
4. dmactive is asserted, releasing the DM from reset. This in itself is not observable by any harts.
This procedure is guaranteed to work in future versions of this spec. The meaning of the dmcontrol
bits where hartreset, hasel, hartsello, and hartselhi currently reside might change, but preserving them
will have no side effects. Clearing the bits of dmcontrol not explicitly mentioned here will have no side
effects beyond the ones mentioned above.
Debug Module DMI Registers that are unimplemented or not mentioned in the table below return 0
when read. Writing them has no effect.
7 1 1 1 2 1 1
17 16 15 14 13 12 11
1 1 1 1 1 1 1
10 9 8 7 6 5 4 3 0
1 1 1 1 1 1 1 4
Throughout this document we refer to hartsel, which is hartselhi combined with hartsello. While the
spec allows for 20 hartsel bits, an implementation may choose to implement fewer than that. The
actual width of hartsel is called HARTSELLEN. It must be at least 0 and at most 20. A debugger should
discover HARTSELLEN by writing all ones to hartsel (assuming the maximum size) and reading back the
value to see which bits were actually set. Debuggers must not change hartsel while an abstract
command is executing. Hardware should enforce this by ignoring changes to hartsel while busy is set.
There are separate setresethaltreq and clrresethaltreq bits so that it is possible to write
dmcontrol without changing the halt-on-reset request bit for each selected hart, when not
all selected harts have the same configuration.
On any given write, a debugger may only write 1 to at most one of the following bits: resumereq,
hartreset, ackhavereset, setresethaltreq, and clrresethaltreq. The others must be written 0.
resethaltreq is an optional internal bit of per-hart state that cannot be read, but can be written with
setresethaltreq and clrresethaltreq.
keepalive is an optional internal bit of per-hart state. When it is set, it suggests that the hardware
should attempt to keep the hart available for the debugger, e.g. by keeping it from entering a low-power
state once powered on. Even if the bit is implemented, hardware might not be able to keep a hart
available. The bit is written through setkeepalive and clrkeepalive.
For forward compatibility, version will always be readable when bit 1 (ndmreset) is 0 and bit 0
(dmactive) is 1.
31 30 29 28 27 26 25 16
1 1 1 1 1 1 10
15 6 5 4 3 2 1 0
10 1 1 1 1 1 1
Writing 1 sets the halt request bit for all currently selected
harts. Running harts will halt whenever their halt request
bit is set.
If this register is included, the debugger can do more with the Program Buffer by writing programs
which explicitly access the data and/or dscratch registers.
31 24 23 20 19 17 16 15 12 11 0
8 4 3 1 4 12
31 15 14 0
0 hawindowsel
17 15
Since some bits in the hart array mask register may be constant 0, some bits in this register may be
constant 0, depending on the current value of hawindowsel.
31 0
maskdata
32
3 5 11 1 1 3 4 4
0 (none): No error.
Writing this register while an abstract command is executing causes cmderr to become 1 (busy) once
the command completes (busy becomes 0).
31 24 23 0
cmdtype control
8 24
If this register is implemented then bits corresponding to implemented progbuf and data registers
must be writable. Other bits must be hard-wired to 0.
If this register is written while an abstract command is executing then the write is ignored and cmderr
becomes 1 (busy) once the command completes (busy becomes 0).
31 16 15 12 11 0
autoexecprogbuf 0 autoexecdata
16 4 12
When system bus access is implemented, this must be an address that can be used with the System
Bus Access module. Otherwise, this must be an address that can be used to access the configuration
structure from the hart with ID 0.
If confstrptrvalid is 0, then the confstrptr registers hold identifier information which is not further
specified in this document.
The configuration structure itself is a data structure of the same format as the data structure pointed
to by mconfigptr as described in the Privileged Spec.
31 0
addr
32
31 0
addr
32
31 0
addr
32
31 0
addr
32
31 0
addr
32
Accessing these registers while an abstract command is executing causes cmderr to be set to 1 (busy) if
it is 0.
Attempts to write them while busy is set does not change their value.
The values in these registers might not be preserved after an abstract command is executed. The only
guarantees on their contents are the ones offered by the command in question. If the command fails,
no assumptions can be made about the contents of these registers.
31 0
data
32
progbufsize indicates how many progbuf registers are implemented starting at progbuf0, counting up.
Accessing these registers while an abstract command is executing causes cmderr to be set to 1 (busy) if
it is 0.
Attempts to write them while busy is set does not change their value.
31 0
data
32
When authbusy is clear, the debugger can communicate with the authentication module by reading or
writing this register. There is no separate mechanism to signal overflow/underflow.
31 0
data
32
If halt groups are not implemented, then group will always be 0 when grouptype is 0.
If resume groups are not implemented, then grouptype will remain 0 even after 1 is written there.
The DM external triggers available to add to halt groups may be the same as or distinct from the DM
external triggers available to add to resume groups.
31 12 11 10 7 6 2 1 0
20 1 4 5 1 1
This register might not be present if fewer than 2 harts are connected to this DM.
The LSB reflects the halt status of hart {hartsel[19:5],5’h0}, and the MSB reflects halt status of hart
{hartsel[19:5],5’h1f}.
31 0
haltsum0
32
This register might not be present if fewer than 33 harts are connected to this DM.
The LSB reflects the halt status of harts {hartsel[19:10],10’h0} through {hartsel[19:10],10’h1f}. The MSB
reflects the halt status of harts {hartsel[19:10],10’h3e0} through {hartsel[19:10],10’h3ff}.
31 0
haltsum1
32
This register might not be present if fewer than 1025 harts are connected to this DM.
The LSB reflects the halt status of harts {hartsel[19:15],15’h0} through {hartsel[19:15],15’h3ff}. The MSB
reflects the halt status of harts {hartsel[19:15],15’h7c00} through {hartsel[19:15],15’h7fff}.
31 0
haltsum2
32
This register might not be present if fewer than 32769 harts are connected to this DM.
The LSB reflects the halt status of harts 20’h0 through 20’h7fff. The MSB reflects the halt status of
harts 20’hf8000 through 20’hfffff.
31 0
haltsum3
32
3 6 1 1 1 3 1
15 14 12 11 5 4 3 2 1 0
1 3 7 1 1 1 1 1
0 (8bit): 8-bit
1 (16bit): 16-bit
2 (32bit): 32-bit
3 (64bit): 64-bit
4 (128bit): 128-bit
7 (other): Other.
sbasize Width of system bus addresses in bits. (0 indicates there is R Preset
no bus access support.)
sbaccess128 1 when 128-bit system bus accesses are supported. R Preset
sbaccess64 1 when 64-bit system bus accesses are supported. R Preset
sbaccess32 1 when 32-bit system bus accesses are supported. R Preset
sbaccess16 1 when 16-bit system bus accesses are supported. R Preset
sbaccess8 1 when 8-bit system bus accesses are supported. R Preset
When the system bus manager is busy, writes to this register will set sbbusyerror and don’t do
anything else.
If sberror is 0, sbbusyerror is 0, and sbreadonaddr is set then writes to this register start the following:
1. Set sbbusy.
2. Perform a bus read from the new value of sbaddress.
3. If the read succeeded and sbautoincrement is set, increment sbaddress.
4. Clear sbbusy.
31 0
address
32
When the system bus manager is busy, writes to this register will set sbbusyerror and don’t do
anything else.
31 0
address
32
When the system bus manager is busy, writes to this register will set sbbusyerror and don’t do
anything else.
31 0
address
32
When the system bus manager is busy, writes to this register will set sbbusyerror and don’t do
anything else.
31 0
address
32
Any successful system bus read updates sbdata. If the width of the read access is less than the width of
sbdata, the contents of the remaining high bits may take on any value.
If the bus manager is busy then accesses set sbbusyerror, and don’t do anything else.
1. Set sbbusy.
2. Perform a bus write of the new value of sbdata to sbaddress.
3. If the write succeeded and sbautoincrement is set, increment sbaddress.
4. Clear sbbusy.
Only sbdata0 has this behavior. The other sbdata registers have no side effects. On systems that have
buses wider than 32 bits, a debugger should access sbdata0 after accessing the other sbdata registers.
31 0
data
32
If the bus manager is busy then accesses set sbbusyerror, and don’t do anything else.
31 0
data
32
If the bus manager is busy then accesses set sbbusyerror, and don’t do anything else.
31 0
data
32
If the bus manager is busy then accesses set sbbusyerror, and don’t do anything else.
31 0
data
32
Modifications to the RISC-V core to support debug are kept to a minimum. There is a special execution
mode (Debug Mode) and a few extra CSRs. The DM takes care of the rest.
If Sdext is implemented and Sdtrig is not implemented, then accessing any of the Sdtrig CSRs must
raise an illegal instruction exception.
When executing code due to an abstract command, the hart stays in Debug Mode and the following
apply:
1. All implemented instructions operate just as they do in M-mode, unless an exception is mentioned
in this list.
2. All operations are executed with machine mode privilege, except that additional Debug Mode CSRs
are accessible and mprv in mstatus may be ignored according to mprven. Full permission checks,
or a relaxed set of permission checks, will apply according to relaxedpriv.
3. All interrupts (including NMI) are masked.
4. Traps don’t take place. Instead, they end execution of the program buffer and the hart remains in
Debug Mode. Because they do not trap to M-mode, they do not update registers such as , mepc,
mcause, mtval, mtval2, and mtinst. The same is true for the equivalent privileged registers that are
updated when trapping to other modes. Registers that may be updated as part of execution before
the exception are allowed to be updated. For example, vector load/store instructions which raise
exceptions may partially update the destination register and set vstart appropriately.
5. Triggers don’t match or fire.
6. If stopcount is 0 then counters continue. If it is 1 then counters are stopped.
7. If stoptime is 0 then time continues to update. If it is 1 then time will not update. It will
resynchronize with time after leaving Debug Mode.
8. Instructions that place the hart into a stalled state act as a nop. This includes wfi, wrs.sto, and
wrs.nto.
9. Almost all instructions that change the privilege mode have UNSPECIFIED behavior. This
includes ecall, mret, sret, and uret. (To change the privilege mode, the debugger can write prv
and v in dcsr). The only exception is ebreak, which ends execution of the Program Buffer when
executed.
10. All control transfer instructions may act as illegal instructions if their destination is in the
Program Buffer. If one such instruction acts as an illegal instruction, all such instructions must act
as illegal instructions.
11. All control transfer instructions may act as illegal instructions if their destination is outside the
Program Buffer. If one such instruction acts as an illegal instruction, all such instructions must act
as illegal instructions.
12. Instructions that depend on the value of the PC (e.g. auipc) may act as illegal instructions.
13. When the Zicfilp extension is implemented, the ELP state is NO_LP_EXPECTED and is not updated by
any instructions. LPAD instruction executes as a no-op.
14. Effective XLEN is DXLEN.
15. Forward progress is guaranteed.
When mprven, the external debugger can set MPRV and MPP appropriately to have
hardware perform memory accesses with the appropriate endianness, address translation,
permission checks, and PMP/PMA checks (subject to relaxedpriv). This is also the only
way to access all of physical memory when 34-bit physical addresses are supported on a
Sv32 hart. If hardware ties mprven to 0 then the external debugger is expected to simulate
all the effects of MPRV, including any extensions that affect memory accesses. For these
reasons it is recommended to tie mprven to 1.
This is a behavior that debug users must be aware of. If they have a breakpoint set between
a lr and sc pair, or are stepping through such code, the sc may never succeed.
Fortunately in general use there will be very few instructions in such a sequence, and
anybody debugging it will quickly notice that the reservation is not occurring. The solution
in that case is to set a breakpoint on the first instruction after the sc and run to it. A
higher level debugger may choose to automate this.
An external debugger can cause a halted hart to execute a single instruction or trap and then re-enter
Debug Mode by setting step before resuming. If step is set when a hart resumes then it will single step,
regardless of the reason for resuming.
If control is transferred to a trap handler while executing the instruction, then Debug Mode is re-
entered immediately after the PC is changed to the trap handler, and the appropriate tval and cause
registers are updated. In this case none of the trap handler is executed, and if the cause was a pending
interrupt no instructions might be executed at all.
If executing or fetching the instruction causes a trigger to fire with action=1, Debug Mode is re-entered
immediately after that trigger has fired. In that case cause is set to 2 (trigger) instead of 4 (single step).
Whether the instruction is executed or not depends on the specific configuration of the trigger.
If the instruction that is executed causes the PC to change to an address where an instruction fetch
causes an exception, that exception does not occur until the next time the hart is resumed. Similarly, a
trigger at the new address does not fire until the hart actually attempts to execute that instruction.
If the instruction being stepped over would normally stall the hart, then instead the instruction is
treated as a nop. This includes wfi, wrs.sto, and wrs.nto.
1. Interrupts will fire as usual. Debuggers that want to disable interrupts while stepping must disable
them by changing mstatus, and specially handle instructions that read mstatus.
2. wfi instructions are not treated specially and might take a very long time to complete.
This mechanism cleanly supports a system which supports multiple privilege levels, where the OS or a
debug stub runs in M-Mode while the program being debugged runs in a less privileged mode.
Systems that only support M-Mode can use icount as well, but count must be able to count several
instructions (depending on the software implementation). See Section B.3.1.
4.6. Reset
If the halt signal (driven by the hart’s halt request bit in the Debug Module) or hasresethaltreq are
asserted when a hart comes out of reset, the hart must enter Debug Mode before executing any
instructions, but after performing any initialization that would usually happen before the first
instruction is executed.
4.7. Halt
When a hart halts:
1. cause is updated.
2. prv and v are set to reflect current privilege mode and virtualization mode.
3. If the Zicfilp extension is implemented, pelp is set to the current ELP state and ELP is set to
NO_LP_EXPECTED
4.8. Resume
When a hart resumes:
Attempts to access an unimplemented Core Debug Register raise an illegal instruction exception.
Table 8 shows the priorities of reasons for entering Debug Mode. Implementations should implement
priorities as shown in the table. For compatibility with old versions of this spec, resethaltreq and
haltreq are allowed to be at different positions than shown as long as:
Table 8. Priority of reasons for entering Debug Mode from highest to lowest.
cause encoding Cause
5 resethaltreq
6 halt group
3 haltreq
2 trigger (See Table 13 for detailed priority)
1 ebreak
4 step
Note that mcontrol/mcontrol6 triggers which fire after the instruction which hit the
trigger are considered to be high priority causes on the subsequent instruction. Therefore,
an execute trigger with timing=after on an ebreak instruction is lower priority than the
ebreak itself because the trigger will fire after the ebreak instruction. For the same reason,
if a single instruction is stepped with both icount and step then the step has priority. See
Table 13 for the relative priorities of triggers with respect to the ebreak instruction.
4 1 3 4 1 1 1 1 1 1
13 12 11 10 9 8 6 5 4 3 2 1 0
ebreaks ebreaku stepie stopcount stoptime cause v mprven nmip step prv
1 1 1 1 1 3 1 1 1 1 2
The debugger must not change the value of this bit while
the hart is running.
stopcount 0 (normal): Increment counters as usual. WARL Preset
7 (other): The hart halted for a reason other than the ones
mentioned above. extcause may contain a more specific
reason.
v Extends the prv field with the virtualization mode the hart WARL 0
was operating in when Debug Mode was entered. The
encoding is described in Table 11. A debugger can change
this value to change the hart’s virtualization mode when
exiting Debug Mode. This bit is hardwired to 0 on harts
that do not support virtualization mode.
mprven 0 (disabled): mprv in mstatus is ignored in Debug Mode. WARL Preset
The debugger must not change the value of this bit while
the hart is running.
prv Contains the privilege mode the hart was operating in WARL 3
when Debug Mode was entered. The encoding is described
in Table 11. A debugger can change this value to change the
hart’s privilege mode when exiting Debug Mode.
Executing the Program Buffer may cause the value of dpc to become UNSPECIFIED. If that is the case,
it must be possible to read/write dpc using an abstract command with postexec not set. The debugger
must attempt to save dpc between halting and executing a Program Buffer, and then restore dpc before
leaving Debug Mode.
Allowing dpc to become UNSPECIFIED upon Program Buffer execution allows for direct
implementations that don’t have a separate PC register, and do need to use the PC when
executing the Program Buffer.
If the Access Register abstract command supports reading dpc while the hart is running, then the
value read should be the address of a recently executed instruction.
If the Access Register abstract command supports writing dpc while the hart is running, then the
executing program should jump to the written address shortly after the write occurs.
The writability of dpc follows the same rules as mepc as defined in the Privileged Spec. In particular,
dpc must be able to hold all valid virtual addresses and the writability of the low bits depends on
IALIGN.
When resuming, the hart’s PC is updated to the virtual address stored in dpc. A debugger may write
dpc to change where the hart resumes.
DXLEN-1 0
dpc
DXLEN
DXLEN-1 0
dscratch0
DXLEN
DXLEN-1 0
dscratch1
DXLEN
This register contains prv and v from dcsr, but in a place that the user is expected to access. The user
should not access dcsr directly, because doing so might interfere with the debugger.
2 1 0
v prv
1 2
Triggers can cause a breakpoint exception, entry into Debug Mode, or a trace action without having to
execute a special instruction. This makes them invaluable when debugging code from ROM. They can
trigger on execution of instructions at a given memory address, or on the address/data in loads/stores.
If Sdtrig is implemented, the Trigger Module must support at least one trigger. Accessing trigger CSRs
that are not used by any of the implemented triggers must result in an illegal instruction exception.
M-Mode and Debug Mode accesses to trigger CSRs that are used by any of the implemented triggers
must succeed, regardless of the current type of the currently selected trigger.
A trigger matches when the conditions that it specifies (e.g. a load from a specific address) are met. A
trigger fires when a trigger that matches performs the action configured for that trigger.
5.1. Enumeration
Each trigger may support a variety of features. A debugger can build a list of all triggers and their
features as follows:
1. Write 0 to tselect. If this results in an illegal instruction exception, then there are no triggers
implemented.
2. Read back tselect and check that it contains the written value. If not, exit the loop.
3. Read tinfo.
4. If that caused an exception, the debugger must read tdata1 to discover the type. (If type is 0, this
trigger doesn’t exist. Exit the loop.)
5. If info is 1, this trigger doesn’t exist. Exit the loop.
6. Otherwise, the selected trigger supports the types discovered in info.
7. Repeat, incrementing the value in tselect.
The above algorithm reads back tselect so that implementations which have triggers
only need to implement bits of tselect.
The algorithm checks tinfo and type in case the implementation has bits of tselect but
fewer than triggers.
5.2. Actions
Triggers can be configured to take one of several actions when they fire. Table 12 lists all options.
Value Description
0 Raise a breakpoint exception. (Used when software wants to use the trigger module without
an external debugger attached.) xepc must contain the virtual address of the next
instruction that must be executed to preserve the program flow.
1 Enter Debug Mode. dpc must contain the virtual address of the next instruction that must
be executed to preserve the program flow.
This action is only legal when the trigger’s dmode is 1. Since tdata1 is WARL, hardware must
prevent it from containing dmode=0 and action=1.
This action can only be supported if Sdext is implemented on the hart.
2 Trace on, described in the trace specification.
3 Trace off, described in the trace specification.
4 Trace notify, described in the trace specification.
5 Reserved for use by the trace specification.
8 - 9 Send a signal to TM external trigger output 0 or 1 (respectively).
other Reserved for future use.
Actions 8 and 9 are intended to increment custom event counters, but these signals could
also be brought to outputs for use by external logic.
5.3. Priority
Table 13 lists the synchronous exceptions from the Privileged Spec, and where the various types of
triggers fit in. The first 3 columns come from the Privileged Spec, and the final column shows where
triggers fit in. Priorities in the table are separated by horizontal lines, so e.g. etrigger and itrigger have
the same priority. If this table contradicts the table in the Privileged Spec, then the latter takes
precedence.
This table only applies if triggers are precise. Otherwise triggers will fire some indeterminate time
after the event, and the priority is irrelevant. When triggers are chained, the priority is the lowest
priority of the triggers in the chain.
When multiple triggers in the same priority fire at once, hit (if implemented) is set for all of them. If
more than one of these triggers has action=0 then tval is updated in accordance with one of them, but
which one is UNSPECIFIED . If one of these triggers has the "enter Debug Mode" action (1) and another
trigger has the "raise a breakpoint exception" action (0), the preferred behavior is to have both actions
take place. It is implementation-dependent which of the two happens first. This ensures both that the
presence of an external debugger doesn’t affect execution and that a trigger set by user code doesn’t
affect the external debugger. If this is not implemented, then the hart must enter Debug Mode and
ignore the breakpoint exception. In the latter case, hit of the trigger whose action is 0 must still be set,
giving a debugger an opportunity to handle this case. Since triggers that have an action other than 0 or
1 don’t affect the execution of the hart, they are not mentioned in the priority table. Such triggers fire
independently from those that have an action of 0 or 1.
the same mode that the resulting exception will be handled in.
In these cases such a trigger may cause a breakpoint exception while already in a trap handler. This
might leave the hart unable to resume normal execution because state such as mcause and mepc would
be overwritten.
1. mcontrol and mcontrol6 triggers with m=1 can cause a breakpoint exception that is
taken from M-mode to M-mode (regardless of delegation).
2. mcontrol and mcontrol6 triggers with s=1 can cause a breakpoint exception that is
taken from S-mode to S-mode if medeleg [3]=1.
3. mcontrol6 triggers with vs=1 can cause a breakpoint exception that is taken from VS-
mode to VS-mode if medeleg [3]=1 and hedeleg [3]=1 .
4. icount triggers with m=1can cause a breakpoint exception that is taken from M-mode
to M-mode (regardless of delegation).
5. icount triggers with s=1 can cause a breakpoint exception that is taken from S-mode to
S-mode if medeleg [3]=1 .
6. icount triggers with vs=1 can cause a breakpoint exception that is taken from VS-mode
to VS-mode if medeleg [3]=1 and hedeleg [3]=1.
7. etrigger and itrigger triggers will always be taken from a trap handler before the first
instruction of the handler. If etrigger/itrigger is set to trigger on exception/interrupt X
and if X is delegated to mode Y then the trigger will cause a breakpoint exception that
is taken from mode Y to mode Y unless breakpoint exceptions are delegated to a more
privileged mode than Y.
8. tmexttrigger triggers are asynchronous and may occur in any mode and at any time.
Harts that support triggers with action=0 should implement one of the following two solutions to
solve the problem of reentrancy:
1. The hardware prevents triggers with action=0 from matching or firing while in M-mode and while
MIE in mstatus is 0. If medeleg [3]=1 then it prevents triggers with action=0 from matching or
firing while in S-mode and while SIE in sstatus is 0. If medeleg [3]=1 and hedeleg [3]=1 then it
prevents triggers with action=0 from matching or firing while in VS-mode and while SIE in
vstatus is 0.
2. mte and mpte in tcontrol is implemented. medeleg [3] is hard-wired to 0.
The first option has the limitation that interrupts might be disabled at times when a user
still might want triggers to fire. It has the benefit that breakpoints are not required to be
handled in M-mode.
The second option has the benefit that it only disables triggers during the trap handler,
though it requires specific software support for this debug feature in the M-mode trap
handlers. It can only work if breakpoints are not delegated to less privileged modes and
therefore targets primarily implementations without S-mode.
Because tcontrol is not accessible to S-mode, the second option can not be extended to
accommodate delegation without adding additional S-mode and VS-mode CSRs.
Both options prevent etrigger and itrigger from having any effect on exceptions and
interrupts that are handled in M-mode. They also prevent triggering during some initial
portion of each handler. Debuggers should use other mechanisms to debug these cases,
such as patching the handler or setting a breakpoint on the instruction after MIE is
cleared.
5.5.1. A Extension
If the A extension is supported, then triggers on loads/stores treat them as follows:
1. Cache operations that enable software to maintain coherence between otherwise non-coherent
implicit and explicit memory accesses.
2. Cache operations that perform block writes of constant data.
Only triggers with size=0 and select=0 will match. Since cache operations affect multiple addresses,
there are multiple possible values to compare against. Implementations must implement one of the
following options. From most desirable to least desirable, they are:
1. Every address from the effective address rounded down to the nearest cache block boundary
(inclusive) to the effective address rounded up to the nearest cache block boundary (exclusive) is a
compare value.
2. The effective address rounded down to the nearest cache block boundary is a compare value.
3. The effective address of the instruction is a compare value.
The above language intends to capture the trigger behavior with respect to the cache
operations to be introduced in a forthcoming I/D consistency extension.
For RISC-V Base Cache Management Operation ISA Extensions 1.0.1, this means the
following:
1. cbo.clean, cbo.flush, and cbo.inval match as if they are stores because they
affect consistency.
2. cbo.zero matches as if it is a store because it performs a block write of constant data.
3. The prefetch instructions don’t match at all.
If physical addresses are less than XLEN bits wide, they are zero-extended. If virtual
addresses are less than XLEN bits wide, they are sign-extended. tdata2 must be
implemented with enough bits of storage to represent the full range of supported physical
and virtual address values when read by software and used by hardware.
If tdata2 can hold any invalid addresses, then writes of an invalid address that can not be represented
as-is should be converted to a different invalid address that can be represented.
For invalid instruction fetch addresses and load and store effective addresses, the compare value may
be changed to a different invalid address.
In addition, an implementation may choose to inhibit all trigger matching against invalid addresses,
especially if there is no support for storage of any invalid address values in tdata2.
Debuggers won’t be aware if an instruction has been partially executed. When they resume execution,
they will execute the same instruction once more. Therefore, it’s crucial that partially executing the
instruction and then executing it again leaves the hart in a state closely resembling the state it would
have been in if the instruction had only been executed once.
Almost all trigger functionality is optional. All tdata registers follow write-any-read-legal semantics. If
a debugger writes an unsupported configuration, the register will read back a value that is supported
(which may simply be a disabled trigger). This means that a debugger must always read back values it
writes to tdata registers, unless it already knows what is supported. Writes to one tdata register must
not modify the contents of other tdata registers, nor the configuration of any trigger besides the one
that is currently selected.
The combination of these rules means that a debugger cannot simply set a trigger by writing tdata1,
then tdata2, etc. The current value of tdata2 might not be legal with the new value of tdata1. To help
with this situation, it is guaranteed that writing 0 to tdata1 disables the trigger, and leaves it in a state
where tdata2 and tdata3 can be written with any value that makes sense for any trigger type supported
by this trigger.
1. Write 0 to tdata1. (This will result in tdata1 containing a non-zero value, since the register is
WARL.)
2. Write desired values to tdata2 and tdata3.
3. Write desired value to tdata1.
Code that restores CSR context of triggers that might be configured to fire in the current privilege
mode must use this same sequence to restore the triggers. This avoids the problem of a partially
written trigger firing at a different time than is expected.
Attempts to access an unimplemented Trigger Module Register raise an illegal instruction exception.
The Trigger Module registers, except mscontext, scontext, and hcontext, are only accessible in
machine and Debug Mode to prevent untrusted user code from causing entry into Debug Mode
without the OS’s permission.
In this section XLEN refers to the effective XLEN in the current execution mode. On systems where
XLEN values can differ between modes, this is handled as follows. Fields retain their values regardless
of XLEN, which only affects where in the register these fields appear (e.g. type). Some fields are wider
when XLEN is 64 than when it is 32 (e.g. svalue). The high bits in such fields retain their value but are
not readable when XLEN is 32. A modification of a register when XLEN is 32 clears any inaccessible
bits in that register.
This register is WARL. Writes of values greater than or equal to the number of supported triggers may
result in a different value in this register than what was written or may point to a trigger where
type=0. To verify that what they wrote is a valid index, debuggers can read back the value and check
that tselect holds what they wrote and read tdata1 to see that type is non-zero.
Since triggers can be used both by Debug Mode and M-mode, the external debugger must restore this
register if it modifies it.
XLEN-1 0
index
XLEN
Writing 0 to this register must result in a trigger that is disabled. If this trigger supports multiple
4 1 XLEN - 5
Trigger-specific data.
If the trigger is disabled, then this register can be written with any value supported by any of the
trigger types supported by this trigger.
XLEN-1 0
data
XLEN
If the trigger is disabled, then this register can be written with any value supported by any of the
trigger types supported by this trigger.
XLEN-1 0
data
XLEN
This register is optional if no triggers are implemented, or if type is not writable and version would be
0. In this case the debugger can read the only supported type from tdata1.
XLEN-1 32 31 24 23 16 15 0
0 version 0 info
XLEN - 32 8 8 16
XLEN-1 8 7 6 4 3 2 0
0 mpte 0 mte 0
XLEN - 8 1 3 1 3
This register is only accessible in HS-Mode, M-mode and Debug Mode. If Smstateen is implemented,
then accessibility of in HS-Mode is controlled by mstateenzero[57].
This register is an alias of the mcontext register, providing access to the hcontext field from HS-Mode.
XLEN-1 32 31 0
0 data
XLEN - 32 32
hcontext is primarily useful to set triggers on hypervisor systems that only fire when a
given VM is executing. It is also useful in systems where M-Mode implements something
like a hypervisor directly.
XLEN-1 14 13 0
0 hcontext
XLEN - 14 14
The encoding of this CSR does not conform to the CSR Address Mapping Convention in
the Privileged Spec. It is expected that new implementations will not support this encoding
and that new debuggers will not use this CSR if scontext is available.
This register is accessible as tdata1 when type is 2. This trigger type is deprecated. It is included for
backward compatibility with version 0.13.
This trigger type only supports a subset of features of the newer mcontrol6. It is expected
that new implementations will not support this trigger type and that new debuggers will
not use it if mcontrol6 is available.
Address and data trigger implementation are heavily dependent on how the processor core is
implemented. To accommodate various implementations, execute, load, and store address/data
triggers may fire at whatever point in time is most convenient for the implementation. The debugger
may request specific timings as described in timing. Table 15 suggests timings for the best user
experience.
A chain of triggers that don’t all have the same timing value will never fire. That means to implement
the suggestions in Table 15, both timings should be supported on load address triggers that can be
chained with a load data trigger.
The Privileged Spec says that breakpoint exceptions that occur on instruction fetches, loads, or stores
update the tval CSR with either zero or the faulting virtual address. The faulting virtual address for
an mcontrol trigger with action=0 is the address being accessed and which caused that trigger to fire.
If multiple mcontrol triggers are chained then the faulting virtual address is the address which caused
any of the chained triggers to fire.
If textra32 or textra64 are implemented for this trigger, it only matches when the conditions set there
are satisfied.
4 1 6 XLEN - 34 2 1 1 1
17 16 15 12 11 10 7 6 5 4 3 2 1 0
2 4 1 4 1 1 1 1 1 1 1
1 (after): The action for this trigger will be taken after the
instruction that triggered it is retired. It should be taken
before the next instruction is retired, but it is better to
implement triggers imprecisely than to not implement
them at all. xepc or dpc (depending on action) must be set
to the virtual address of the next instruction that must be
executed to preserve the program flow.
Implementing this trigger as described here requires that version is 1 or higher, which in turn means
tinfo must be implemented.
This replaces mcontrol in newer implementations and serves to provide additional functionality.
Address and data trigger implementation are heavily dependent on how the processor core is
implemented. To accommodate various implementations, execute, load, and store address/data
triggers may fire at whatever point in time is most convenient for the implementation.
Table 15 suggests timings for the best user experience. The underlying principle is that firing just
before the instruction gives a user more insight, so is preferable. However, depending on the
instruction and conditions, it might not be possible to evaluate the trigger until the instruction has
partially executed. In that case it is better to let the instruction retire before the trigger fires, to avoid
extra memory accesses which might affect the state of the system.
A chain of triggers must only fire if every trigger in the chain was matched by the same instruction.
The Privileged Spec says that breakpoint exceptions that occur on instruction fetches, loads, or stores
update the tval CSR with either zero or the faulting virtual address. The faulting virtual address for
an mcontrol6 trigger with action=0 is the address being accessed and which caused that trigger to fire.
If multiple mcontrol6 triggers are chained then the faulting virtual address is the address which
caused any of the chained triggers to fire.
In implementations that support match mode 1 (NAPOT), not all NAPOT ranges may be supported. All
NAPOT ranges between and are supported where . The value of maskmax6
can be determined by the debugger via the following sequence:
1. Write tdata1=0, in case the current tdata2 value is not supported with mcontrol6 triggers.
2. Write tdata2=0, which is always supported with mcontrol6 triggers.
3. Write tdata1 with type=mcontrol6 and match=1.
4. Read match. If it is not 1 then NAPOT matching is not supported.
5. Write all ones to tdata2.
6. Read tdata2. The value of maskmax6 is the index of the most significant 0 bit plus 1.
If textra32 or textra64 are implemented for this trigger, it only matches when the conditions set there
are satisfied.
uncertain and uncertainen exist to accommodate systems where not every memory access
is fully observed by the Trigger Module. Possible examples include data values in far
AMOs, and the address/data/size of accesses by instructions that perform multiple
memory accesses, such as vector, push, and pop instructions.
While the uncertain mechanism exists to deal with these situations, it can lead to an
unusable number of false positives. Users will get a much better debug experience if the
TM does have perfect visibility into the details of every memory access.
4 1 XLEN - 32 1 1 1 1 1 1 2 3
15 12 11 10 7 6 5 4 3 2 1 0
4 1 4 1 1 1 1 1 1 1
1. An instruction retires after having been fetched in a privilege mode where the trigger is enabled.
This explicitly includes all RET instructions from various modes.
2. A trap is taken from a privilege mode where the trigger is enabled. This explicitly includes traps
taken due to interrupts.
If more than one of the above events occur during a single instruction execution, the trigger still only
matches once for that instruction.
For use in single step, icount must match for traps where the instruction will not be
reexecuted after the handler, such as illegal instructions that are emulated by privileged
software and the instruction being emulated never retires. Ideally, icount would not match
for traps where the instruction will later be retried by the handler, such as page faults
where privileged software modifies the page tables and returns to the faulting instruction
which ultimately retires. Trying to distinguish the two cases leads to complex rules, so
instead the rule is simply that all traps match. See also Section 4.5.2.
When count is greater than 1 and the trigger matches, then count is decremented by 1.
When count is 1 and the trigger matches, then pending becomes set. In addition count will become 0
unless it is hard-wired to 1.
The only exception to the above is when the instruction the trigger matched on is a write to the icount
trigger. In that case pending might or might not become set if count was 1. Afterwards count contains
When pending is set, the trigger fires just before any further instructions are executed in a mode
where the trigger is enabled. As the trigger fires, pending is cleared. In addition, if count is hard-wired
to 1 then m, s, u, vs, and vu are all cleared.
If the trigger fires with action=0 then zero is written to the tval CSR on the breakpoint trap.
The intent of pending is to cleanly handle the case where action is 0, m is 0, u is 1, count is
1, and the U-mode instruction being executed causes a trap into M-mode. In that case we
want the entire M-mode handler to be executed, and the debug trap to be taken before the
next U-mode instruction.
This trigger type is intended to be used as a single step for software monitor programs or
native debug. Systems that support multiple privilege modes that want to debug software
running in lower privilege modes don’t need to support count greater than 1.
If textra32 or textra64 are implemented for this trigger, it only matches when the conditions set there
are satisfied.
4 1 XLEN - 32 1 1 1 14 1 1 1 1 6
It can be enabled for individual interrupt numbers by setting the bit corresponding to the interrupt
number in tdata2. The interrupt number is interpreted in the mode that the trap handler executes in.
(E.g. virtualized interrupt numbers are not the same in every mode.) In addition the trigger can be
enabled for non-maskable interrupts using nmi.
If XLEN is 32, then it is not possible to set a trigger for interrupts with Exception Code
larger than 31. A future version of the RISC-V Privileged Spec will likely define interrupt
Exception Codes 32 through 47. Some of those numbers are already being used by the
RISC-V Advanced Interrupt Architecture.
Hardware may only support a subset of interrupts for this trigger. A debugger must read back tdata2
after writing it to confirm the requested functionality is actually supported.
When the trigger matches, it fires after the trap occurs, just before the first instruction of the trap
handler is executed. If action=0, the standard CSRs are updated for taking the breakpoint trap, and
zero is written to the relevant tval CSR. If the breakpoint trap does not go to a higher privilege mode,
this will lose CSR information for the original trap. See Section 5.4 for more information about this
case.
If textra32 or textra64 are implemented for this trigger, it only matches when the conditions set there
are satisfied.
4 1 1 XLEN - 19 1 1 1 1 1 1 1 6
This trigger may fire on up to XLEN of the Exception Codes defined in mcause (described in the
Privileged Spec, with Interrupt=0). Those causes are configured by writing the corresponding bit in
tdata2. (E.g. to trap on an illegal instruction, the debugger sets bit 2 in tdata2.)
If XLEN is 32, then it is not possible to set a trigger on Exception Codes higher than 31. A
future version of the RISC-V Privileged Spec will likely define Exception Codes 32 through
47.
Hardware may support only a subset of exceptions. A debugger must read back tdata2 after writing it
to confirm the requested functionality is actually supported.
When the trigger matches, it fires after the trap occurs, just before the first instruction of the trap
handler is executed. If action=0, the standard CSRs are updated for taking the breakpoint trap, and
zero is written to the relevant tval CSR. If the breakpoint trap does not go to a higher privilege mode,
this will lose CSR information for the original trap. See Section 5.4 for more information about this
case.
If textra32 or textra64 are implemented for this trigger, it only matches when the conditions set there
are satisfied.
4 1 1 XLEN - 19 1 1 1 1 1 1 1 6
This trigger fires when any selected TM external trigger input signals. Up to 16 TM external trigger
inputs coming from other blocks outside the TM, (e.g. signaling an hpmcounter overflow) can be
selected. Hardware may support none or just a few TM external trigger inputs (starting with TM
external trigger input 0 and continuing sequentially). Unsupported inputs are hardwired to be
inactive.
If the trigger fires with action=0 then zero is written to the tval CSR on the breakpoint trap. This
trigger fires asynchronously but it is subject to delegation by medeleg[3] like the other triggers.
The TM external trigger input can signal when the trigger is prevented from firing due to one of the
mechanisms in Section 5.4. An implementation may either ignore the signal altogether when it cannot
fire (dropping the trigger event) or it may hold the action as pending and fire the trigger once it is legal
to do so.
4 1 1 XLEN - 29 1 16 6
If DXLEN >= 64, then this register provides access to the low bits of each field defined in textra64.
Writes to this register will clear the high bits of the corresponding fields in textra64.
All functionality in this register is optional. Any number of upper bits of mhvalue and svalue may be
tied to 0. mhselect and sselect may only support 0 (ignore).
Byte-granular comparison of scontext to svalue allows scontext to be defined to include more than one
element of comparison. For example, software instrumentation can program the scontext value to be
the concatenation of different ID contexts such as process ID and thread ID. The user can then
program byte compares based on sbytemask to include one or more of the contexts in the compare.
Note that sselect and mhselect filtering apply in all modes, including M-mode and S-
mode. If desired, debuggers can use a trigger’s mode filtering bits to restrict the matching
to modes where it considers ASID/VMID/scontext/hcontext to be active.
6 3 3 2 16 2
3, 7 (reserved): Reserved.
This register is accessible as tdata3 when type is 2, 3, 4, 5, or 6 and XLEN=64. The function of the
fields are defined above, in textra32. This register retains its value when XLEN changes. When
XLEN=32 some of the bits can be accessed through textra32.
13 3 8 4 2 32 2
There may be multiple DTMs in a single hardware platform. Ideally every component that
communicates with the outside world includes a DTM, allowing a hardware platform to be debugged
through every transport it supports. For instance a USB component could include a DTM. This would
trivially allow any hardware platform to be debugged over USB. All that is required is that the USB
module already in use also has access to the Debug Module Interface.
Using multiple DTMs at the same time is not supported. It is left to the user to ensure this does not
happen.
This specification defines a JTAG DTM in Section 6.1. Additional DTMs may be added in future
versions of this specification.
An implementation can be compatible with this specification without implementing any of this
section. In that case it must be advertised as conforming to "RISC-V Debug Specification, with custom
DTM." If the JTAG DTM described here is implemented, it must be advertised as conforming to the
"RISC-V Debug Specification, with JTAG DTM.""
31 28 27 12 11 1 0
4 16 11 1
11 3 1 1 1 3 2 6 4
And so on.
dmistat Read-only alias of op. R 0
abits The size of address in dmi. R Preset
In Update-DR, the DTM starts the operation specified in op unless the current status reported in op is
sticky.
In Capture-DR, the DTM updates data with the result from that operation, updating op if the current
op isn’t sticky.
For instance a series of scans may write a Debug Program and execute it. If one of the
writes fails but the execution continues, then the Debug Program may hang or have other
unexpected side effects.
abits+33 34 33 2 1 0
address data op
abits 32 2
3 (reserved): Reserved.
1 (reserved): Reserved.
To make it easy to acquire debug hardware, this spec recommends a connector that is compatible with
the MIPI-10 .05 inch connector specification, as described in MIPI Debug & Trace Connector
Recommendations, Version 1.20, 2 July 2021.
The connector has .05 inch spacing, gold-plated male header with .016 inch thick hardened copper or
beryllium bronze square posts (SAMTEC FTSH or equivalent). Female connectors are compatible
gold connectors.
Viewing the male header from above (the pins pointing at your eye), a target’s connector looks as it
does in Table 17. The function of each pin is described in Table 18.
If a hardware platform requires nTRST then it is permissible to reuse the nRESET pin as the nTRST
signal, resulting in a MIPI 10-pin JTAG
nTRST connector.
The MIPI-10 connector should provide plenty of signals for all modern hardware. If a design does
need legacy JTAG signals, then the MIPI-20 connector should be used. Pins whose functionality isn’t
needed may be left unconnected.
Its physical connector is virtually identical to MIPI-10, except that it’s twice as long, supporting twice
as many pins. Its pinout is shown in Table 19. The function of each pin is described in Table 18.
GND 9 10 nRESET
GND 11 12 GND or RTCK
GND 13 14 NC or nTRST_PD
GND 15 16 nTRST or NC
GND 17 18 TRIGIN or NC
GND 19 20 TRIGOUT or GND
6.1.8. cJTAG
This spec does not have specific recommendations on how to use the cJTAG protocol.
When implementing cJTAG access to a JTAG DTM, the MIPI 10-pin Narrow JTAG connector should be
used. Pins whose functionality isn’t needed may be left unconnected.
Viewing the male header from above (the pins pointing at your eye), a target’s connector looks as it
does in Table 20.
Muxes on the register file(s) allow for accessing GPRs and CSRs using the Access Register abstract
command.
Memory is accessed using the Abstract Access Memory command or through System Bus Access.
This implementation could allow a debugger to collect information from the hart even when that hart
is unable to execute instructions.
When the halt request bit is set, the Debug Module raises a special interrupt to the selected harts. This
interrupt causes each hart to enter Debug Mode and jump to a defined memory region that is serviced
by the DM and is only accessible to the harts in Debug Mode. Accesses to this memory should be
uncached to avoid side effects from debugging operations. When taking this jump, pc is saved to dpc
and cause is updated in dcsr. This jump is similar to a trap but it is not architecturally considered a
trap, so for instance doesn’t count as a trap for trigger behavior.
The code in the Debug Module causes the hart to execute a "park loop." In the park loop the hart writes
its mhartid to a memory location within the Debug Module to indicate that it is halted. To allow the
DM to individually control one out of several halted harts, each hart polls for flags in a DM-controlled
memory location to determine whether the debugger wants it to execute the Program Buffer or
perform a resume.
To execute an abstract command, the DM first populates some internal words of program buffer
according to command. When transfer is set, the DM populates these words with lw <gpr>,
0x400(zero) or sw <gpr>, 0x400(zero). 64- and 128-bit accesses use ld/sd and lq/sq respectively. If
transfer is not set, the DM populates these instructions as nop’s. If postexec is set, execution continues
to the debugger-controlled Program Buffer, otherwise the DM causes an ebreak to execute
immediately.
When ebreak is executed (indicating the end of the Program Buffer code) the hart returns to its park
loop. If an exception is encountered, the hart jumps to an address within the Debug Module. The code
there causes the hart to write to the Debug Module indicating an exception. Then the hart jumps back
to the park loop. The DM infers from the write that there was an exception, and sets cmderr
appropriately. Typically the hart will execute a fence instruction before entering the park loop, to
ensure that any effects from the abstract command, such as a write to data0, take effect before the DM
returns busy to 0.
To resume execution, the debug module sets a flag which causes the hart to execute a dret. dret is an
instruction that only has meaning while in Debug Mode and not executing from the Program Buffer.
Its recommended encoding is 0x7b200073. When dret is executed, pc is restored from dpc and
normal execution resumes at the privilege set by prv and v, and the ELP state set by pelp.
data0 etc. are mapped into regular memory at an address relative to with only a 12-bit imm. The exact
address is an implementation detail that a debugger must not rely on. For example, the data registers
might be mapped to 0x400.
For additional flexibility, progbuf0, etc. are mapped into regular memory immediately preceding
data0, in order to form a contiguous region of memory which can be used for either program
execution or data transfer.
The PMP must not disallow fetches, loads, or stores in the address range associated with the Debug
Module when the hart is in Debug Mode, regardless of how the PMP is configured. The same is true of
PMA. Without this guarantee, the park loop would enter an infinite loop of traps and debug would not
be possible.
The DTM can start a request when the DM sets REQ_READY to 1. When this is the case REQ_OP can
be set to 1 for a read or 2 for a write request. The desired address is driven with the REQ_ADDRESS
signal. Finally REQ_VALID is set high, indicating to the DM that a valid request is pending.
The DM must respond to a request from the DTM when RSP_READY is high. The status of the
response is indicated by the RSP_OP signal (see op). The data of the response is driven to RSP_DATA.
A pending response is signalled by setting RSP_VALID.
Table 21. Signals for the suggested DMI between one DTM and one DM
Signal Width Source Description
REQ_VALID 1 DTM Indicates that a valid request is pending
REQ_READY 1 DM Indicates that the DM is able to process a request
REQ_ADDRESS abits DTM Requested address
REQ_DATA 32 DTM Requested data
REQ_OP 2 DTM Same meaning as the op field
RSP_VALID 1 DM Indicates that a valid respond is pending
RSP_READY 1 DTM Indicates that the DTM is able to process a respond
RSP_DATA 32 DM Response data
RSP_OP 2 DM Same meaning as the op field
To keep the examples readable, they all assume that everything succeeds, and that they complete
faster than the debugger can perform the next access. This will be the case in a typical JTAG setup.
However, the debugger must always check the sticky error status bits after performing a sequence of
actions. If it sees any that are set, then it should attempt the same actions again, possibly while adding
in some delay, or explicit checks for status bits.
To write an arbitrary Debug Bus register, select dmi, and scan in a value with op set to 2, and address
and data set to the desired register address and data respectively. From then on everything happens
exactly as with a read, except that a write is performed instead of the read.
It should almost never be necessary to scan IR, avoiding a big part of the inefficiency in typical JTAG
use.
B.2.3. Halting
To halt one or more harts, the debugger selects them, sets haltreq, and then waits for allhalted to
indicate the harts are halted. Then it can clear haltreq to 0, or leave it high to catch a hart that resets
while halted.
B.2.4. Running
First, the debugger should restore any registers that it has overwritten. Then it can let the selected
harts run by setting resumereq. Once allresumeack is set, the debugger knows the selected harts have
resumed. Harts might halt very quickly after resuming (e.g. by hitting a software breakpoint) so the
debugger cannot use allhalted/anyhalted to check whether the hart resumed.
Abstract commands are only required to support GPR access. To access non-GPR registers, the
debugger can use the Program Buffer to move values to/from a GPR, and then access the GPR value
using an abstract command.
With system bus access, addresses are physical system bus addresses.
Memory can be accessed through the Program Buffer by having the hart perform loads/stores.
Whether the addresses are physical or virtual depends on the system configuration.
Abstract memory accesses act as if they are performed by the hart, although the actual
implementation may differ.
With system bus access, addresses are physical system bus addresses.
Through the Program Buffer, the hart performs the memory accesses. Addresses are physical or virtual
(depending on and other system configuration).
Abstract memory accesses act as if they are performed by the hart, although the actual
implementation may differ.
B.2.9. Triggers
A debugger can use hardware triggers to halt a hart when a certain event occurs. Below are some
examples, but as there is no requirement on the number of features of the triggers implemented by a
hart, these examples might not be applicable to all implementations. When a debugger wants to set a
trigger, it writes the desired configuration, and then reads back to see if that configuration is
supported. All examples assume XLEN=32.
Enter Debug Mode when the instruction at 0x80001234 is executed, to be used as an instruction
breakpoint in ROM:
tdata1 0x6980105 type=6, dmode=1, action=1, select=0, match=0, m=1, s=1, u=1, vs=1, vu=1,
c execute=1
tdata2 0x8000123 address
4
Enter Debug Mode when performing a load at address 0x80007f80 in M-mode or S-mode or U-mode:
tdata1 0x68001059 type=6, dmode=1, action=1, select=0, match=0, m=1, s=1, u=1, load=1
tdata2 0x80007f80 address
Enter Debug Mode when storing to an address between 0x80007c80 and 0x80007cef (inclusive) in
VS-mode or VU-mode when hgatp.VMID=1:
tdata1 0 0x69801902 type=6, dmode=1, action=1, chain=1, select=0, match=2, vs=1, vu=1,
store=1
tdata2 0 0x80007c80 start address (inclusive)
textra32 0 0x03000000 mhselect=6, mhvalue=0
tdata1 1 0x69801182 type=6, dmode=1, action=1, select=0, match=3, vs=1, vu=1, store=1
tdata2 1 0x80007cf0 end address (exclusive)
Enter Debug Mode when storing to an address between 0x81230000 and 0x8123ffff (inclusive):
tdata1 0x698010da type=6, dmode=1, action=1, select=0, match=1, m=1, s=1, u=1, vs=1, vu=1, store=1
tdata2 0x81237fff 16 upper bits to match exactly, then 0, then all ones.
Enter Debug Mode when loading from an address between 0x86753090 and 0x8675309f or between
0x96753090 and 0x9675309f (inclusive):
tdata1 0 0x69801a59 type=6, dmode=1, action=1, chain=1, match=4, m=1, s=1, u=1, vs=1, vu=1,
load=1
tdata2 0 0xfff03090 Mask for low half, then match for low half
tdata1 1 0x698012d9 type=6, dmode=1, action=1, match=5, m=1, s=1, u=1, vs=1, vu=1, load=1
tdata2 1 0xefff8675 Mask for high half, then match for high half
When an exception occurs while executing the Program Buffer, command becomes set. The debugger
can check this field to see whether a program encountered an exception. If there was an exception, it’s
left to the debugger to know what must have caused it.
Halt the hart for a minimum amount of time to perform a single memory write:
This shows an example of setting the m bit in to enable a hardware breakpoint in M-mode. Similar
quick access instructions could have been used previously to configure the trigger that is being
enabled here:
Stepping code running in the same privilege mode as the debugger is more complicated, depending on
what other debug features are implemented.
If hardware implements mpte and mte, then stepping through non-trap code which doesn’t allow for
nested interrupts is also straightforward.
If hardware automatically prevents action=0 triggers from matching when entering a trap handler as
described in Section 5.4, then a carefully written trap handler can ensure that interrupts are disabled
whenever the icount trigger must not match.
If neither of these features exist, then single step is doable, but tricky to get right. To single step, the
debug stub would execute something like:
There is an additional problem with using icount to single step. An instruction may cause an exception
into a more privileged mode where the trigger is not enabled. The exception handler might address the
cause of the exception, and then restart the instruction. Examples of this include page faults, FPU
instructions when the FPU is not yet enabled, and interrupts. When a user is single stepping through
such code, they will have to step twice to get past the restarted instruction. The first time the exception
handler runs, and the second time the instruction actually executes. That is confusing and usually
undesirable.
To help users out, debuggers should detect when a single step restarted an instruction, and then step
again. This way the users see the expected behavior of stepping over the instruction. Ideally the
debugger would notify the user that an exception handler executed the first time.
The debugger should perform this extra step when the PC doesn’t change during a regular step.
It is safe to perform an extra step when the PC changes, because every RISC-V instruction
either changes the PC or has side effects when repeated, but never both.
To avoid an infinite loop if the exception handler does not address the cause of the exception, the
debugger must execute no more than a single extra step.
Index
A confstrptr2, 38
aampostincrement, 21 confstrptr3, 38
aamsize, 21 confstrptrvalid, 29
aamvirtual, 21 control, 37
aarpostincrement, 19 count, 85
aarsize, 19 custom, 47
abits, 94 custom0, 47
abstractauto, 37
abstractcs, 35 D
Access Memory, 20 data, 46, 47, 47, 47, 68, 71, 95
Access Register, 18 data0, 39
ackhavereset, 31 dataaccess, 34
ackunavail, 31 dataaddr, 34
action, 76, 81, 86, 87, 88, 89 datacount, 36
address, 45, 45, 45, 45, 95 datasize, 34
allhalted, 29 dcsr, 51
allhavereset, 28 debugver, 52
allnonexistent, 29 dmactive, 33
allresumeack, 29 dmcontrol, 30
allrunning, 29 dmcs2, 39
allunavail, 29 dmexttrigger, 40
anyhalted, 29 dmi, 95
anyhavereset, 28 dmireset, 94
anynonexistent, 29 dmistat, 94
anyresumeack, 29 dmode, 68
anyrunning, 29 dmstatus, 28
anyunavail, 29 dpc, 56
authbusy, 29 dscratch0, 57
authdata, 39 dscratch1, 57
authenticated, 29 dtmcs, 93
autoexecdata, 37 dtmhardreset, 94
autoexecprogbuf, 37
E
B ebreakm, 54
busy, 35 ebreaks, 54
BYPASS, 97 ebreaku, 54
ebreakvs, 53
C ebreakvu, 54
cause, 55 errinfo, 94
cetrig, 53 etrigger, 87
chain, 76, 82 execute, 78, 84
clrkeepalive, 32 extcause, 53
clrresethaltreq, 32
cmderr, 36 F
cmdtype, 19, 20, 21, 37 field, 8
command, 36
confstrptr0, 37 G
confstrptr1, 38 group, 40
grouptype, 40
H N
haltreq, 31 ndmreset, 33
haltsum0, 41 ndmresetpending, 28
haltsum1, 41 nextdm, 38
haltsum2, 42 nmi, 87
haltsum3, 42 nmip, 56
hartinfo, 33 nscratch, 34
hartreset, 31
hartsel, 30 O
hartselhi, 32 op, 96
hartsello, 32
hasel, 32 P
hasresethaltreq, 29 PartNumber, 93
hawindow, 35 pelp, 53
hawindowsel, 34, 34 pending, 85
hcontext, 70, 71 postexec, 19
hgselect, 41 priv, 58
hgwrite, 41 progbuf0, 39
hit, 73, 85, 86, 88, 89 progbufsize, 35
hit0, 80 prv, 56, 58
I Q
icount, 84 Quick Access, 20
IDCODE, 93
idle, 94 R
impebreak, 28 regno, 20
info, 69 relaxedpriv, 35
intctl, 89 resethaltreq, 30
itrigger, 86 resume ack bit, 29, 29
resumereq, 31
K
keepalive, 30 S
s, 77, 84, 85, 87, 88
L sbaccess, 43
load, 78, 84 sbaccess128, 44
sbaccess16, 44
M sbaccess32, 44
m, 77, 83, 85, 87, 88 sbaccess64, 44
ManufId, 93 sbaccess8, 44
maskmax, 72 sbaddress0, 44
match, 77, 83 sbaddress1, 45
mcontext, 71 sbaddress2, 45
mcontrol, 71 sbaddress3, 45
mcontrol6, 78 sbasize, 44
mhselect, 90 sbautoincrement, 43
mhvalue, 90 sbbusy, 43
mprven, 55 sbbusyerror, 43
mpte, 70 sbcs, 42
mscontext, 71 sbdata0, 46
mte, 70 sbdata1, 46
sbdata2, 47
sbdata3, 47 W
sberror, 44 write, 20, 21
sbreadonaddr, 43
sbreadondata, 43 Z
sbversion, 43 Zicfilp, 53
sbytemask, 90, 91
scontext, 70
select, 73, 80, 89
setkeepalive, 32
setresethaltreq, 32
shortname, 7
size, 81
sizehi, 72
sizelo, 75
Smdbltrp, 53, 53
sselect, 90
step, 56
stepie, 54
stickyunavail, 28
stopcount, 54
stoptime, 55
store, 78, 84
svalue, 90
T
target-specific, 21
tcontrol, 69
tdata1, 66
tdata2, 68
tdata3, 68
textra32, 89
textra64, 90
timing, 74
tinfo, 69
tmexttrigger, 88
transfer, 19
tselect, 66
type, 67
U
u, 77, 84, 86, 87, 88
uncertain, 79
uncertainen, 84
V
v, 55, 58
Version, 93
version, 30, 69, 95
vs, 79, 85, 87, 88
vu, 79, 85, 87, 88