6 Trigger Module
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. These are all features that can be useful without having the Debug Module present, so the Trigger Module is broken out as a separate piece that can be implemented separately.
A hart can be compliant with this specification without implementing any trigger functionality at all, but if it is implemented then it must conform to this section.
Triggers do not fire while in Debug Mode.
Each trigger may support a variety of features. A debugger can build a list of all triggers and their features as follows:
Write 0 to tselect
.
Read back tselect
and check that it contains the written value. If not,
exit the loop.
Read tinfo
.
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.)
If info
is 1, this trigger doesn’t exist. Exit the loop.
Otherwise, the selected trigger supports the types discovered in info
.
Repeat, incrementing the value in tselect
.
It is possible for a trigger with the “enter Debug Mode” action (1) and another
trigger with the “raise a breakpoint exception” action (0) to fire at the same
time. 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. What happens with
trace actions when triggers with different actions are also firing is left to
the trace specification.
6.1 Native M-Mode Triggers
Triggers can be used for native debugging. On a fully featured system triggers
will be set using u
or s
, and when firing they can cause a breakpoint exception
to trap to a more privileged mode. It is possible to set triggers natively to
fire in M mode as well. In that case there is no higher privilege mode to trap
to. When such a trigger causes a breakpoint exception while already in a trap
handler, this will leave the system unable to resume normal execution.
On full-featured systems this is a remote corner case that can probably be ignored. On systems that only implement M mode, however, it is recommended to implement one of two solutions to this problem. This way triggers can be useful for native debugging of even M mode code.
The simple solution is to have the hardware prevent triggers with action=0 from
firing while in M mode and while in mstatus
is 0. Its limitation is
that interrupts might be disabled at other times when a user might want
triggers to fire.
A more complex solution is to implement mte
and mpte
in tcontrol
. This
solution has the benefit that it only disables triggers during the trap
handler.
A user setting M mode triggers that cause breakpoint exceptions will have to be aware of any problems that might come up with the particular system they are working on.
6.2 Trigger Registers
These registers are CSRs, accessible using the RISC-V csr
opcodes and
optionally also using abstract debug commands.
Most 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 already
what is
supported. Writes to one tdata
register may not modify the contents of
other tdata
registers, nor the configuration of any trigger besides the
one that is currently selected.
The above algorithm reads back
tselect
so that implementations which have 2n triggers only need to implement n bits oftselect
.The algorithm checks
tinfo
andtype
in case the implementation has m bits oftselect
but fewer than 2m triggers.