8.1. About Nuclei Near Cycle Model
The Nuclei Near Cycle Model (referred to as xlmodel) is a co-simulation using SystemC TLM-2 combined with xlspike. Xlspike uses spike as the RISC-V ISA simulator and adds support for Nuclei’s N/NX/UX RISC-V processors.
SystemC establishes the TLM 2.0 interaction relationships among the components under Nuclei EvalSoC.
The xlmodel can be obtained in Nuclei Studio 2026.10.
The xlmodel is supported on both Linux and Windows system.
The xlmodel supports GDB debugging capabilities (GDB RSP interface) with Nuclei Studio, including SMP multi-thread debugging, breakpoints and watchpoints.
The xlmodel is a near cycle model that can test the performance of firmware with different ISA configurations.
The xlmodel has SystemC built-in and uses version 2.3.4 by default.
The xlmodel has built-in gprof functionality, offering a detailed view of the functions call graph and the cycle count distribution across functions in the test code.
The xlmodel supports flame graph generation for visualizing call stack performance and multi-core/multi-threaded application execution.
The xlmodel supports semihosting (guest
printf/file-I/O/exit via the RISC-V semihosting convention).The xlmodel can run big-endian RISC-V ELF files directly; target endianness is detected from the ELF header.
The xlmodel can boot a RISC-V Linux kernel with the Nuclei Linux SDK, in both uniprocessor and SMP mode. See Use Nuclei Model in Nuclei Linux SDK.
The xlmodel supports SoC configuration through a
soc-cfgJSON file, and provides a--fastmodeoption for maximum functional simulation speed.The xlmodel can easily extend user-defined instructions, namely Nuclei NICE instructions.
Xlspike supports RV32IMAFDCBPV and RV64IMAFDCBPV ISA.
Since this model is also integrated in Nuclei Studio, you can use it to do
Profiling and Code Coverage
Demonstrating the acceleration of Nuclei Model NICE/VNICE instructions through Profiling: https://doc.nucleisys.com/nuclei_studio_supply/18-demonstrate_NICE_VNICE_acceleration_of_the_Nuclei_Model_through_profiling/
Nuclei Model combined with Nice Wizard for rapid verification of NICE/VNICE instruction acceleration: https://doc.nucleisys.com/nuclei_studio_supply/19-rapid_verification_of_NICE_VNICE_acceleration_with_Nuclei_Model_and_NICE_Wizard/
NICE Instruction Design and Modeling - Nuclei NICE Wizard
Debugging in Nuclei Studio - Using Nuclei Model Debugger
Flame Graph - Nuclei Studio use xlmodel flame graph
Note
Before using xlmodel, you should check the current version using the --version parameter to verify whether it is the latest release. The version output also contains the git commit hash of the build.
The version output of the current latest version is
SystemC 2.3.4-Accellera --- May 16 2024 16:02:03
Copyright (c) 1996-2022 by all Contributors,
ALL RIGHTS RESERVED
[XLMODEL-INFO] xl_cpumodel Commit: abb552a
[XLMODEL-INFO] xl_cpumodel Version 2026.10 - 1.3.0, Build Time Nov 6 2026, 18:38:31
8.2. Design and Architecture
8.2.1. SystemC components
Brief description of the xlmodel SystemC components:
Evalsoc: SystemC modeling of EvalSoC, including the binding relationships of all components and load image functionality
Cluster: Modeling of single-core or multi-core CPU, using xlspike internally to execute instructions
Bus: Simple bus manager
Memory: Simple memory, including default sram/ddr iregion and flashxip iregion
Timer: Nuclei SysTimer unit (ECLIC mode and CLINT-compatible window)
Cidu: Core Interrupt Distribution Unit for multi-core interrupt routing, inter-core interrupts and semaphores
EvalUart: Nuclei EvalSoC UART
EvalQspi: Nuclei EvalSoC QSPI
8.2.2. Address Allocation of Evalsoc in xlmodel
The following table shows the default EvalSoC address map in xlmodel. Memory regions and peripherals can be relocated or resized with command-line options (such as --ddrbase and --ddrsz) or through soc-cfg. IREGION devices use fixed offsets from iregion.base, whose default value is 0x18000000.
Type |
Component |
Base address |
Size |
Description |
|---|---|---|---|---|
Memory |
XIP/NOR flash |
|
|
Boot flash and XIP memory. |
Memory |
DDR |
|
|
General-purpose system memory; enlarge it when booting Linux. |
Memory |
ILM |
|
|
Instruction local memory. |
Memory |
DLM |
|
|
Data local memory. |
Memory |
SRAM |
|
|
On-chip SRAM address window. |
Fixed peripheral |
UART0 |
|
|
EvalSoC serial controller. |
Fixed peripheral |
QSPI0 |
|
|
SPI/QSPI controller. |
Fixed peripheral |
QSPI1 |
|
|
SPI/QSPI controller. |
Fixed peripheral |
QSPI2 |
|
|
SPI/QSPI controller. |
IREGION |
ECLIC |
|
|
Nuclei ECLIC unit. |
IREGION |
TIMER |
|
|
Nuclei SysTimer/CLINT-compatible window. |
IREGION |
SMP/CC |
|
|
SMP and cluster-cache control unit. |
IREGION |
CIDU |
|
|
Core interrupt distribution unit. |
IREGION |
PLIC |
|
|
Platform-level interrupt controller. |
For details, please see Nuclei Model Command-line Options.
8.2.3. Nuclei CPU Features Supported in xlmodel
The following table summarizes the current implementation status.
Feature |
Status |
|---|---|
NMI |
Supported. |
TIMER |
Supported; see TIMER Support. |
PLIC |
Supported; see PLIC Support. |
ECLIC v1/v2 |
Supported; see ECLIC Support. |
CIDU |
Supported; see CIDU Support. |
PMP |
Supported. |
TEE |
Supported. |
WFI |
Supported. |
WFE |
Not supported. |
ECC |
ECC-related CSRs are implemented. |
CCM |
CCM-related CSRs are implemented. |
SPMP |
Not supported. |
SMPU |
Supported. |
SMP / CLUSTER CACHE |
Register-level access is supported; cache behavior is not modeled. |
Big-endian |
Supported; driven by the ELF header. |
Semihosting |
Supported; see Semihosting. |
8.2.3.1. TIMER Support
The Nuclei SysTimer implements a shared time base, per-hart timer comparison and delivery, and multi-core ECLIC operation. EvalSoC also provides a CLINT-compatible timer model for conventional RISC-V software, and the Sstc supervisor timer extension is supported.
8.2.3.2. PLIC Support
The PLIC model supports platform-level interrupt prioritization and routing for machine-mode and supervisor-mode interrupt contexts, with up to 1024 interrupt sources. Multi-core PLIC mode is not supported.
8.2.3.3. ECLIC Support
ECLIC supports single-core and multi-core operation in both M-mode and S-mode. The ECLIC v1 model provides the basic interrupt configuration, arbitration, nesting and trigger behavior. ECLIC v2 additionally supports automatic context save/restore and shadow general-purpose register groups, together with the associated nested-trap state handling. The interrupt number count and CLICINTCTLBITS can be configured with --eclic.
8.2.3.4. CIDU Support
The CIDU distributes external interrupts among per-hart ECLIC instances. It also implements inter-core interrupts, multiple interrupt-distribution modes, and hardware semaphores for multicore software.
8.2.4. Nuclei SDK Cases Supported in xlmodel
See Use Nuclei Model in Nuclei SDK for the case status table.
8.3. Nuclei Model Command-line Options
This section covers EvalSoC-specific settings and commonly used xlmodel options. Run xl_cpumodel --help for the full list.
8.3.1. Command-line Syntax and Help
Use bin/xl_cpumodel on Linux and bin/xl_cpumodel.exe on Windows, together with the ELF file of the test program:
xl_cpumodel [options] <elf-file>
The following parameter examples are based on a Linux system. If you are using a Windows system, simply replace xl_cpumodel with xl_cpumodel.exe.
Use the following commands to discover the options and cores available in the installed package:
xl_cpumodel --help
xl_cpumodel --version
xl_cpumodel --cpu=?
The default test code ELF files are provided in the tests directory of the package, for example:
./xl_cpumodel --cpu=nx900 --download=ilm ../tests/demotimer/demotimer_nx900.elf
8.3.2. CPU Configuration
--cpu=<str>: Selects the CPU model, defaults to n300fd. Use --cpu=? to list all supported Nuclei cores (rv32/rv64), or refer to the Supported Nuclei Processor Cores section of the Nuclei SDK documentation.
--ext=<str>: Enables additional ISA extensions, separated by _, for example --ext=_zba_zbb_zbc_zbs_xxldspn1x. See Supported ISA Extensions for the available extensions. The Sstc extension is enabled by default and does not need to be passed; an extension can also be disabled or re-enabled by appending name=true/false items, where later items take precedence, for example --ext=_zba_zbb,sstc=false. Example:
./xl_cpumodel --cpu=n300fd --download=ilm --ext=_zba_zbb_zbc_zbs_xxldspn1x ../tests/demodsp/demodsp_n300fd.elf
--bpu=<str>: Selects the BPU strategy based on Nuclei core types, which affects the cycle count of branch and jump instructions. --bpu=n300 is applicable to Nuclei cores up to and including N300, and --bpu=n900 is applicable to Nuclei cores from N300 onwards:
./xl_cpumodel --cpu=n300fd --ext=_zba_zbb_zbc_zbs_xxldspn1x --download=ilm --bpu=n300 ../tests/demodsp/demodsp_n300fd.elf
./xl_cpumodel --cpu=nx900 --download=ilm --bpu=n900 ../tests/demotimer/demotimer_nx900.elf
--priv=<str>: Selects the implemented privilege modes m, mu or msu, defaulting to msu. Use --priv=m for M-mode only CPUs.
--eclic=<str>: Configures the ECLIC with irqnums:<n>,intctlbits:<n>,shdnum:<n>, defaulting to irqnums:64,intctlbits:3,shdnum:9. irqnums sets the total number of interrupt lines, intctlbits sets CLICINTCTLBITS, and shdnum sets the number of ECLIC v2 shadow register groups. Use it together with --ext=_xlclicv2 to enable ECLIC v2:
./xl_cpumodel --cpu=n900 --download=ilm --ext=_xlclicv2 --eclic=irqnums:64,intctlbits:3,shdnum:9 --soc-cfg=../tests/demoeclicstress_eclicv2_n900/cpu.json ../tests/demoeclicstress_eclicv2_n900/demoeclicstress.elf
--varch=vlen:n,elen:n: Sets the RISC-V Vector micro-architecture configuration when the V extension is enabled, defaulting to vlen:128,elen:64. VLEN and ELEN must comply with the RISC-V Vector specifications. Example:
./xl_cpumodel --cpu=ux900fd --ext=v --download=ilm --varch=vlen:128,elen:64 ../tests/rvv_conv_f32/rvv_conv_f32.elf
./xl_cpumodel --cpu=ux900fd --ext=v --download=ilm --varch=vlen:512,elen:64 ../tests/rvv_conv_f32/rvv_conv_f32.elf
VLEN values of 2048 and 4096 are also supported, which is useful for VNICE instruction modeling with very wide vector registers:
./xl_cpumodel --cpu=ux900fd --ext=v --download=ilm --varch=vlen:2048,elen:64 ../tests/rvv_conv_f32/rvv_conv_f32.elf
--smp=<n>: Sets the SMP system core number, with a maximum of 16. If this parameter is not set, 1 CPU is used. Example:
./xl_cpumodel --cpu=nx900 --download=sram --smp=4 ../tests/smphello_4core/smphello_nx900.elf
8.3.2.1. Supported ISA Extensions
The following extensions can be selected through --ext=. Choose extensions supported by the selected CPU configuration and the guest program.
Extension |
Functionality |
|---|---|
v |
RISC-V V Extension |
h |
RISC-V H-Extension |
_zicbom |
RISC-V Zicbom Extension |
_zicboz |
RISC-V Zicboz Extension |
_zicond |
RISC-V Zicond Extension |
_zicsr |
RV32/RV64 Zicsr Standard Extension |
_zifencei |
RV32/RV64 Zifencei Standard Extension |
_zihintpause |
ZiHintPause extension |
_zilsd |
Zilsd extension (RV32 ONLY) |
_zimop |
RISC-V Zimop Extension |
_zcmop |
RISC-V Zcmop Extension |
_zclsd |
Zclsd extension (RV32 ONLY); use |
_zawrs |
Zawrs extension |
_zacas |
Zacas extension (AMO CAS) |
_zfh |
Zfh Extension |
_zfa |
Zfa Extension |
_zfhmin |
Zfhmin Extension |
_zfbfmin |
Scalar BF16 conversions (Zfbfmin) |
_zfinx |
Zfinx Extension |
_zdinx |
Zdinx Extension |
_zibi |
RISC-V Zibi Extension |
_zicfilp |
RISC-V Zicfilp Extension (landing pad) |
_zca |
RISC-V ZC* Extension |
_zcb |
RISC-V ZC* Extension |
_zcf |
RISC-V ZC* Extension |
_zcd |
RISC-V ZC* Extension |
_zcmp |
RISC-V ZC* Extension |
_zcmt |
RISC-V ZC* Extension |
_zba |
RISC-V Bitmanipulation Extension |
_zbb |
RISC-V Bitmanipulation Extension |
_zbc |
RISC-V Bitmanipulation Extension |
_zbkb |
RISC-V Bitmanipulation Extension |
_zbkc |
RISC-V Bitmanipulation Extension |
_zbkx |
RISC-V Bitmanipulation Extension |
_zbs |
RISC-V Bitmanipulation Extension |
_zk |
RISC-V Scalar Crypto Extension |
_zkn |
RISC-V Scalar Crypto Extension |
_zknd |
RISC-V Scalar Crypto Extension |
_zkne |
RISC-V Scalar Crypto Extension |
_zknh |
RISC-V Scalar Crypto Extension |
_zkr |
RISC-V Scalar Crypto Extension |
_zks |
RISC-V Scalar Crypto Extension |
_zksed |
RISC-V Scalar Crypto Extension |
_zksh |
RISC-V Scalar Crypto Extension |
_zkt |
RISC-V Scalar Crypto Extension |
_zve32x |
RISC-V V Extension |
_zve32f |
RISC-V V Extension |
_zve64x |
RISC-V V Extension |
_zve64f |
RISC-V V Extension |
_zve64d |
RISC-V V Extension |
_zvfh |
RISC-V V Extension |
_zvfhmin |
RISC-V V Extension |
_zvfbfmin |
Vector BF16 conversions, V extension required |
_zvfbfwma |
Vector BF16 multiply-accumulate, V extension required |
_zvkg |
RISC-V Vector Crypto Extension |
_zvkned |
RISC-V Vector Crypto Extension |
_zvksed |
RISC-V Vector Crypto Extension |
_zvksh |
RISC-V Vector Crypto Extension |
zhinx |
Zhinx Extension |
zhinxmin |
Zhinxmin Extension |
smaia |
Smaia Extension |
_smrnmi |
Smrnmi Extension |
ssaia |
Ssaia Extension |
_sscofpmf |
Sscofpmf Extension |
_sstc |
Sstc Extension (enabled by default) |
_svinval |
Svinval Extension |
_svnapot |
Svnapot Extension |
_svpbmt |
Svpbmt Extension |
_xxldsp |
Nuclei DSP Extension based on P-ext 0.5.4 + default 8 EXPD instructions |
_xxldspn1x |
Xxldsp + Nuclei N1 extension |
_xxldspn2x |
Xxldspn1x + Nuclei N2 extension |
_xxldspn3x |
Xxldspn2x + Nuclei N3 extension |
_xxlcz |
Nuclei code size reduction extension |
_xxlvqmacc |
Nuclei custom VPU extension; use |
_xxlfbf |
Nuclei scalar BF16 extension; not enabled via |
_xxlvfbf |
Nuclei vector BF16 extension; not enabled via |
_xxlclicv2 |
Nuclei ECLIC v2 extension (use |
_agnostic |
Nuclei vector tail/mask-agnostic policy: fill ones (V required) |
8.3.3. SoC Configuration
-M/--machine=<str>: Machine type config, defaults to nuclei_evalsoc.
--download=<str>: Selects the download mode; the default is flashxip and it can be set to ilm, ddr, sram or flash. The startup address of the selected mode is the EvalSoC memory base by default, and can be overridden per mode through soc-cfg or globally with --vectorbase. Example:
./xl_cpumodel --cpu=nx900 --download=sram --smp=4 ../tests/democidu_en_firclaim/democidu_en_firclaim_nx900.elf
--soc-cfg=<file.json>: Overrides the built-in board configuration with a JSON file. See soc-cfg JSON Configuration.
--mem=<str>: Defines additional user memory regions when the test code uses external memory sections, for example --mem="0x30000000:0x10000000,0x40000000:0x10000000". Example:
./xl_cpumodel --cpu=nx900 --download=ilm --mem="0x30000000:0x10000000,0x40000000:0x10000000" ../tests/demoeclic_swirq_high/demoeclic_swirq_high_nx900.elf
--vectorbase=<addr>: Sets the reset vector address explicitly. It takes precedence over the startup address selected by --download, including the download.<mode>.startaddr item of the --soc-cfg file and the default memory base. When it is set, the consistency check between the ELF entry point and the selected download mode is skipped.
8.3.4. soc-cfg JSON Configuration
The --soc-cfg=<file.json> option loads a JSON file that overrides the built-in EvalSoC board configuration, aligned with the soc-cfg format used by Nuclei QEMU. Without --soc-cfg, xlmodel uses the built-in default layout. For any configurable item, the effective value is resolved in the order CLI parameter > ``soc-cfg`` JSON > built-in default.
The following example overrides memory regions, selected peripherals and download-mode startup addresses:
{
"general_config": {
"ddr": {
"base": "0x80000000",
"size": "64M"
},
"ilm": {
"base": "0x80000000",
"size": "0x800000"
},
"dlm": {
"base": "0x90000000",
"size": "0x800000"
},
"sram": {
"base": "0xA0000000",
"size": "512M"
},
"norflash": {
"base": "0x20000000",
"size": "256M"
},
"iregion": {
"base": "0x18000000",
"eclic": "1",
"smpcc": "1",
"cidu": "1",
"plic": "1"
},
"uart0": {
"base": "0x10013000",
"size": "0x1000",
"irq": "32",
"enable": "1"
},
"qspi0": {
"base": "0x10014000",
"size": "0x1000",
"irq": "34",
"enable": "1"
},
"timer_freq": "32768",
"cpu_freq": "16000000"
},
"download": {
"ilm": {
"startaddr": "0x80000000"
},
"flashxip": {
"startaddr": "0x20000000"
},
"flash": {
"startaddr": "0x20000000"
},
"sram": {
"startaddr": "0xA0000000"
},
"ddr": {
"startaddr": "0x80000000"
}
}
}
Field |
Applies to objects |
Description |
|---|---|---|
|
|
Sets the base address and size of the corresponding memory or MMIO region. |
|
|
Sets the peripheral interrupt ID routed to ECLIC/CIDU. |
|
|
Enables or disables the corresponding device. |
|
|
Enable or disable the corresponding IREGION block. |
|
|
Sets the SysTimer clock frequency; overridden by |
|
|
Sets the CPU frequency; overridden by |
|
|
Sets the firmware startup address for the corresponding download mode. |
Notes on the JSON format:
Numeric leaf values can be written as decimal strings,
0x-prefixed hexadecimal strings, or with aK/M/Gsize suffix; plain JSON numbers andtrue/falseare also accepted.Partial overrides are supported: omitted objects and fields keep their defaults.
download.<mode>.startaddronly changes the startup address of that download mode; it does not change the memory-region mapping.
An example of running with a soc-cfg file:
./xl_cpumodel --cpu=nx900 --download=ilm --soc-cfg=soc.json ../tests/demotimer/demotimer_nx900.elf
8.3.5. Memory Configuration
The base address and size of each memory region can be adjusted with the following options; they override the same items in soc-cfg:
--ilmbase/--ilmsz: ILM base address and size--dlmbase/--dlmsz: DLM base address and size--srambase/--sramsz: SRAM base address and size--ddrbase/--ddrsz: DDR base address and size--flashxipbase/--flashxipsz: XIP (NOR flash) base address and size--iregionbase: IREGION base address
For example, enlarging DDR to 2 GB when booting Linux:
./xl_cpumodel --cpu=ux900fd --download=ddr --ddrbase=0x80000000 --ddrsz=0x80000000 <linux-image.elf>
8.3.6. Simulation Speed and Time
--cpufreq=<n>: Simulated CPU frequency in Hz (default 655360). It takes precedence over the cpu_freq item of the --soc-cfg file. The frequency does not change the per-instruction cycle estimates: it only defines the cycle-to-second conversion and the mtime tick interval (one tick every cpu_freq / timer_freq cycles). Example:
./xl_cpumodel --cpu=nx900 --download=ilm --cpufreq=16000000 ../tests/demotimer/demotimer_nx900.elf
Note
Set --cpufreq to the real board frequency when comparing simulated timings against hardware, and keep the default for functional runs. A higher value does not improve cycle accuracy: timer-driven workloads (RTOS ticks, busy-wait delays) retire instructions proportionally to cpu_freq / timer_freq while waiting, so raising it slows the simulation proportionally — at 50 MHz demotimer retires ~76x more instructions than at the default and takes minutes instead of seconds.
--timefreq=<n>: Sets the timer frequency in Hz, defaulting to 32768 Hz.
--timeout=<n>: Sets the expected real execution time in seconds for a simulation run; otherwise, it is unlimited. This parameter is ignored during GDB debugging. When the timeout is reached, the enabled gprof/flame graph files are generated. Example:
./xl_cpumodel --cpu=nx900 --download=sram --smp=2 --gprof=1 --flamegraph=1 --timeout=3 ../tests/freertos_smpdemo/freertos_smpdemo_nx900.elf
Pressing Ctrl+C also stops the simulation gracefully, and similarly generates gprof/flame graph files for the period from startup to shutdown.
--funcmode=1: Every retired instruction is counted as a fixed 1 cycle and the per-instruction near-cycle calculation is skipped. Trace, gprof and flame graph are still available in this mode.
--fastmode=1: Switches to the fast functional mode to maximize simulation speed. The functional behavior (instruction execution, peripherals, interrupts) is unchanged, so use it when the exact cycle count is not required, such as booting Linux or running very long functional tests. Cycle-related features such as --trace, --gprof and --flamegraph are not available in this mode:
./xl_cpumodel ../tests/demodsp/demodsp_n300fd.elf --cpu=n300fd --ext=_zba_zbb_zbc_zbs_xxldspn1x --download=ilm --fastmode=1
8.3.7. Trace, Profiling and Logs
--trace=1: Generates the instruction trace file <elf-name>.rvtrace in the current execution path. It contains the instruction count, cycle count, hart, pc, opcode and disassembly of each instruction. Example:
./xl_cpumodel --cpu=nx900 --download=ilm --trace=1 ../tests/demoeclic_swirq_low/demoeclic_swirq_low_nx900.elf
-t <path>: Specifies the trace file path directly and enables tracing at the same time.
--gprof=1: Enables the built-in gprof functionality. The gprof<n>.gmon and gprof<n>.log files are generated when the simulation completes, where n is the hart ID. Import them into Nuclei Studio for detailed analysis. Example:
./xl_cpumodel --cpu=nx900fd --download=ilm --gprof=1 ../tests/whet/whet_nx900fd.elf
--flamegraph=1: Enables the built-in flame graph functionality. The xlmodel_flame_<n>.gtef files are generated when the simulation completes, where n is the hart ID. For each hart, the flame graph shows the main thread, RTOS task threads, and M-mode/S-mode interrupt threads. Import them into Nuclei Studio, see Nuclei Studio use xlmodel flame graph for detailed usage. Example:
./xl_cpumodel --cpu=n300fd --download=ilm --flamegraph=1 ../tests/demo_clint_timer/demo_clint_timer_n300fd.elf
--logdir=<str>: The directory to store generated files (instruction trace, gprof files, flame graphs). Example:
./xl_cpumodel --cpu=nx900 --download=ilm --trace=1 --gprof=1 --flamegraph=1 --logdir=../log ../tests/demoeclic_swirq_low/demoeclic_swirq_low_nx900.elf
--log=<str>: Sets the log level, from least to most detailed: error, info, debug, tlm. The default is info, and --log=debug --trace=1 can adds register updates, exceptions and CSRs to the trace file. Example:
./xl_cpumodel --cpu=nx900 --download=ilm --trace=1 --log=debug ../tests/demotimer/demotimer_nx900.elf
8.4. DEBUG
You can debug applications running with xlmodel by passing the --gdbport=<port_num> parameter. This enables the GDB server and allows external GDB (e.g., riscv64-unknown-elf-gdb) to connect via the specified portnum for software debugging.
To debug via the command line, follow these steps on a Linux system: (Windows is similar)
Start xlmodel with GDB debugging enabled:
./xl_cpumodel --cpu=nx900 --download=ilm --gdbport=1234 ../tests/demotimer/demotimer_nx900.elf
Open another command-line terminal and run GDB:
riscv64-unknown-elf-gdb tests/demotimer/demotimer_nx900.elf
Connect to the GDB port, load the ELF file, and perform standard GDB debugging:
target remote :1234 load tests/demotimer/demotimer_nx900.elf set disassemble-next-line on info register all si b xxx c
The GDB stub supports:
SMP debugging:
info threadslists every hart of the cluster;thread <n>switches the target hart andsisingle-steps only the selected hart, whilecontinueruns the whole cluster.Breakpoints and watchpoints: software breakpoints (
b), hardware breakpoints (hbreak), and watchpoints (watch/rwatch/awatch) on physical or virtual addresses. Stop replies report the stop reason, e.g.swbreak,hwbreak,watch,rwatchorawatch.Memory access after MMU is enabled: addresses are translated from VA to PA automatically. Use
monitor pa on/monitor pa offto force the GDB stub to access physical addresses directly.
For an easier experience using GDB debugging with xlmodel, we recommend using Nuclei Studio. When GDB is enabled, passing --gprof=1 and --flamegraph=1 allows you to capture profiling result and generated flame graph visualizations while the program is suspended in GDB.
For more information on using xlmodel debugging in Nuclei Studio, please refer to the Using Nuclei Model Debugger.
Note
The --timeout=<n> parameter has no effect when software debugging is enabled.
8.5. Semihosting
xlmodel supports the RISC-V semihosting convention: when --semihosting=1 is passed, an EBREAK instruction surrounded by the semihosting magic words traps into the host and executes the requested semihosting call, with the operation number in register a0 and the parameter block pointer in a1. Semihosting calls are executed by the host directly and bypass the UART.
Supported operations include basic printing (SYS_WRITE0/SYS_WRITEC), file I/O (SYS_OPEN, SYS_CLOSE, SYS_READ, SYS_WRITE, SYS_FLEN, SYS_SEEK), and program exit (SYS_EXIT).
Build the guest program with semihosting enabled (for example --specs=semihost.specs or the SDK semihosting support), then run:
./xl_cpumodel --cpu=nx900 --download=ilm --semihosting=1 <semihosting-enabled.elf>
8.6. Use Nuclei Model in Nuclei SDK
Setup Tools and Environment
Download the nuclei-sdk, checkout to
masterbranch.Download RISC-V GNU Toolchain from Nuclei Download Center.
Download the xlmodel software package from Nuclei Download Center (or obtain it in Nuclei Studio), extract it and add
xlmodel/binto thePATHenvironment variable.
Example
If you want to use xlmodel on Nuclei SDK. The example here uses the CPU of the n300fd, but other CPU types can also be used for testing. The example is demo_dsp.
First, you need to configure the toolchain, nuclei-sdk, and xlmodel environments according to the documentation https://doc.nucleisys.com/nuclei_sdk/quickstart.html
# Enter the example folder of demo_dsp
cd nuclei-sdk/application/baremetal/demo_dsp/
# Clear the compilation cache
make clean
# Compile the program for the n300fd, set the download mode to ILM, and enable the xxldsp extension
make CORE=n300fd SOC=evalsoc DOWNLOAD=ilm ARCH_EXT=_xxldsp dasm
# Automatically generate xlmodel running commands and execute the program
make CORE=n300fd SOC=evalsoc DOWNLOAD=ilm ARCH_EXT=_xxldsp run_xlmodel
Where ARCH_EXT can be used to pass the extension name. The run_xlmodel target calls xl_cpumodel with the matching --cpu, --download and --ext options (and --smp when CPU_CNT is set), so no extra xlmodel options are needed and make sure xl_cpumodel is in the PATH. Under normal circumstances, you should see the test cases finish successfully.
Support for Nuclei SDK Cases on xlmodel
Y- Successfully run and consistent with hardware
N- Successfully run but inconsistent with hardware
F- Failed
Cases |
SMP=1 |
SMP>1 |
Description (additional compilation parameters and running status) |
|---|---|---|---|
benchmark/coremark |
Y |
||
benchmark/dhrystone |
Y |
||
benchmark/ dhrystone_v2.2 |
Y |
||
benchmark/whetstone |
Y |
||
benchmark/ whetstone_v1.2 |
Y |
||
cpuinfo/ |
N |
||
demo_backtrace/ |
Y |
||
demo_cache/ |
F |
Cache emulation is not supported. |
|
demo_cidu/ |
Y |
SMP=4, XLCFG_CIDU=1. |
|
demo_clint_timer/ |
Y |
||
demo_dsp/ |
Y |
||
demo_ecc/ |
N |
ECC error injection and correction behavior is not modeled. |
|
demo_eclic/ |
Y |
||
demo_eclic_stress/ |
Y |
XLCFG_ECLIC=2, ECLIC_HWCTX=0/1; run with an
increased |
|
demo_eclic_umode/ |
Y |
||
demo_nice/ |
Y |
||
demo_plic/ |
Y |
XLCFG_PLIC=1. |
|
demo_pma/ |
N |
XLCFG_CCM=1, XLCFG_HPM=1. |
|
demo_pmp/ |
Y |
||
demo_profiling/ |
N |
xlmodel already implements its own profiling. |
|
demo_smode_clint/ |
Y |
||
demo_smode_eclic/ |
Y |
XLCFG_TEE=1. |
|
demo_smode_plic/ |
Y |
XLCFG_PLIC=1. |
|
demo_smpcc/ |
N |
Control registers are modeled; cluster-cache behavior is not modeled. |
|
demo_smpu/ |
Y |
XLCFG_SMPU=1, CHK_MODE=0 through 5. |
|
demo_sstc/ |
Y |
XLCFG_TEE=1, XLCFG_SSTC=1. |
|
demo_stack_check/ |
N |
Only CSRs are implemented. |
|
demo_timer/ |
Y |
||
demo_vnice/ |
Y |
||
empty/ |
Y |
||
exception_mmode/ |
Y |
||
exception_smode/ |
Y |
XLCFG_TEE=1. |
|
exception_umode/ |
Y |
XLCFG_SMODE=1, XLCFG_SMPU=1. |
|
helloworld/ |
Y |
||
lowpower/ |
Y |
||
smphello/ |
Y |
SMP=4. |
|
freertos/demo/ |
Y |
||
freertos/smpdemo/ |
Y |
SMP=4. |
|
rtthread/demo/ |
Y |
||
rtthread/demo_smode/ |
Y |
XLCFG_TEE=1, XLCFG_SSTC=1. |
|
rtthread/msh/ |
Y |
||
threadx/demo/ |
Y |
||
threadx/smpdemo/ |
Y |
SMP=4. |
|
ucosii/demo/ |
Y |
And xlmodel and Nuclei SDK are deeply integrated in Nuclei Studio, you can run Nuclei SDK test code using xlmodel in Nuclei Studio, please refer to the Nuclei Studio use xlmodel.
8.7. Use Nuclei Model in Nuclei Linux SDK
xlmodel can boot and test a RISC-V Linux Kernel using the emulated Nuclei EvalSoC, in both uniprocessor and SMP mode, for RV64 and RV32. For more information about the Nuclei Linux SDK, see https://github.com/Nuclei-Software/nuclei-linux-sdk .
Prebuilt boot images built from the Linux SDK are provided in the tests directory of the xlmodel package:
File |
Arch |
Description |
|---|---|---|
|
RV64 |
Linux 6.6 flash payload for ux900fd from the Linux SDK CI. |
|
RV32 |
Linux 6.6 flash payload for u900 from the Linux SDK CI. |
An example of booting Linux on a single core:
./xl_cpumodel --cpu=ux900fd --download=ddr \
--ext=_svpbmt_zicbom_sstc_sscofpmf_zba_zbb_zbc_zbs_zicond \
--fastmode=1 --ddrbase=0x80000000 --ddrsz=0x80000000 \
--timeout=3600 ../tests/boot_linux_rv64/fw_payload_xlspike_ux900fd_flash_job_5c231cec.elf
An example of booting Linux on two cores (SMP): add --smp=2 and disable ILM with --ilmsz=0, because the SMP image uses a DDR-only memory map and the default ILM overlaps the enlarged DDR region:
./xl_cpumodel --cpu=ux900fd --download=ddr \
--ext=_svpbmt_zicbom_sstc_sscofpmf_zba_zbb_zbc_zbs_zicond \
--fastmode=1 --smp=2 --ilmsz=0 --ddrbase=0x80000000 --ddrsz=0x80000000 \
--timeout=3600 ../tests/boot_linux_rv64/fw_payload_xlspike_ux900fd_flash_job_5c231cec.elf
The RV32 image boots in the same way with --cpu=u900 and the tests/boot_linux_rv32 image.
Note
Booting Linux requires a large DDR (2 GB in the examples above, via --ddrsz), and --fastmode=1 is recommended. Tracing and profiling options are not available in fast mode.
8.8. NICE support
8.8.1. NICE build
If you need to validate your custom NICE instructions, you need to contact Nuclei Support to obtain software package of model (xlmodel_nice).
The directory structure of xlmodel_nice is as follows, you need to implement the NICE instructions in nice/nice.cc.
nice directory |
description |
|---|---|
nice |
header and source files for the NICE interface |
systemc |
SystemC 2.3.4 header files and static libraries |
xl_model |
xlmodel header files and library files |
xl_spike |
xlspike header files and library files |
tests |
simple test codes |
CMakeLists.txt |
CMake file required for compilation |
After implementing the NICE instruction, you need to recompile xlmodel_nice.
nice build for Linux
# Install essential compilation tools
sudo apt install build-essential cmake
# Check the tools have been installed successfully
gcc -v && g++ -v && cmake --version
# Change to the root directory of the xlmodel_nice package
cd <xlmodel_nice root directory>
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
nice build for Windows
To compile xlmodel_nice on Windows, you need to download a Windows-compatible GCC tool, such as MinGW64. You can download MSYS2 to easily obtain the MinGW64 toolchain, which simplifies the installation and management of MinGW64 on Windows.
Below are the steps to use MSYS2’s MinGW64 to compile xlmodel_nice on Windows:
Install the latest version of MSYS2 from https://www.msys2.org/, and then add the MinGW64 toolchain path to the environment variables:
Install MinGW64 toolchain, CMake, and other basic compilation tools in the MSYS2 terminal:
# Sync the package databases first, rerun until it prints "there is nothing to do" pacman -Syu pacman -S base-devel mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake
Compile xlmodel_nice in the MinGW64 terminal:
# Check the tools have been installed successfully
gcc -v && g++ -v && cmake --version
# Change to the root directory of the xlmodel_nice package
cd <xlmodel_nice root directory>
mkdir build && cd build
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
Note
If you need to import and compile xlmodel_nice in Nuclei Studio (Nuclei Studio use xlmodel), you also need to configure the MSYS2 environment as described above first.
8.8.2. NICE example
If you are unfamiliar with how to implement the NICE instruction, refer to the implementation in xlmodel_nice/nice/nice.cc for custom Nuclei NICE/VNICE instructions.
The test example for Nuclei NICE instruction features are located in tests/demonice:
./xl_cpumodel --cpu=nx900 --download=ilm ../tests/demonice/demonice_nx900.elf
The test example for Nuclei VNICE instruction features are located in tests/demovnice:
./xl_cpumodel --cpu=nx900fd --ext=v --download=ilm ../tests/demovnice/demovnice_nx900fd.elf
8.9. SystemC integration
If you need to integrate xlmodel into a third-party SoC simulation platform, you need to contact Nuclei AE for the software integration package of the model (xlmodel_integrate).
xlmodel_integrate mainly includes the source code of SystemC components. You can extract the parts you need and use them on third-party platforms with relatively little adaptation.
The integration package is delivered per target platform. The standard package is built against SystemC 2.3.4 and is available for several Linux distributions (linux64, Debian 10, CentOS 7) and Windows (win32); for Ubuntu hosts, additional variants built against SystemC 3.0.0 and SystemC 3.0.2 are provided, so the package can be linked into SystemC 3.x based platforms as well.
directory |
description |
|---|---|
src |
All SystemC components, Cluster and Timer are mandatory to integrate, while others can be integrated as needed. |
inc |
All header files related to xlmodel, which are integrated as needed. |
systemc |
SystemC 2.3.4 header files and the platform-specific static library ( |
cycle |
The near cycle lib file, must be integrated. |
profiling |
The xlmodel profiling lib file, which is integrated as needed. |
xlspike |
xlspike header files and the platform-specific static library ( |
tests |
simple test codes. |
nice |
header and source files for the NICE interface, must be fully integrated. |
CMakeLists.txt |
CMake file required for compilation. |
Here are the integration steps instructions:
Find the Cluster class in inc/cluster.h:
The Cluster class contains two types of variables:
Internal variables: Initialized to default values in the constructor’s member initialization list.
User-defined variables: Initialization in the constructor’s member list depends on your firmware, CPU configurations and extra simulation feature needs.
Usage recommendations:
You can inherit the Cluster class in your SystemC platform class to use base methods of your platform.
Find the Cluster class in src/cluster.cpp:
Usage recommendations:
If you do not need to replace the SystemC sockets and TLM methods in the Cluster class, you can directly use the constructor and methods in the Cluster class without any modification.
Adjust the user-defined variables in the constructor’s member initialization list.
If your platform implements TLM transmission from CPU to Bus, you can substitute the read/write implementations into
cpu_read_tlm()andcpu_write_tlm().
Use External Interrupts:
To connect User-defined external interrupts to the CPU:
Pass the number of external interrupt sources to the Cluster constructor. It decides the size of the Cluster’s
irq_sockets, and each source is bound to one socket.The total number of interrupt lines is configured with
irq_num. An external interrupt ID must be smaller thanirq_numminus the built-in interrupt offset (19 for ECLIC, 1 for PLIC).Bind your device’s interrupt socket to one of the Cluster’s
irq_sockets.
8.10. Changelog
8.10.1. Version 2026.10
This release is based on 2025.10 version with some new features and bug fixes introduced.
New Features:
Support booting a RISC-V Linux kernel with the Nuclei Linux SDK (RV64/RV32, uniprocessor and SMP)
SMP GDB debugging: per-hart thread switching, single-step on the selected hart, watchpoints (watch/rwatch/awatch) on virtual addresses, stop-reason reporting
Support ECLIC v2 hardware context and shadow register groups (
--ext=_xlclicv2); add--eclic=irqnums:<n>,intctlbits:<n>,shdnum:<n>Support for vector tail/mask-agnostic policies via
--ext=v,agnostic=true(fill ones) and--ext=v,noagnostic=true(keep old values).ECLIC interrupt sources scale to 4096(M-only) or 1024(M/S), and Privilege can be configured by
--priv=m/mu/msuoptions; PLIC interrupt sources scale to 1024Support big-endian RISC-V ELF files; target endianness is detected from the ELF header, including big-endian GDB debugging
SMP simulation now supports up to 16 cores (previously limited to 8)
Support RISC-V semihosting (
--semihosting=1) for guest printf/file-I/O/exit via EBREAKSupport
soc-cfgJSON configuration files (--soc-cfg), aligned with the Nuclei QEMU format, with CLI > soc-cfg > default priorityAdd
--fastmode=1for maximum functional simulation speedSupport the
Sstcsupervisor timer extension by defaultFaster flamegraph
.gtefgeneration with improved symbol resolutionAdd new extensions: Zibi, Zicfilp, Zacas, Zaamo/Zalrsc, vector crypto (Zvkg/Zvkned/Zvksed/Zvksh), BF16 support: standard extensions (
Zfbfmin/Zvfbfmin/Zvfbfwma) and NucleiXxlfbf/Xxlvfbf(enabled via theMMISC_CTL1fp16modebit); NucleiXxlvqmaccVPU extension (use_xlvqmacc); DSP extensions differentiated into Xxldspn1x/N2x/N3x; VLEN 2048/4096 supportUART: RX polling mode: guest can poll RXDATA without enabling the UART interrupt
Add
--cpu=?core listing,--timefreq,--srambase/--sramszand--vectorbaseoptions;--extsupports per-extensionname=true/falseoverrides;--versionoutput now includes the git commit hashSupport pure-BSS ELF loading
The integrate package now supports multiple Linux distributions (linux64, Debian 10, CentOS 7) and provides SystemC 3.0.0/3.0.2 variants on Ubuntu, in addition to the SystemC 2.3.4 based standard package
Bug Fixes:
Fixed memory issues reported by AddressSanitizer, including incomplete spike-side teardown on model exit and several uninitialized variables
Fixed ECLIC pending-bit handling that caused continuous interrupt re-triggering, ECLIC re-arbitration after configuration register writes, edge-trigger handling and S-mode software interrupt issues
Fixed PLIC interrupts not being triggered when enabling an already-pending source or setting a pending bit of an already-enabled source
Registered the SSCRATCHCSW/SSCRATCHCSWL CSRs, fixing illegal-instruction errors in S-mode RT-Thread demos
Fixed lr/sc reservation invalidation across harts in SMP
Fixed the mtime advance model in Nearcycle/func mode (exact cycle-proportional Bresenham ratio instead of a floored ratio)
Fixed PMP fetch/load/store checks, instruction access fault reporting and page-fault exception injection
Fixed VNICE masked instructions not following the vector tail/mask-agnostic policy, and user-defined VNICE instructions being wrongly masked by
v0when bit 25 of the encoding is 0Fixed GDB connection issues: oversized packets that were not split and reassembled could terminate the GDB session, and bytes left over from an abnormally disconnected client corrupted the next client’s handshake
Fixed flame graph issues: RTOS tasks migrating across SMP cores were shown with duplicated thread identities, M-mode/S-mode interrupt handlers were attributed to the wrong interrupt thread lane, and frames of nested interrupt handlers were handled incorrectly across cross-mode preemptions, leaving orphaned frames
Fixed Ctrl+C not stopping the model properly in GDB mode; it now works in all modes and dumps the collected gprof and flame graph results on exit
Fixed UART issues: the interrupt output now uses transition-detected levels and the pending status is updated while the TX FIFO drains; interactive stdin input was restored and is fed to the RX FIFO regardless of the guest interrupt-enable state
Known Issues:
Does not support CACHE emulation
Two ThreadX SMP test cases livelock on nx900fd:
threadx_event_flag_isr_set_clear_testandthreadx_event_flag_isr_wait_abort_test. The timer tick lands in a window where the test ISR exit conditions never hold, so hart 0 spins inside_tx_thread_smp_protectwithout releasing the lock and the other harts starve. Both cases pass on n900fd, and the issue is sensitive to timing-model changes
8.10.2. Version 2025.10
This release is based on 2025.02 version with some new features and bug fixes introduced.
Support GDB debugging
Support flame graph
Add the CIDU module
Add Nuclei systimer support in CLINT mode
Support SMP ECLIC, can run smpdemo of FreeRTOS
Add new cpu support for the Nuclei n300e and 1000 series
Add zfinx/zhinx/zhinxmin/zdinx/zimop/zcmop/smaia/ssaia extensions
Add hypervisor aia
The base address and size of memory resources can be configured
Support for setting the CPU frequency
Output is separated into stdout and stderr
Known Issues:
Does not support CACHE emulation
Does not support booting a Linux Kernel
Some SMP cases for RT-Thread and Zephyr are not yet running correctly
When debugging with Nuclei Studio, if the ELF file lacks DWARF debug information, you need to add the
--mem=0x0:0x10000000option as a workaround to prevent GDB from reporting memory read errors
8.10.3. Version 2025.02
Known Issues:
Does not support smp ECLIC, CIDU and CACHE emulation
New Features:
Nuclei 200/300/900/1000 are supported, and support cpu core name are aligned with Nuclei SDK 0.7.1 release.
Added support for Windows system, now both windows and linux system are supported.
Added important parameters such as
--cpu,--ext, and--mem, and changed the--timeparameter to--timeoutAdded rough cycle calculation for vector instructions
Improvements:
Improved the CPU, Timer, and UART models
Improved the xlmodel_nice software package
Resolved the issue where some instructions could not be profiled
Adapted to run demo_vnice, demo_plic, and multiple RTOS cases in nuclei-sdk