andes-riscv
The RISC-V architecture support crate for Andes' RISC-V cores.
This crate has machine-generated code from YAML definitions.
This crate is a supplement to the riscv crate, which provides the core RISC-V support.
CSR code is generated by yaml2pac in rvcsr mode, using upstream chiptool IR.
- yaml2pac: https://github.com/embedded-drivers/yaml2pac
- chiptool: https://github.com/embassy-rs/chiptool
Overview
Series
- Entry Series: D23, N22
- 25 Series
- 27 Series
- 45 Series
- AX60 Series
Known Platform and Chips
- HPMicro's HPM5xxx/HPM6xxx series, D25(F)/D45 core
- BK7256, D25(F) dual core
- Renesas' RZ/Five MPU, AX45MP single core
- SBC: Tinker V
- Renesas' R9A0 series, N22 or D25(F) core
- Telink's TLSR9 series, D25(F) core
- GOWIN's GW5AST-138, FPGA with Andes A25 RISC-V CPU IP and AE350 subsystem
Project Status
- 32-bit CSRs
- L1C operations
- DSP (P-extension) intrinsics — complete ~190 instructions
- 64-bit platform support
API Style
The CSR API uses module-per-CSR style.
// Read typed CSR
let en = read.dc_en;
// Single-bit atomic CSR operations (single instruction)
unsafe
unsafe
// Multi-bit fields use read-modify-write
unsafe
unsafe
Migration Notes (0.1.x -> 0.2.x)
- CSR entrypoints changed from
register::foo().read()/modify()toregister::foo::read()/modify(). - Raw untyped CSR helpers now use
usizeinread()/write()for better XLEN alignment. - Single-bit field operations expose atomic
set_xxx()/clear_xxx()helpers.
DSP (P-extension) Intrinsics
The dsp module provides all ~190 Andes V5 DSP instructions, works on stable Rust via core::arch::asm!.
use dsp;
let r = kadd16; // 2x16-bit saturating add
let m = smmul; // MSW 32x32 multiply
let acc = smaqa; // 4x8-bit multiply-accumulate
let = smar64; // 32x32 MAC to 64-bit
Runtime detection:
if read.edsp
Performance (HPM6750 benchmark, N=1000)
| Instruction | DSP | Scalar | Speedup | Description |
|---|---|---|---|---|
kadd16 |
7 | 19 | 2.7x | 2x16-bit saturating add |
smmul |
7 | 7 | 1.0x | Scalar mulh is already equivalent |
kmda |
8 | 15 | 1.8x | Dual 16x16 multiply-add |
smaqa |
10 | 46 | 4.5x | 4x8-bit multiply-accumulate |
smar64 |
17 | 19 | 1.1x | Register pair (a4/a5) overhead dominates |
(cycles/iteration, opt-level="z")
Alternative: core::arch::riscv32 (nightly)
Rust nightly provides built-in P-extension intrinsics via core::arch::riscv32 (feature gate riscv_ext_intrinsics). These are native LLVM intrinsics, so the compiler can do register allocation, instruction scheduling, and constant folding — no .insn limitations.
However, core::arch::riscv32 only covers 105 base SIMD instructions from the RISC-V P-extension draft (opcode 0x77). The Andes V5 DSP extension uses a different opcode (0x7F, custom-3) and includes ~190 instructions — the extra ~85 are Andes-specific extensions not in core::arch:
core::arch::riscv32 |
andes_riscv::dsp |
|
|---|---|---|
| Instructions | 105 (P-ext draft) | ~190 (complete Andes V5) |
| Rust version | nightly only | stable |
| Opcode | 0x77 (OP-P) |
0x7F (custom-3) |
| Compiler optimization | full (native intrinsics) | limited (.insn opaque) |
| Register pair freedom | compiler-allocated | hard-coded a4/a5 |
Missing from core::arch (Andes-only):
- MSW 32x32 multiply family (
smmul,kmmac,kmmsb,smmwb,smmwt, ...) - 32x32 → 64-bit MAC family (
smar64,smsr64,kmar64, ...) - Dual 16x16 multiply family (
kmda,kmxda,smds,kmada, ...) - KDM/KHM saturating double/half multiply (
kdmbb,khmbb, ...) - 64-bit arithmetic (
add64,sub64,kadd64, ...) - Packed multiply to 64-bit (
smul16,smul8,mulsr64, ...) - Misc:
bpick,insb,wext,sclip32,uclip32, ...
Recommendation: Use andes_riscv::dsp for the complete instruction set on stable Rust. If you only need the base 105 SIMD instructions and can use nightly, core::arch::riscv32 will give better codegen for register-pair instructions.
Known Limitations (.insn approach)
Since LLVM has no native Andes V5 DSP support, all instructions are emitted via .insn inline assembly. This has two consequences:
-
64-bit register pair instructions (
smar64,smalda,smul16, etc.) are hard-coded to use the a4/a5 register pair. The compiler cannot freely allocate registers, which causes spill/reload overhead — especially when function calls exist in the loop body. -
The compiler treats DSP instructions as opaque — no constant folding, instruction scheduling, CSE, or auto-vectorization is possible across DSP intrinsics.
Single-register DSP instructions (kadd16, kmda, smaqa, etc.) are #[inline(always)] and have negligible overhead after inlining.
Features
defmt: enablesdefmt::Formaton generated fieldset/register types.
CSRs
AndeStar V5 machine mode CSRs
Configuration Registers
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0xFC0 | MRO | micm_cfg | Instruction cache/memory configuration. |
| 0xFC1 | MRO | mdcm_cfg | Data cache/memory configuration. |
| 0xFC2 | MRO | mmsc_cfg | Miscellaneous configuration. |
| 0xFC3 | MRO | mmsc_cfg2 | Miscellaneous configuration. (RV32) |
| 0xFC7 | MRO | mvec_cfg | Vector processor configuration. |
| 0xFCF | MRO | mccache_ctl_base | Cluster cache control base address |
| 0xFCA | MRO | mrvarch_cfg | RISC-V Architecture |
Crash Debug CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0xFC8 | MRO | mcrash_statesave | Current state save for crash debugging |
| 0xFC9 | MRO | mstatus_crashsave | mstatus state save for crash debugging |
Memory CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7C0 | MRW | milmb | Instruction local memory base address. |
| 0x7C1 | MRW | mdlmb | Data local memory base address. |
| 0x7C2 | MRW | mecc_code | ECC code. |
| 0x7C3 | MRW | mnvec | NMI-handler base address. |
| 0x7CA | MRW | mcache_ctl | Cache control |
| 0x7CB | MRW | mcctlbeginaddr | CCTL begin address |
| 0x7CC | MRW | mcctlcommand | CCTL command |
| 0x7CD | MRW | mcctldata | CCTL data |
| 0x7F0 | MRW | mppib | Private peripheral interface base address |
| 0x7F1 | MRW | mfiob | Fast IO interface base address |
Hardware Stack Protection & Recording
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7C6 | MRW | mhsp_ctl | Hardware stack protection control |
| 0x7C7 | MRW | msp_bound | SP bound register |
| 0x7C8 | MRW | msp_base | SP base register |
Trap related CSR
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7C4 | MRW | mxstatus | Additional machine mode status |
| 0x7C9 | MRW | mdcause | Detailed exception cause |
| 0x7D5 | MRW | mslidedleg | Supervisor local interrupt delegation |
| 0x7D6 | MRW | msavestatus | Status save register (level 1 & level 2) |
| 0x7D7 | MRW | msaveepc1 | EPC save register (level 1) |
| 0x7D8 | MRW | msavecause1 | Exception cause save register (level 1) |
| 0x7D9 | MRW | msaveepc2 | EPC save register (level 2) |
| 0x7DA | MRW | msavecause2 | Exception cause save register (level 2) |
| 0x7DB | MRW | msavedcause1 | Detailed exception cause save (level 1) |
| 0x7DC | MRW | msavedcause2 | Detailed exception cause save (level 2) |
Control CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7C5 | MRW | mpft_ctl | Performance throttling control |
| 0x7D0 | MRW | mmisc_ctl | Miscellaneous control |
| 0x7DF | MRW | mclk_ctl | Clock control |
Counter related CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7CE | MRW | mcounterwen | Counter write enable |
| 0x7CF | MRW | mcounteriinten | Counter overflow interrupt enable |
| 0x7D1 | MRW | mcountermask_m | Counter not counting in M-mode |
| 0x7D2 | MRW | mcountermask_s | Counter not counting in S-mode |
| 0x7D3 | MRW | mcountermask_u | Counter not counting in U-mode |
| 0x7D4 | MRW1C | mcounterrovf | Counter overflow status |
Enhanced CLIC CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7EC | MRW | mirq_entry | Interrupt common entry point |
| 0x7ED | MRW | mintsel_jal | Select interrupt and call ISR |
| 0x7EE | MRW | pushmcause | Store mcause to stack |
| 0x7EF | MRW | pushmepc | Store mepc to stack |
| 0x7EB | MRW | pushmxstatus | Store mxstatus to stack |
Physical Memory Attribute CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0xBC0 | MRW | pmacfg0 | PMA configuration |
| 0xBC1 | MRW | pmpcfg1 | PMA configuration (RV32 only) |
| 0xBC2 | MRW | pmpcfg2 | PMA configuration |
| 0xBC3 | MRW | pmpcfg3 | PMA configuration (RV32 only) |
| 0xBD0~BDF | MRW | pmaaddr0~15 | PMA address |
AndeStar V5 debug mode CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x7E0 | DRW | dexc2dbg | Enable exception to enter Halt Mode. |
| 0x7E1 | DRW | ddcause | Detailed exception type information when an exception enters Halt Mode. |
AndeStar V5 supervisor mode CSRs
Supervisor Trap Related
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x9C4 | SRW | slie | Supervisor local interrupt enable |
| 0x9C5 | SRW | slip | Supervisor local interrupt pending |
| 0x9C9 | SRW | sdcause | Detailed exception cause |
Supervisor Counter Related
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x9CF | SRO/SRW | scounteri nten | Counter overflow interrupt enable |
| 0x9D1 | SRO/SRW | scountermask_m | Counter mask for M-mode |
| 0x9D2 | SRO/SRW | scountermask_s | Counter mask for S-mode |
| 0x9D3 | SRO/SRW | scountermask_u | Counter mask for U-mode |
| 0x9D4 | SRO/SRW1C | scounterrovf | Counter overflow status |
| 0x9E0 | SRO/SRW | scountiinhibit | Supervisor counter inhibit |
| 0x9E3~6 | SRO/SRW | shpmevent3~6 | Performance monitoring event selection |
Supervisor Control
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x9CD | SRW | scctldata | CCTL data |
| 0x9D0 | SRW | smisc_ctl | Miscellaneous control |
AndeStar V5 user mode CSRs
| Address | Privilege | Name | Description |
|---|---|---|---|
| 0x800 | URW | uitb | Instruction table base address for CoDense extension. |
| 0x801 | URW | ucode | Contains overflow flag for DSP extension. |
| 0x809 | URW | udcause | User detailed trap cause |
| 0x80B | URW | ucctlbeginaddr | CCTL begin address |
| 0x80C | URW | ucctlcommand | CCTL command |
| 0x810 | URW | wfe | Wait for event control |
| 0x811 | URW | sleepvalue | Sleep value |
| 0x812 | URW | txevt | Transmit event |