Skip to content

ch32v: board JSON march/mabi are dead — every series compiles as RV32EC/ilp32e, IMAC parts get software multiply #1106

Description

@zackees

Part of the CH32V pipeline audit (#1102).

What happens

Every CH32V board JSON carries the ISA/ABI for its core, e.g. genericCH32V203C8T6.json:

"march": "rv32imacxw",
"mabi": "ilp32",

but nothing reads these fields. BoardConfig (fbuild-config) has no march/mabi members (grep: zero hits outside the JSON assets), and get_ch32v_config_for_mcu() in crates/fbuild-build-mcu/src/ch32v/mcu_config.rs returns the CH32V003 base config for every series:

// All CH32V variants currently share the CH32V003 config as a base,
// with march/mabi overridden from the board JSON extra_flags.   <-- this override does not exist
let json = match mcu {
    "ch32v003" => CH32V003_JSON,
    _ => CH32V003_JSON,
};

configs/ch32v003.json pins -march=rv32ec_zicsr -mabi=ilp32e, and extra_flags only ever contributes -D defines (BoardConfig::get_defines). Net effect: CH32V103, V203, V208, V303, V307, X035 and L103 — all RV32IMAC-class QingKe V3/V4 cores per WCH's datasheets — are compiled and linked as RV32EC with the ilp32e ABI.

Why it matters — worked example

int32_t c = a * b; on a CH32V203 (144 MHz, hardware multiplier) compiles to a call into libgcc's software __mulsi3 instead of a single mul instruction — a ~20x slowdown on multiply-heavy code (filters, LED color math). Division is worse. On top of that only registers x0–x15 are ever allocated, and the C++ -isystem multilib path (derived in orchestrator.rs from the same base config) selects the rv32ec/ilp32e headers, so the whole toolchain is consistently building for the wrong ISA. Builds pass and binaries run (RV32EC is a subset of RV32IMAC), which is why CI never noticed.

Notes for the fix

  • Parse build.march/build.mabi into BoardConfig and inject them (overriding the base config's pair) into compile + link + the multilib get_cxx_system_includes() call.
  • The JSON value rv32imacxw is a MounRiver-ism: the xw (WCH compressed) extension is not accepted by the xPack riscv-none-elf-gcc fbuild installs — strip xw (use rv32imac, or rv32imac_zicsr per toolchain version) or translate when building the flag, otherwise the wire-up will break every non-003 board at configure time.
  • get_ch32v_config_for_mcu(mcu: &str) is actually called with the series string — rename the parameter while touching this.

Severity: HIGH (large silent performance/codegen regression on 7 of 8 supported series; misleading comment claims the override exists).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions