FAQs for RISC-V Debugger

The embedded tools company

Search FAQs

PDF document ( 148KB / 27-Mar-2022 )

[System Designer] How are instruction- and data caches handled by the Lauterbach RISC-V debugger?
Ref: 0578

Unfortunately, the RISC-V debug specification does not define an explicit, standardized way to handle instruction- or data caches. Nevertheless, in some scenarios a debugger and/or the debug IP need to be able to trigger certain cache operations, such as cache flushes.

Example #1:
Let's assume an SoC with a single RISC-V core with instruction cache. The core's instruction memory contains a RISC-V instruction 'A'. The RISC-V core gets halted some instructions before the execution of 'A'. The core has not executed 'A' yet, however it has already loaded 'A' into its instruction cache, and into its instruction pipeline. Now the debugger sets a software breakpoint onto 'A', which means it (temporarily) replaces 'A' with an 'EBREAK' instruction. After that, the debugger lets the core resume again. In order to achieve that the core will execute the new 'EBREAK' instruction instead of the originally cached 'A' instruction, the debugger needs to flush the core's instruction cache and instruction pipeline before letting the CPU resume.

Example #2:
Let's assume an SoC with multiple RISC-V cores with data caches. Each core is halted. Each core has already cached the memory data 'X' of an address 'B' in their respective data cache. Now, the debugger uses the direct system bus access to write new data 'Y' into the data memory at address 'B'. When the debugger resumes the cores now, it needs to make sure that each core's data cache does not contain a the old/outdated data 'X' any more. That is why the debugger needs to flush each core's data cache before letting the cores resume, or before reading any memory content from the perspective of one of the cores.

In order to solve the above example scenarios and other scenarios, the debugger uses the program buffer execution of the 'FENCE' and/or 'FENCE.I' instructions. According to the RISC-V ISA specification, these instructions must ensure that a cache and/or pipeline flush (or an equivalent chip-specific operation) will happen, if applicable to the respective chip and if needed in the respective scenario.

The following points show example scenarios in which the debugger usually uses the FENCE and FENCE.I instructions. Of course the described behavior may not always be applicable, and may also change in future debugger versions.

  1. Resume core: Before the debugger lets a core resume, it will execute both a 'FENCE' and 'FENCE.I' instruction via program buffer.
  2. Read memory via core: Before the debugger reads memory from perspective of a core (via program buffer or 'access memory' abstract command), it will execute a 'FENCE' instruction via program buffer.
  3. Write memory via core: After the debugger has written memory from perspective of a core (via program buffer or 'access memory' abstract command), it will execute a 'FENCE' instruction via program buffer.
The above actions by the debugger are only possible if the hardware's debug IP does have a program buffer with sufficient size. In that case, the debugger will execute the described steps independent of whether the respective core does have any caches or not.
If the hardware's debug IP does however NOT have any program buffer (or a program buffer of insufficient size), then the debugger must assume that the debug IP will automatically handle all respective scenarios itself.

[System Designer] Which combinations of 'mcontrol' on-chip triggers are supported?
Ref: 0546

The RISC-V debug specification defines a trigger module, which holds a set of triggers. Each trigger can be individually configured for one of multiple trigger types (such as 'mcontrol'), and depending on the trigger type the trigger can be configured with various options. The debug specification allows system designs with heterogeneous trigger capabilities, which means not every trigger must support the same trigger types and same trigger type configuration options.

The following are the requirements for the trigger type 'mcontrol' in order to be compatible with the current version of the Lauterbach RISC-V debugger:

  • The debugger only uses the largest contiguous block of triggers that support the type 'mcontrol'. Example: if only trigger indexes 1, 4, 5, 6, 9 support type 'mcontrol', then the debugger will only use the contiguous block of indexes 4, 5, 6.

  • Each mcontrol trigger has various optional configuration options (execute, store, load, chain, ...). The debugger currently only uses configuration options that are supported by all triggers of the contiguous mcontrol block (see above). The exception is the 'chain' option, which is used if it is supported by all except the last trigger in that block.

[System Designer] Which core registers (CSRs) are needed by the debugger?
Ref: 0531

The debugger does not only need access to debug registers of the Debug Module. In order to function properly, several core registers (Control and Status Registers, CSRs) need to be accessible/implemented as well. The following summary lists CSRs that stand in the context of debugging, and mentions whether they are needed or not:

Core Debug Registers
  • Debug Control and Status (dcsr)
    1. Mandatory register. Without it, debug support is not possible.
  • Debug PC (dpc)
    1. Mandatory register. Without it, debug support is not possible.
  • Debug Scratch Register 0/1 (dscratch0/1)
    1. Optional register. The Lauterbach debugger does currently not use these registers.

Debug/Trace Registers
  • Debug/Trace trigger register select (tselect):
    1. [debug spec v0.13.x]: Mandatory, no matter if triggers are implemented or not
    2. [debug spec v0.14.x and later]: Mandatory if any triggers are implemented, otherwise optional
  • First Debug/Trace trigger data register (tdata1):
    1. [debug spec v0.13.x]: Mandatory, no matter if triggers are implemented or not
    2. [debug spec v0.14.x and later]: Mandatory if any triggers are implemented, otherwise optional
  • Second Debug/Trace trigger data register (tdata2):
    1. Mandatory if any triggers are implemented, otherwise optional
  • Third Debug/Trace trigger data register (tdata3):
    1. Optional register (from debugger perspective). Currently the debugger does only support match control triggers, for which tdata3 is not used. Might however be used for other trigger types in the future.
  • Trigger Info (tinfo):
    1. Mandatory if triggers are implemented and the "trigger type bitfield" (tdata1->type) is writable. Otherwise optional.

Machine-Level Control and Status Registers (Machine-Level CSRs)
  • Machine ISA Register (misa):
    1. This register helps the debugger to determine the capabilities of the core under debug.

      It helps to determine the base ISA of the core. Also, it helps to determine supported ISA extensions such as e.g. floating-point ("F"/"D"), for which the debugger needs to access and display additional floating-point registers.

      If this register is not implemented, the debugger has to fall back to less reliable and intrusive try & error methods to determine the information mentioned above. In some cases, an automatic detection of the respective information may not be possible at all. Therefore, it is highly recommended to implement this register, so that the debugger can work in a reliable and minimally-intrusive way.

[System Designer] Which features, debug registers, and debug register bitfields that are declared as "optional" are needed by the debugger?
Ref: 0530

Some parts of the RISC-V debug specification are very generic and leave room for optional features and optional implementations. Several debug registers of the Debug Module (DM), bitfields of these registers or whole features are declared as 'optional'. The following lists all optional features, debug registers as well as all debug registers that contain optional bitfields, and describes whether they are currently needed by the debugger.

Please note that this list can change at any time in the future. If a register or bitfield is not in this list, then the debug specification sees it as non-optional, and consequently it is always required by our debugger.

  1. Abstract Data 0 - 11 (data0 - data11): The required amount of dataX registers depends on several factors, such as base ISA (RV32, RV64, ...) of all cores that are connected to the RISC-V debug module. Also it depends on the implemented set of features in the debug module, in particular the implemented abstract commands. Please refer to the RISC-V debug specification for details.
    In most standard RISC-V chips the following applies: if the debug module only addresses RV32 cores then at least data0 is needed, however if the debug module addresses at least one RV64 core then at least data0 and data1 are needed.

  2. Debug Module Control (dmcontrol):
    1. hasel bitfield: Recommended for multicore debugging, as this allows a synchronized start and stop of multiple RISC-V cores via hardware.
      If there are multiple RISC-V cores connected to a debug module and 'hasel' is not supported, then the debugger can not start/stop all cores simultaneously, but only consecutively.
      If there is only one RISC-V core connected to a debug module, then this bit is not needed.

  3. Hart Info (hartinfo): Currently this register is not used, as the debugger does not use programs that do explicitly access data or dscratch registers. Future versions of the debug driver might make use of the fact that programs that directly access data or dscratch registers are faster. Compatibility for such future performance improvements is only possible if this register is implemented. If it is not implemented the debug driver will still work, but without these performance improvements.

  4. Abstract Command Autoexec (abstractauto): Although this register is declared as optional, we highly recommend to implement it. The 'autoexecdata[0]' feature bit allows significant performance boosts when executing multiple consecutive abstract commands. This is e.g. extensively used during memory read/write via program buffer or abstract command.
    Our debug driver does however also support designs that do not support this optional feature.

  5. Program Buffer 0 - 15 (progbuf0 - progbuf15): The debug specification allows program buffer sizes between 0 and 16. A size of 0 means that there is no program buffer at all. In general there are two main ways of implementing a valid RISC-V debug IP (both of which are described in the RISC-V debug specification in more detail):

    1. Abstract Command Based Approach: All main operations and interactions of the debugger are done via abstract commands. In this case, no program buffer is needed, so program buffer size can be 0.

      However, the current ratified debug specifications v0.13.x/0.14.x/1.0.x do not provide a proper mechanism to detect/discover if a certain abstract command type is supported, and which individual options of an abstract command are supported. In particular, this affects the debugger system discovery for the 'access memory' abstract command , which is why Lauterbach can currently only provide limited support for this abstract command. See the discussions of the official RISC-V debug workgroup for more details. Due to these discrepancies regarding system discovery of abstract commands, we currently recommend to use the "Execution Based" approach instead until the issues with system discovery are resolved.

      That is why the 'access memory' abstract command can currently only be supported by our debugger, if all possible options and combinations of the 'aamsize', 'aampostincrement' and 'write' bitfields of that command are supported by the hardware.
      To tell the debugger to use this abstract command as default method for memory access, configure "SYStem.MemAccessStop AAM".

      Cache coherency: the 'access memory' abstract command and the RISC-V debug specification in general do not provide a standardized mechanism to operate on instruction- or data caches of the CPU. If there is no program buffer, then the debugger can not ensure cache coherency by itself, so the hardware needs to automatically ensure cache coherency on its own (e.g. execute cache flushes when the debugger initiates a respective access memory abstract command - if needed). See FAQ question "How are instruction- and data chaches handled by the Lauterbach RISC-V debugger?" for details.

    2. Execution Based Approach: The main operations and interactions of the debugger do partially rely on the program buffer execution.

      In this case the Lauterbach debugger currently uses the program buffer in a variety of scenarios, and there might be added additional scenarios in the future, or existing scenarios and behaviors change due to bug fixes or improvements. Therefore it is difficult to "recommend" a certain (small) program buffer size without knowing whether this size might be sufficient for all features in the future. Also, the required program buffer size depends on whether the 'implicit ebreak' feature is implemented (dmstatus.impebreak).
      What can be said however is that, as of the current implementation of the debug driver (state 2021-03-16), a program buffer size of 3 (without implicit ebreak) or 2 (with implicit ebreak) is the minimum that is sufficient for all currently available features.
      However it is not unlikely that an advanced and improved future driver might require (or at least could make good use of) a larger program buffer.

      In summary, in case that a system designer wants to stay on the safe side for future updates of the driver, and if chip area is not quite that important, then we suggest a full program buffer size of 16. However, as mentioned, the current minimum size mentioned above is also sufficient. Also, in case that the driver will add functions that require a size larger than the minimum size mentioned above, we will always leave a "fallback" option with possibly reduced functionality for hardware with smaller program buffer sizes. Hardware with a program buffer size that is smaller than the requirements mentioned above can however not work with our debug driver, if you go with the "execution based" approach.

      Cache coherency: the RISC-V debug specification in general does not provide a standardized mechanism to operate on instruction- or data caches of the CPU. However, the existence of a program buffer allows the debugger to execute "FENCE" and/or "FENCE.I" instructions. This allows the debugger to ensure cache coherency, by executing these instructions before/after certain debugger operations. See FAQ question "How are instruction- and data chaches handled by the Lauterbach RISC-V debugger?" for details.

  6. System Bus Address (sbaddress0/1/2) + System Bus Data (sbdata0/1/2/3): These optional registers are only needed if you want to access memory via the system bus. The debugger can also work without system bus access. Whether you need the system bus access or not depends on the individual needs of the user and on the target architecture.

  7. Halt summary registers:
    1. haltsum0/1/2/3: Currently not used by the debugger.

Can non-standard / custom RISC-V ISA extensions be supported?
Ref: 0528

The RISC-V ISA specification defines ISA extensions, which can complement a base ISA set with certain additional instructions. Despite the standard ISA extensions, the ISA specification also standardizes a way to define own non-standard / custom ISA extensions.

There are a different options how custom, non-standard ISA extensions can be supported by our tool:

  1. Direct Integration: In some circumstances Lauterbach can directly add support for certain custom ISA extensions to TRACE32. This mainly affects the disassembler and optionally the instruction set simulator and/or trace support. The support for the custom extensions can then be enabled by e.g. selecting the corresponding CPU entry via the SYStem.CPU command. If and under which circumstances such a direct integration into our software can be provided needs to be discussed individually.

  2. Disassembler plugin via APU API: Lauterbach provides an API that allows users to load their own custom "disassembler plugin" (via shared library such as *.dll or *.so), in order to extend the Lauterbach disassembler functionality by own non-standard instructions of ISA extensions. This API is called "API for Auxiliary Processing Unit" (APU API). More information can be found at https://www.lauterbach.com/pdf/api_apu.pdf

    The advantages of using such a plugin are:
    1. Users can test their ISA extension(s) already in very early stages of their chip and toolchain development and have full control over any changes.
    2. There is no license arrangement with Lauterbach required.
    3. It is not necessary to reveal details about the ISA extensions to Lauterbach or any other party (beneficial for confidential extensions).

    In order to support instruction trace decoding in combination with custom instructions, the APU API allows to mark program flow control instructions with certain jump flags and allows to define jump target addresses. See restrictions mentioned below.

    Please be aware of the restrictions of using a RISC-V APU API disassembler plugin:
    1. The APU API is not supported by the TRACE32 instruction set simulator. Lauterbach does provide an API for the simulator, however this API only allows to simulate periphery behavior (https://www.lauterbach.com/pdf/simulator_api.pdf) and not behavior of a whole core.
    2. If there are custom instructions with more complex program flow control behavior, then it needs to be discussed individually if and how trace support can be covered by the generic interface of the APU API.

Which RISC-V base ISAs are supported?
Ref: 0526

The RISC-V specification defines base ISAs for 32bit (RV32), 64bit (RV64) and 128bit (RV128). The Lauterbach debug driver generally supports core architectures with RV32 and RV64 base ISA. However, RV128 ISA cores are currently not supported.

Which standard RISC-V ISA extensions are supported?
Ref: 0527

The RISC-V ISA specification defines certain standard ISA extensions, which can complement a base ISA set with certain additional instructions (e.g. the "A" extension for atomic instructions).

Our RISC-V debugger supports all standard ISA extensions that are defined in the RISC-V ISA specification. This includes support by our disassembler and instruction set simulator. For certain special extensions such as floating point extensions ("F"), our RISC-V debugger can display the content of additional floating point registers and modify their values. Our support covers any valid combination of these standard ISA extensions.

Which versions of the RISC-V debug specification are supported by the Lauterbach debugger?
Ref: 0525

The Lauterbach RISC-V debugger does support designs based on the official RISC-V debug specification (see link to the RISC-V homepage below).
The first officially ratified debug spec version was version v0.13, which is why our debugger supports all v0.13.x versions and any versions after that. However any unofficial draft versions before the first ratified v0.13 (such as v0.11) are not supported.

Also be aware that conformity of RISC-V hardware with the official RISC-V debug specification is not the only criterion for seamless compatibility with Lauterbach tools. The hardware should also meet the requirements that are listed in the "RISC-V Debugger" FAQ category on our homepage, in all questions that have the prefix "[System Designer]" .

Which ways of integrating a RISC-V debug module into a SoC are currently supported?
Ref: 0529

Please see the Lauterbach RISC-V debugger manual (link below), chapter "Quick Start for Debug Module Configuration" for details.

Copyright © 2023 Lauterbach GmbH, Altlaufstr.40, 85635 Höhenkirchen-Siegertsbrunn, Germany   Impressum     Privacy Policy
The information presented is intended to give overview information only.
Changes and technical enhancements or modifications can be made without notice. Report Errors
Last generated/modified: 02-Jan-2023