6.1. OpenOCD Usage Guide

This document provides comprehensive guidance on OpenOCD installation, configuration, and usage for Nuclei RISC-V CPUs.

6.1.1. Table of Contents

6.1.2. Tool Installation and Environment Setup

Download and install the latest version of the OpenOCD tool from the Nuclei official website: https://nucleisys.com/download.php

After downloading and extracting to the installation directory, add the following directory to the PATH environment variable:

  • Nuclei\OpenOCD\xxx\bin

6.1.3. Repositories and Documentation

OpenOCD Repositories

GitHub (RISC-V OpenOCD) Repository.

Gitee (RISC-V OpenOCD) Repository.

OpenFlashLoader

Note

The OpenOCD Flashloader enables support for various customized flash programming implementations without requiring modifications to OpenOCD itself. For detailed usage instructions, please refer to the documentation in the source code repository.

GitHub (OpenFlashLoader) Repository.

Gitee (OpenFlashLoader) Repository.

Note

Nuclei OpenOCD is modified based on OpenOCD with some customized features, so in this guide, we don’t provide any detailed usage about openocd, please directly refer to the openocd.pdf in our released Nuclei OpenOCD package.

OpenOCD User Guide Location: openocd/doc/pdf/openocd.pdf

6.1.4. Getting Started

6.1.4.1. Checking OpenOCD Version

To determine the installed OpenOCD version:

  1. Open a command prompt (Windows) or terminal (Linux)

  2. Execute the command: openocd -v to see version output

../_images/openocd-v.png

Note

Version Information parsed for above screenshot not for current release:

  • Git Commit ID: 787e48e66

  • Compile Date: 2022-12-29 08:49

6.1.4.2. Running OpenOCD

Common Command Line Parameters

Parameter

Description

-v

Display version information

-d

Set debug level to 3

-d0

Error messages only

-d1

Error and warning messages

-d2

Error, warning, and info (default)

-d3

Error, warning, info, and debug messages

-d4

All messages including low-level debug

-f file

Use specified configuration file

-s dir

Directory to search for config files

-l logfile

Redirect log output to specified file

6.1.5. Nuclei-Specific Features

6.1.5.1. CPU Information Display

The nuclei cpuinfo command provides detailed information about the CPU’s capabilities, including:

  • Supported instruction sets

  • Available functional components

  • Component configurations

This command simplifies the process of querying CPU features by automatically reading and interpreting the relevant CSR (Control and Status Register) values, eliminating the need for manual register inspection and calculation.

This command implementation is updated with latest nuclei sdk 0.9.0 cpuinfo to provide same analysis using same source code and more detailed information are analyzed from 2025.10 release.

When you use riscv64-unknown-elf-gdb to connect to Nuclei OpenOCD GDB debug server, you will be able to use command monitor nuclei cpuinfo to dump Nuclei Detailed CPU Information.

6.1.5.2. NUSPI (Nuclei SPI) Driver

The NUSPI driver provides support for Nuclei’s SPI controller, which is utilized in Nuclei RISC-V FPGA evaluation boards and other compatible hardware.

Usage:

flash bank name nuspi base size chip_width bus_width target spi_base [simulation]

6.1.5.3. Custom Driver with OpenFlashLoader

The custom driver provides compatibility with various SPI controllers and flash memory types. When using this driver, it must be combined with the OpenFlashLoader to achieve optimal functionality.

Usage:

flash bank name custom base size chip_width bus_width target spi_base flashloader_path [simulation] [sectorsize=]

flashloader_path could be one of the following:

Note

This requires 2025.10 version to provide correct path search handling.

  • Absolute path: eg. C:\\flashloader\\loader.bin or /home/loader/loader.bin

  • Relative path: eg. loader.bin, it will search under where openocd executed, and scripts folder of where openocd installed such as toolchain/openocd/scripts

6.1.5.4. Nuclei-Specific CSRs

The Nuclei version of OpenOCD supports several custom CSRs (Control and Status Registers). For a complete list and detailed information, refer to:

GitHub (src/target/riscv/encoding.h).

Gitee (src/target/riscv/encoding.h).

6.1.5.5. Embedded Trace (ETrace) Support

Note

The ETrace feature is currently in the experimental stage and should not be used in production environments.

Some Nuclei CPUs include embedded trace support, enabling detailed examination of instruction execution. The trace functionality is managed through an Embedded Trace (ETrace) module integrated into the CPU’s scan chains.

Current Implementation:

  • RISC-V ETrace Instruction Trace (available)

  • Data Trace (not yet implemented)

ETrace Commands:

  1. Configuration:

    • nuclei etrace config etrace-addr buffer-addr buffer-size wrap: Initializes ETrace and configures operational parameters

  2. Control:

    • nuclei etrace enable: Activates ETrace functionality

    • nuclei etrace disable: Deactivates ETrace functionality

    • nuclei etrace start: Begins trace data collection

    • nuclei etrace stop: Stops trace data collection

  3. Data Management:

    • nuclei etrace dump filename: Exports captured trace data to a file

    • nuclei etrace clear: Resets trace buffer pointers

    • nuclei etrace info: Displays current ETrace status

Note

For detailed command documentation, please refer to openocd.pdf. The ETrace feature is also available in Nuclei Studio IDE.

6.1.5.6. Debug Map Feature

Note

The debug map for each hardware thread (hart) is automatically read and displayed during OpenOCD initialization. Alternatively, you can access the debug map at runtime using the examine_cpu_core command.

For detailed documentation about the Nuclei debug map feature, please contact your application engineer.

Commands:

  • nuclei expose_cpu_core

    • Configures the list of indices for nuclei_examine_cpu_core

    • Must be executed before the init command

  • nuclei examine_cpu_core

    • Returns a 64-bit value combining dm-custom1 and dm-custom2 registers

    • Value calculation: (dm-custom2 << 32) + dm-custom1

6.1.5.7. Cross-Trigger Interface (CTI)

The Cross-Trigger Interface (CTI) provides an advanced debugging mechanism that enables developers to:

  • Trigger specific debugging actions

  • Synchronize multiple debugging-related events

Available Commands:

  • nuclei cti halt_group on/off target_name0 target_name1 ...

    • Controls halt group triggers

  • nuclei cti resume_group on/off target_name0 target_name1 ...

    • Controls resume group triggers

6.1.5.8. Debug with Hypervisor

Need 2025.10 version to work with, only work with riscv virt2phys_mode sw, see riscv-openocd issue #1278

6.1.5.9. Reset and Halt Command

The init resethalt command addresses situations where:

  • The CPU becomes unresponsive due to software issues, the debugger and development board cannot establish a normal connection, and debugging is still not possible after power cycling or software reset.

The init resethalt command works by sending a reset and halt request to the CPU via the JTAG interface. After reset, the CPU automatically enters the halt state after executing only one instruction, preventing it from running problematic software code and enabling normal debugging.

6.1.5.10. FTDI nSCAN1 Mode Command

The ftdi nscan1_mode command controls Nuclei’s Compact JTAG (cJTAG) mode functionality.

Usage:

ftdi nscan1_mode on|off

  • on: Means select 2-wire cJTAG mode

  • off: Means select 4-wire JTAG mode

Note

This command follows the same syntax and behavior as the standard ftdi oscan1_mode command.

6.1.6. Configuration File Overview

The OpenOCD configuration file defines how to establish a connection with the development board through the debug interface. Nuclei provides a sample configuration file that can be adapted to specific hardware requirements.

Example Configuration:

6.1.6.1. Debugger Speed Configuration

To adjust the debugger communication speed:

adapter_khz 1000
adapter speed 1000

Both commands set the debugger speed to 1000 kHz.

6.1.6.2. Debugger Interface Configuration

The following configuration selects and initializes the FTDI debugger interface:

adapter driver ftdi
ftdi vid_pid 0x0403 0x6010

transport select jtag

ftdi layout_init 0x0008 0x001b
ftdi layout_signal nSRST -oe 0x0020 -data 0x0020
ftdi layout_signal TCK -data 0x0001
ftdi layout_signal TDI -data 0x0002
ftdi layout_signal TDO -input 0x0004
ftdi layout_signal TMS -data 0x0008
ftdi layout_signal JTAG_SEL -data 0x0100 -oe 0x0100

Configuration Details:

  • FTDI chip VID/PID must match the connected hardware

  • JTAG transport protocol selected

  • Signal layout configured for HBird Debugger compatibility

6.1.6.3. Debugger Mode Configuration

OpenOCD supports two debugging modes:

  • JTAG Mode: Enabled with ftdi nscan1_mode off

  • Compact JTAG (cJTAG) Mode: Enabled with ftdi nscan1_mode on

6.1.6.5. Work Area Configuration

The work area is a dedicated memory region that accelerates various operations, including:

  • Memory read/write operations

  • Execution of small program fragments

  • Flash memory operations

Configuration Example:

$_TARGETNAME0 configure -work-area-phys 0x08000000 -work-area-size 0x10000 -work-area-backup 1

Note

Work Area Requirements:

  • Must be a readable, writable, and executable memory region

  • Base address (0x08000000) and size (0x10000) should be adjusted according to system requirements

6.1.6.6. NOR Flash Configuration

The NOR flash configuration specifies the memory mapping and controller settings:

set _FLASHNAME0 $_CHIPNAME0.flash
flash bank $_FLASHNAME0 nuspi 0x20000000 0 0 0 $_TARGETNAME0.0 0x10180000

Note

Configuration Parameters:

  • nuspi: Flash driver type (adjust as needed)

  • 0x20000000: QSPI XIP address (adjust as needed)

  • 0x10180000: QSPI controller base address (adjust as needed)

6.1.6.7. Debugger Connection Specification

When multiple debuggers are present in the debugging environment, you can specify which debugger to connect to using:

ftdi_serial FT4YR31I

Replace “FT4YR31I” with the actual serial number of your debugger.

6.1.6.8. Debugging Service Ports Configuration

OpenOCD provides three debugging service ports:

  1. GDB Port (default: 3333)

  2. Telnet Port (default: 4444)

  3. TCL Port (default: 6666)

Configuration Example:

gdb_port 3333
telnet_port 4444
tcl_port 6666

Note

  • Port numbers can be customized if the default ports are unavailable

  • To disable a service, set its port to disabled

  • Ensure port numbers don’t conflict with other services

6.1.6.9. Semihosting Support

OpenOCD supports ARM semihosting, which allows target programs to use host system resources. To enable:

arm semihosting enable

Note

Semihosting provides access to:

  • File I/O operations

  • Console input/output

  • System clock information

  • Other host system services

For more detailed information about how to use openocd, please check the openocd.pdf distributed in openocd release.

6.1.6.10. Target Defer Examine

In some multicore systems, the slave-target is not debuggable and needs to be unlocked by the host-target before it can be used, in which case the -defer-examine parameter is needed.

# Configuring the "-defer-examine" parameter
$SLAVE_TARGETNAME configure -defer-examine

# Override events, the following events will trigger reset, slave-target needs to be initialized manually after reset
$_TARGETNAME1_0 configure -event gdb-flash-erase-start {
  init
}
$_TARGETNAME1_0 configure -event gdb-flash-write-end {
  init
}

# Initialization, since the slave-target specifies the "-defer-examine" parameter, only the other targets will be initialized.
init

# The host-target unlocks the slave-target with the command configuration registers
$HOST_TARGETNAME dmi_write/dm_write
$HOST_TARGETNAME dmi_read/dm_read

# Manually initialize slave-target
$SLAVE_TARGETNAME arp_examine

6.1.6.11. Segmentation Fault Caused by Missing Configuration in Hummingbird-Debugger-Kit

When debugging with Hummingbird-Debugger-Kit and OpenOCD, you may encounter a “segmentation fault” issue. This is most likely caused by the following missing content in the OpenOCD configuration file:

ftdi_layout_init 0x0008 0x001b
ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020
ftdi_layout_signal TCK -data 0x0001
ftdi_layout_signal TDI -data 0x0002
ftdi_layout_signal TDO -input 0x0004
ftdi_layout_signal TMS -data 0x0008
ftdi_layout_signal JTAG_SEL -data 0x0100 -oe 0x0100

6.1.7. Low-Cost Debugger Solution

Nuclei provides an affordable debugging solution called DLink for Nuclei RISC-V CPUs:

  • Supports both JTAG and cJTAG protocols

  • Fully compatible with Nuclei Studio

  • Open-source implementation available

6.1.8. Frequently Asked Questions

For additional troubleshooting and common issues, please refer to:

6.1.9. Common Problem Troubleshooting and Solutions

6.1.9.1. Reading DTM Registers (idcode/dtmcs) using OpenOCD

OpenOCD can only read DTM registers using a combination of irscan+drscan commands, and cannot directly read the idcode register.

  • You can add the following commands directly in the configuration file (taking reading idcode register as an example)

irscan $_TARGETNAME 0x01
set idcode [drscan $_TARGETNAME 32 0x00]
puts "IDCODE = 0x$idcode"
  • Reading directly in GDB will not return the correct value because OpenOCD is continuously polling the board status in the background (polling changes the IR register state). After you execute irscan to set IR=0x01, before the next drscan is executed, OpenOCD’s polling may have already changed IR to another value, resulting in an incorrect read. The actual execution result is as follows:

(gdb) monitor irscan riscv.cpu x1
(gdb) monitor drscan riscv.cpu 32 0
00000000

6.1.10. Changelog

6.1.10.1. Version 2026.10

This release is based on 2025.10 version with some new features and bug fixes introduced.

  • Add nuclei trace command group for trace-bundle instruction-trace and data-trace support

  • Update nuclei etrace command group for ATB2AXI instruction-trace support

  • Update nuclei cpuinfo command implementation using nuclei-sdk same source code to provide same behavior

  • Sync nuclei custom CSR support for eclic_v2

  • Modify N100 vlenb/mtopi/mtopei display

  • Add flash support for HG25Q16B, GD25LE16E, GD25LQ128E, MX25R8035F, XTD25W02A, XTD25W04A, GT25Q16A, GT25Q32EB, GT25Q64EB

  • Add dummy flash driver to support automatic hardware breakpoint placement in specified address ranges

  • Update custom flash driver with wrsize support, flash-id based device matching, and fix memory issues in custom.c and nuspi.c

  • Fix FTD2xx vendor IDs and product IDs to resolve matching issues when multiple FTDI devices are present

  • Modify GD32VF103 IDCODE to correctly display chip information on the target

6.1.10.2. Version 2025.10

This release is based on 2025.02 version with some new features and bug fixes introduced.

  • Update nuclei cpuinfo command implementation using nuclei sdk 0.9.0 cpuinfo same source code to provide same behavior

    • When you connect to your FPGA evaluation board or Chip with Nuclei CPU inside it using Nuclei OpenOCD, you will be able to see message like this: Info: [riscv.cpu] Nuclei CPU Detected: mhartid-0x0 marchid-0x0300 v5.2.0, ISA: RV32ABCIM, Feature: ECLIC, ILM-128K, DLM-128K, IC-32K, sometimes it may not show, it is expected.

  • Correct custom flashloader binary file location search rules, where openocd executed, openocd scripts folder, and absolute path

  • Sync nuclei custom CSRs support

  • Optimize flash probe process, when no flash probed, it will exit with error instead of hang on it

  • Support debug for hypervisor mode

  • Fix debug Assertion failed! on HBird opensource cpu

  • Fix nuclei riscv cross trigger command implementation nuclei cti xxx

  • Clear haltreq signal when openocd connect failed

  • Fix segmentation fault issue when debug level set to 3 or 4

  • When debug on FPGA CPU MHz is very slow such as 5MHz, openocd may work not correctly, it will be fixed by make CPU run faster such as 10MHz

6.1.10.3. Version 2025.02

In this release, Nuclei OpenOCD bump openocd code base from 0.11 to 0.12, with this base changes, a lot of new features supported by upstream will be taken into Nuclei OpenOCD.

Known Issues:

  • There is a probability that writing flash under smp multi-core architecture will fail, which can be solved by clarifying the number of SMP cores or reducing the JTAG frequency.

New Features:

  • Live watch feature implementation, see Using Live Watch

  • Nuclei CTI command group support

  • Enhanced ETrace command group functionality, see Trace

  • Optimized CPU information command

Improvements:

  • Continuous integration and documentation enhancements

  • Code organization: consolidated Nuclei commands into nuclei_riscv.c

  • Register access optimization: replaced vslide1down_vx with direct vx register access for lite vpu case

CSR Updates:

New Custom CSRs:

Address Range

CSR Name

0x1a4~0x1af

smpuaddr4~15

0x1c0~0x1ef

smpuaddr16~63

CSR Renaming:

Old Name

New Name

spmpcfg0~3

smpucfg0~3

spmpaddr0~15

smpuaddr0~15

mfp16mode

mmisc_ctl1

mecc_ctrl

mecc_ctl

mstack_ctrl

mstack_ctl

Base Version:

6.1.11. Known Issues

Nuclei OpenOCD Known Issues. For more complex issues, we create separate issues on GitHub. Please refer to GitHub Issues.

6.1.11.1. custom flash driver memory out-of-bounds bug in the 2025.10 openocd

Note

This issue is fixed in the 2026.10 openocd.

When using the custom flash driver on Linux systems, a memory out-of-bounds issue may occur. This is caused by the custom flash driver not accounting for the null terminator (’0’) during malloc. The error log is as follows:

malloc():invalid next size(unsorted)

6.1.11.2. Multiple vid_pid matching failure bug in the 2025.10 openocd

Note

This issue is fixed in the 2026.10 openocd.

When multiple vid_pid pairs are configured, only the first vid_pid pair is used, while the others are ignored. This causes subsequent vid_pid devices to fail to find the debug device during connection. The error log is as follows:

Error: unrecognized USB device descriptor
Error: unable to open ftdi device with description ‘*’, serial ‘*’ at bus location ‘*’

6.1.11.3. First connection basic_cpuinfo read failure bug in the 2025.10 openocd

Note

This issue is fixed in the 2026.10 openocd.

An error occurs on the first connection with OpenOCD, but reconnecting with the same debug environment works fine. This is caused by an issue with the basic_cpuinfo call location leading to CSR read failure. The error log is as follows:

Error: [riscv.cpu] Unexpected read of fp via program buffer.
Warn : [riscv.cpu] Couldn't read vlenb; vector register access won't work.
Error: [riscv.cpu] Unexpected read of fp via program buffer.
Error: [riscv.cpu] Unexpected read of fp via program buffer.
Error: [riscv.cpu] Examination failed

6.1.11.4. tracedecoder decoding error on Chinese-locale Linux systems bug in the v0.9.0 tracedecoder at 2025.10

Note

This issue is fixed in the v1.0.0 tracedecoder at 2026.10.

When using tracedecoder on Linux systems with Chinese locale settings, ELF file parsing errors may occur. This is caused by tracedecoder not accounting for the Chinese locale during decoding. The error log is as follows:

Error: parseElfName():expected
Error: parseobjDump():expected file name and type
Error: ElfReader::ElfReader(): objdump() failed
Error: Trace::buildElfProcess(): Error creating ElfReader object
Error: Trace::configure(): buildElfProcess()failed
Error: new Trace(trace.bin,rom.elf)failed

6.1.11.5. tracedecoder runtime library mismatch on Linux systems bug in the v0.9.0 tracedecoder at 2025.10

Note

This issue is fixed in the v1.0.0 tracedecoder at 2026.10.

When running tracedecoder on Linux systems, a runtime library mismatch error may occur. This is caused by incompatibility between the runtime library versions on the test system and those used when compiling tracedecoder. The error log is as follows:

bin/dqr: /lib64/libc.so.6: version 'GLIBc 2.14' not found (required by bin/dqr)
bin/dgr: /usr/lib64/libstdc++,so.6: version 'GLIBcxx 3.4.21'not found (required by bin/dqr)

6.1.11.6. tracedecoder may lose a few instructions before the sync packet bug in the v0.9.0 tracedecoder at 2025.10

Note

This issue is fixed in the v1.0.0 tracedecoder at 2026.10.

tracedecoder may lose a few instructions before the sync packet. Previously, upon receiving a sync packet, the address within the packet was directly used as the next instruction address to continue parsing. We have now adjusted the decoding logic so that upon receiving a sync packet, instruction inference is still attempted first, rather than directly using the address within the packet as the next instruction address to continue parsing.

6.1.12. Other Debuggers

For information on debugging Nuclei RISCV CPU with JLink and Lauterbach, please refer to the links below:

Jlink.

Lauterbach.