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:
Open a command prompt (Windows) or terminal (Linux)
Execute the command:
openocd -vto see version output
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.binor/home/loader/loader.binRelative path: eg.
loader.bin, it will search under where openocd executed, andscriptsfolder of where openocd installed such astoolchain/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:
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:
Configuration:
nuclei etrace config etrace-addr buffer-addr buffer-size wrap: Initializes ETrace and configures operational parameters
Control:
nuclei etrace enable: Activates ETrace functionalitynuclei etrace disable: Deactivates ETrace functionalitynuclei etrace start: Begins trace data collectionnuclei etrace stop: Stops trace data collection
Data Management:
nuclei etrace dump filename: Exports captured trace data to a filenuclei etrace clear: Resets trace buffer pointersnuclei 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_coreConfigures the list of indices for
nuclei_examine_cpu_coreMust be executed before the
initcommand
nuclei examine_cpu_coreReturns a 64-bit value combining
dm-custom1anddm-custom2registersValue 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:
Using Nuclei HBird Debugger (FTDI-based), see Reference implementation.
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 offCompact JTAG (cJTAG) Mode: Enabled with
ftdi nscan1_mode on
6.1.6.4. JTAG Link Configuration
The JTAG link configuration varies depending on the system architecture:
Single Core System
This is a n900 single core system example.
set _CHIPNAME0 riscv0
jtag newtap $_CHIPNAME0 cpu -irlen 5 -expected-id 0x10900a6d
set _TARGETNAME0 $_CHIPNAME0.cpu
target create $_TARGETNAME0 riscv -chain-position $_TARGETNAME0 -coreid 0
SMP (Symmetric Multiprocessing) System
This is a n900-smp4 SMP system example.
set _CHIPNAME0 riscv0
jtag newtap $_CHIPNAME0 cpu -irlen 5 -expected-id 0x10900a6d
set _TARGETNAME0 $_CHIPNAME0.cpu
target create $_TARGETNAME0.0 riscv -chain-position $_TARGETNAME0 -coreid 0 -rtos hwthread
target create $_TARGETNAME0.1 riscv -chain-position $_TARGETNAME0 -coreid 1
target create $_TARGETNAME0.2 riscv -chain-position $_TARGETNAME0 -coreid 2
target create $_TARGETNAME0.3 riscv -chain-position $_TARGETNAME0 -coreid 3
target smp $_TARGETNAME0.0 $_TARGETNAME0.1 $_TARGETNAME0.2 $_TARGETNAME0.3
AMP (Asymmetric Multiprocessing) System
This is a n300 + n900-smp2 AMP system example.
set _CHIPNAME0 riscv0
jtag newtap $_CHIPNAME0 cpu -irlen 5 -expected-id 0x10300a6d
set _CHIPNAME1 riscv1
jtag newtap $_CHIPNAME1 cpu -irlen 5 -expected-id 0x10900a6d
set _TARGETNAME0 $_CHIPNAME0.cpu
target create $_TARGETNAME0 riscv -chain-position $_TARGETNAME0 -coreid 0
set _TARGETNAME1 $_CHIPNAME1.cpu
target create $_TARGETNAME1.0 riscv -chain-position $_TARGETNAME1 -coreid 0 -rtos hwthread
target create $_TARGETNAME1.1 riscv -chain-position $_TARGETNAME1 -coreid 1
target smp $_TARGETNAME1.0 $_TARGETNAME1.1
Note
The -rtos hwthread option enables OpenOCD’s pseudo RTOS functionality, which:
Presents CPU cores (“hardware threads”) as threads to GDB
Allows inspection of SMP system state through GDB commands
Enables core-specific debugging operations:
info threadslists active CPU coresthreadswitches between CPU core viewsstepandstepioperate on individual cores
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:
GDB Port (default: 3333)
Telnet Port (default: 4444)
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
disabledEnsure 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 cpuinfocommand implementation using nuclei sdk 0.9.0 cpuinfo same source code to provide same behaviorWhen 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
scriptsfolder, and absolute pathSync 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 cpuFix nuclei riscv cross trigger command implementation
nuclei cti xxxClear
haltreqsignal when openocd connect failedFix 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.cRegister access optimization: replaced
vslide1down_vxwith directvxregister 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:
Changes based on riscv-collab/riscv-openocd@f82c5a7.
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: