Dev Log
Engineering Tom Whitfield

RISC-V vs ARM Driver Generation

Compare register access, peripheral interfaces, and interrupt handling on RISC-V and ARM, including the target-specific changes Embedd makes.

RISC-V and ARM comparison of peripheral access and interrupt controller structures

An STM32L4 USART and a GigaDevice GD32VF103 UART both expose registers at fixed memory-mapped addresses. Their C-level access is nearly the same. The surrounding support infrastructure differs, and that is where most driver-generation work occurs.

What Both Architectures Share

Both architectures use the same MMIO pattern: each peripheral has a memory-map base address, its registers sit at fixed byte offsets, and C accesses them through volatile pointer dereferences. An STM32L4 USART transmit register and a GigaDevice GD32VF103 UART transmit register follow the same model: write a data byte to the register address and the peripheral transmits it. Bitfields, base addresses, and clock setup vary, but the core volatile pointer write does not.

That common model allows one basic generator structure for both targets. Embedd shares register-struct generation, while architecture-specific header templates provide volatile aliases, base-address definitions, and peripheral-struct pointer macros. Datasheet register-table extraction and bitfield-mask generation remain independent of architecture.

ARM Infrastructure: CMSIS and SVD

For ARM Cortex-M, driver generation benefits from standard conventions. CMSIS supplies common peripheral access types (__I, __O, __IO for read-only, write-only, and read-write volatile access), standard struct naming, and consistent system-register formats for SCB, SysTick, and DWT. CMSIS-compliant toolchains recognize these conventions.

SVD files, the CMSIS System View Description standard, represent a device's memory map, peripheral layouts, bitfield names, and interrupt assignments in XML. A reliable vendor SVD gives ARM driver generation structured input instead of requiring PDF datasheet parsing. Since SVD is machine-readable, it is faster to validate and generally more dependable for this purpose.

Vendor SVD quality is uneven. NXP and Nordic provide accurate files for most devices, while some ST files contain bitfield offset errors that conflict with the reference manual. When SVD reliability is uncertain, Embedd checks it against the datasheet PDF, treating the PDF as authoritative and the SVD as a comparison source. Any disagreement is flagged rather than resolved silently.

RISC-V: No Standard HAL, Many Vendors

RISC-V has no CMSIS counterpart. Its ISA specifies processor-core registers and a limited set of Control and Status Registers (CSRs) at fixed addresses, but vendors define peripheral layouts, names, and access rules themselves. RISC-V also lacks an equivalent SVD format that vendors consistently publish.

As a result, Embedd relies primarily on PDFs for RISC-V driver generation. The GD32VF103, WCH CH32V307, and SiFive FE310-G002 manuals use different structures. The GD32VF103 manual closely follows STM32 documentation because GigaDevice designed the part as an STM32F103 drop-in replacement, so the STM32 parser needs little adjustment. CH32V307 uses different register names and peripheral grouping, requiring its own parsing profile. SiFive uses a Freedom Metal SDK header format that Embedd can parse, though it supplies less bitfield metadata than a complete reference manual.

RISC-V's lack of standardization does not make device bring-up harder by itself. It does mean onboarding the first datasheet from a new RISC-V vendor family takes longer than onboarding one from an ARM vendor already indexed by Embedd.

Interrupts: NVIC Compared with PLIC

The generated code diverges most clearly around interrupts. ARM Cortex-M includes the NVIC, or Nested Vectored Interrupt Controller, in its architecture specification. Cortex-M devices place NVIC registers at fixed addresses on the processor's private peripheral bus, in the 0xE000E000 range. CMSIS offers a portable API: NVIC_SetPriority, NVIC_EnableIRQ, and NVIC_ClearPendingIRQ. Generated Cortex-M interrupt setup is therefore consistent apart from the IRQ number constant.

RISC-V relies on the PLIC, or Platform-Level Interrupt Controller, for external interrupts. The PLIC sits outside the RISC-V ISA specification and is a separate hardware block with a vendor-defined memory map. SiFive's layout has become a widely used de facto standard, but locations still vary across vendors. Enabling an interrupt requires setting the PLIC threshold, assigning source priority, and enabling that source in the PLIC enable register.

/* ARM Cortex-M NVIC interrupt enable (CMSIS standard) */
NVIC_SetPriority(USART1_IRQn, 3);
NVIC_EnableIRQ(USART1_IRQn);

/* GD32VF103 PLIC interrupt enable (vendor PLIC, SiFive-compatible layout) */
/* Set threshold to 0 (enable all priorities) */
*(volatile uint32_t *)(PLIC_BASE + PLIC_THRESHOLD) = 0;
/* Set priority for USART0 interrupt source (IRQ 56) */
*(volatile uint32_t *)(PLIC_BASE + PLIC_PRIORITY(56)) = 1;
/* Enable interrupt source 56 in hart 0 enable register */
*(volatile uint32_t *)(PLIC_BASE + PLIC_ENABLE(0, 56)) |= (1 << (56 % 32));

Embedd emits the interrupt setup appropriate to each target. The public call stays the same: embx_gd32vf_usart0_irq_enable(priority). The generated sequence then uses the required PLIC or NVIC path.

Atomic Access: LDREX/STREX and LR/SC

Peripheral registers shared between interrupt and application contexts need atomic read-modify-write operations to prevent races. ARM Cortex-M (M3 and later) supplies LDREX and STREX, enabling an optimistic access loop with retries. On Cortex-M targets, GCC compiles C11 atomic operations into LDREX/STREX sequences.

RISC-V's A extension supplies the equivalent atomic operations, LR (Load-Reserved) and SC (Store-Conditional). C11 atomics compile properly on RISC-V targets that include A, and most embedded RISC-V MCUs do. The GD32VF103 implements RV32IMAC, including the A atomic extension.

For registers requiring atomic read-modify-write, Embedd uses C11 atomic accessor functions when the target provides both ISA support and compiler-extension support. Without atomic instructions, generated accessors use critical sections, disabling and then enabling global interrupts. Header comments identify the method selected for each accessor.

How Output Differs by Architecture

In Embedd's generated output, ARM and RISC-V differ in interrupt configuration, including PLIC or NVIC calls, and in the CMSIS type aliases unavailable on RISC-V. Register-struct layouts, bitfield-mask macros, HAL APIs, and test stubs retain the same structure. Call embx_uart_init, provide a configuration struct, and receive the driver. The target architecture stays inside the implementation.

Both architectures share the same constraint: generation follows the datasheet. If that document is incomplete or incorrect, the driver reflects it. Errata and undocumented register behavior occur on ARM and RISC-V devices alike and fall outside automatic generation.

Generate a driver today

Upload a chip datasheet and receive C99 peripheral drivers in under two minutes.

Get started free