J-Link RISC-V

From SEGGER Wiki
Jump to: navigation, search

This article handles J-Link related RISC-V specifics. It is assumed that RISC-V as a term is already known. For more generic information about RISC-V, please refer to the RISC-V knowledge base article

Memory accesses

The RISC-V debug specification defines multiple ways to access memory on a RISC-V based core:

  • Via program + data buffers (using program buffers to feed load / store instructions to the core)
  • Via system bus access (DMA-like access to memory)
  • Via abstract commands

When connecting to a RISC-V based core, J-Link will auto-detect which of the afore-mentioned memory access types are implemented and decides what access types to use by default.
The logic in J-Link is as follows:

//
// Determine memory access support on target side
//
if (NumDataBuf > 0) {
  SupportProgBuf = TRUE;
}
if (sbcs.sbasize > 0) {
  SupportSBA = TRUE;
}
SupportAAM = TRUE;
//
// Determine defaults used by J-Link while core is halted
//
if (SupportProgBuf == TRUE) {
  UseMemAccTypeWhileCoreHalted = MEM_ACC_PROG_BUF;
} else if (SupportSBA == TRUE) {
  UseMemAccTypeWhileCoreHalted = MEM_ACC_SBA;
} else {
  UseMemAccTypeWhileCoreHalted = MEM_ACC_AAM;
}
//
// Determine defaults used by J-Link while core is running
//
if (SupportSBA == TRUE) {
  UseMemAccTypeWhileCoreRunning = MEM_ACC_SBA;
} else {
  UseMemAccTypeWhileCoreRunning = MEM_ACC_NONE;
}

Implementation examples:

  • If an implementation supports SBA only, it should implement NumProgBuf = 0 and NumDataBuf = 0
  • If an implementation supports AAM only, it should implement NumProgBuf = 0 and NumDataBuf = 0 and sbcs.sbasize = 0.

Force default memory access type

Currently, there is no way to force J-Link to use a certain memory access type by default. This is planned for a future version of the J-Link software.

Watchpoint support

J-Link supports data breakpoints (watchpoints) for RISC-V CPUs which are based on the V0.13 standard of the RISC-V debug spec. In general, the following combinations are possible for a watchpoint:

  • Addr == EXACT, Data == EXACT
  • Addr == EXACT, Data == ANY
  • Addr == EXACT, Data == RANGE
  • Addr == RANGE, Data == EXACT
  • Addr == RANGE, Data == ANY
  • Addr == RANGE, Data == RANGE
  • Addr == ANY, Data == EXACT
  • Addr == ANY, Data == ANY
  • Addr == ANY, Data == RANGE

Note: Right now, only the ones shown in bold are supported by J-Link

JTAG chain auto-detection

When using cJTAG / JTAG as target interface, is it possible to have multiple devices / TAPs inside the same device, daisy-chained.
For JTAG, J-Link has an algorithm to detect which TAP to select by default. The algorithm is explained below:

  • If a TAP with IRLen = 5 and TAPId == known RISC-V TAP, it is selected as the TAP to be used
  • If a TAP with IRLen = 4 and TAPId == known CoreSight DAP TAP, it is selected as the TAP to be used (RISC-V behind DAP is assumed)
  • If no TAP with a TAPId == known RISC-V / DAP TAP is found, but there is only 1 TAP in the chain and it has IRLen = 4 or IRLen = 5, it is selected as the TAP to be used

Note: While for most cores like ARM, the TAPId is more or less standardized, for RISC-V almost every vendor does their own TAPId.

Example setups

In the following, some example setups are given and the default outcome regarding TAP selection is explained:

TAPs are counted from TDO to TDI, so the TAP closest to TDO is TAP_0:
TDI -> TAP_n -> ... -> TAP_1 -> TAP_0 -> TDO

Case 1:
TAP_0: IRLen = 5, TAPId = Known RISC-V TAP
=> J-Link will automatically select TAP_0 as the one to be used for the current debug session

Case 1:
TAP_0: IRLen = 5, TAPId == Unknown TAP
=> J-Link will automatically select TAP_0 as the one to be used for the current debug session

Case 3:
TAP_0: IRLen = 5, TAPId == Unknown TAP
TAP_1: IRLen = 5, TAPId == Known RISC-V TAP
=> J-Link will automatically select TAP_1 as the one to be used for the current debug session

Case 4:
TAP_0: IRLen = 5, TAPId == Known RISC-V TAP
TAP_1: IRLen = 5, TAPId == Unknown TAP
=> J-Link will automatically select TAP_0 as the one to be used for the current debug session


Case 5:
TAP_0: IRLen = 5, TAPId == Known RISC-V TAP
TAP_1: IRLen = 4, TAPId == Known DAP TAP
=> J-Link will automatically select TAP_0 (RISC-V) as the one to be used for the current debug session

Case 6:
TAP_0: IRLen = 4, TAPId == Known DAP TAP
TAP_1: IRLen = 5, TAPId == Known RISC-V TAP
=> J-Link will automatically select TAP_0 (DAP) as the one to be used for the current debug session

Case 7:
TAP_0: IRLen = 5, TAPId == Known RISC-V TAP
TAP_1: IRLen = 5, TAPId == Known RISC-V TAP
=> J-Link will automatically select TAP_0 as the one to be used for the current debug session

Case 8:
TAP_0: IRLen = 5, TAPId == Unknown TAP
TAP_1: IRLen = 5, TAPId == Unknown TAP
=> User needs to manually select the TAP to be used

Case 9:
TAP_0: IRLen = 5, TAPId == Unknown TAP
TAP_1: IRLen = 4, TAPId == Known DAP TAP
=> J-Link will automatically select TAP_1 as the one to be used for the current debug session

If the algorithm above does not fit for a specific setup, the user needs to tell J-Link which TAP in the chain to use.
Please refer to the appropriate wiki article of the software utility in use, for more information.
For example, for J-Link Commander, the JTAGConf command is used.
An alternative way (e.g. in case even the JTAG chain detection cannot be used for some reason) is to manually setup the JTAG chain via J-Link script file:
Below are two example script for a JTAG chain that consists of 2 CPU-TAPs (each a RISC-V with IRLen == 5) that specifies to connect to TAP #0 or #1 resprectively.

RISC-V behind a CoreSight DAP

The official debug spec. for RISC-V only describes how to implement a RISC-V debug interface via JTAG and a DM. The topology looks like this:

JTAG TAP -> DM -> DMI registers

However, for hybrid designs where there are for example ARM cores next to the RISC-V in the same system, it makes sense to put the RISC-V behind a DAP; so the ARM cores and the RISC-V can be accessed via the same debug connector and also other protocols like SWD can be supported this way. The topology looks like this:

JTAG/SWD -> SWJ-DP -> APB-AP -> DMI registers
or
JTAG/SWD -> SWJ-DP -> AHB-AP -> DMI registers

When using RISC-V behind a DAP, some considerations need to be taken into account:

  • There is no ROM table scan available for RISC-V
  • J-Link cannot auto-detect behind which AP the RISC-V can be found
  • J-Link cannot auto-detect where in the AP address space the RISC-V DMI registers can be found
  • For such setups, the user needs to manually specify where to find the RISC-V core in the DAP setup

Example script file to specify location of RISC-V in DAP setup:

void ConfigTargetSettings(void) {
  //
  // Specify AP map and where to find each AP in the CoreSight address space:
  //
  JLINK_ExecCommand("CORESIGHT_AddAP = Index=0 Type=AHB-AP BaseAddr=0x00002000");  // AP0: AHB-AP that connects to Cortex-M4 core in chip
  JLINK_ExecCommand("CORESIGHT_AddAP = Index=1 Type=APB-AP BaseAddr=0x00004000");  // AP1: APB-AP that connects to RISC-V core in chip
  JLINK_ExecCommand("CORESIGHT_AddAP = Index=2 Type=AXI-AP BaseAddr=0x00006000");  // AP2: AXI-AP that allows DMA like access to system memories
  //
  // Setup parameters for RISC-V connection
  // If RISC-V is behind an APB-AP, use "CORESIGHT_SetIndexAPBAPToUse"
  // If RISC-V is behind an AHB-AP, use "CORESIGHT_SetIndexAHBAPToUse"
  //
  JLINK_ExecCommand("CORESIGHT_SetIndexAPBAPToUse = 1");  // AP (from previously specified AP map) that connects to the RISC-V DMI registers
  JLINK_ExecCommand("CORESIGHT_SetCoreBaseAddr = 0x0");   // Address in AP address space where DMI registers can be found
  return 0;
}

Note: If a specific device (manufacturer + name) is selected in the J-Link software and not a generic RV32 / RV64,
J-Link usually has a compiled-in script available for that device which already specifies the parameters from above, so the user does not need to create such a script file.

For more information about J-Link script files and how to use them, please refer to the wiki article: J-Link script files