From c54edd34c4b3ccfff29b3b485b9ce3c48dd5773c Mon Sep 17 00:00:00 2001 From: zackees Date: Tue, 21 Jul 2026 16:48:59 -0700 Subject: [PATCH] fix(ch32v): honor board ISA and ABI settings Closes #1106 --- .../src/ch32v/ch32v_compiler.rs | 13 ++- .../fbuild-build-mcu/src/ch32v/mcu_config.rs | 82 +++++++++++++++++-- .../src/ch32v/orchestrator.rs | 7 +- crates/fbuild-config/src/board/db.rs | 6 ++ crates/fbuild-config/src/board/loaders.rs | 10 +++ crates/fbuild-config/src/board/types.rs | 6 ++ 6 files changed, 117 insertions(+), 7 deletions(-) diff --git a/crates/fbuild-build-mcu/src/ch32v/ch32v_compiler.rs b/crates/fbuild-build-mcu/src/ch32v/ch32v_compiler.rs index e8fce11ce..6286fbd7a 100644 --- a/crates/fbuild-build-mcu/src/ch32v/ch32v_compiler.rs +++ b/crates/fbuild-build-mcu/src/ch32v/ch32v_compiler.rs @@ -267,7 +267,7 @@ impl Compiler for Ch32vCompiler { #[cfg(test)] mod tests { use super::*; - use crate::ch32v::mcu_config::get_ch32v_config_for_mcu; + use crate::ch32v::mcu_config::{apply_board_isa, get_ch32v_config_for_mcu}; fn test_compiler() -> Ch32vCompiler { let mut defines = HashMap::new(); @@ -297,6 +297,17 @@ mod tests { assert!(flags.contains(&"-mabi=ilp32e".to_string())); } + #[test] + fn test_common_flags_use_board_isa() { + let mut config = get_ch32v_config_for_mcu("ch32v203").unwrap(); + apply_board_isa(&mut config, Some("rv32imacxw"), Some("ilp32")); + let mut compiler = test_compiler(); + compiler.mcu_config = config; + let flags = compiler.c_flags(); + assert!(flags.contains(&"-march=rv32imac_zicsr".to_string())); + assert!(flags.contains(&"-mabi=ilp32".to_string())); + } + #[test] fn test_common_flags_contain_optimization() { let compiler = test_compiler(); diff --git a/crates/fbuild-build-mcu/src/ch32v/mcu_config.rs b/crates/fbuild-build-mcu/src/ch32v/mcu_config.rs index 37b12fc7f..c8bbecec9 100644 --- a/crates/fbuild-build-mcu/src/ch32v/mcu_config.rs +++ b/crates/fbuild-build-mcu/src/ch32v/mcu_config.rs @@ -66,30 +66,102 @@ impl McuConfig for Ch32vMcuConfig { /// /// The series is derived from the board JSON `build.series` field /// (e.g. "ch32v003", "ch32v203", "ch32v307"). -pub fn get_ch32v_config_for_mcu(mcu: &str) -> Result { +pub fn get_ch32v_config_for_mcu(series: &str) -> Result { // All CH32V variants currently share the CH32V003 config as a base, // with march/mabi overridden from the board JSON extra_flags. - let json = match mcu { + let json = match series { "ch32v003" => CH32V003_JSON, _ => { // For other CH32V series, use the CH32V003 config as a base. - // The board JSON's extra_flags and march/mabi fields provide - // the series-specific differences. CH32V003_JSON } }; serde_json::from_str(json).map_err(|e| { fbuild_core::FbuildError::ConfigError(format!( "failed to parse CH32V MCU config for '{}': {}", - mcu, e + series, e )) }) } +/// Normalize a board-JSON ISA string for the xPack RISC-V GCC toolchain. +pub fn normalize_march(march: &str) -> String { + let mut normalized = march.to_ascii_lowercase(); + if let Some(stripped) = normalized.strip_suffix("xw") { + normalized = stripped.to_string(); + } + if !normalized.contains("zicsr") { + normalized.push_str("_zicsr"); + } + normalized +} + +/// Apply board ISA and ABI values to compiler and linker flags. +pub fn apply_board_isa(config: &mut Ch32vMcuConfig, march: Option<&str>, mabi: Option<&str>) { + fn replace(flags: &mut [String], prefix: &str, value: &str) { + for flag in flags { + if flag.starts_with(prefix) { + *flag = format!("{prefix}{value}"); + } + } + } + + if let Some(march) = march { + let normalized = normalize_march(march); + replace(&mut config.compiler_flags.common, "-march=", &normalized); + replace(&mut config.linker_flags, "-march=", &normalized); + } + if let Some(mabi) = mabi { + replace(&mut config.compiler_flags.common, "-mabi=", mabi); + replace(&mut config.linker_flags, "-mabi=", mabi); + } +} + #[cfg(test)] mod tests { use super::*; + #[test] + fn test_normalize_march() { + assert_eq!(normalize_march("rv32imacxw"), "rv32imac_zicsr"); + assert_eq!(normalize_march("rv32imac"), "rv32imac_zicsr"); + assert_eq!(normalize_march("rv32ec_zicsr"), "rv32ec_zicsr"); + assert_eq!(normalize_march("rv32ecxw"), "rv32ec_zicsr"); + } + + #[test] + fn test_apply_board_isa_updates_compiler_and_linker() { + let mut config = get_ch32v_config_for_mcu("ch32v003").unwrap(); + apply_board_isa(&mut config, Some("rv32imacxw"), Some("ilp32")); + assert!( + config + .compiler_flags + .common + .contains(&"-march=rv32imac_zicsr".to_string()) + ); + assert!( + config + .compiler_flags + .common + .contains(&"-mabi=ilp32".to_string()) + ); + assert!( + config + .linker_flags + .contains(&"-march=rv32imac_zicsr".to_string()) + ); + assert!(config.linker_flags.contains(&"-mabi=ilp32".to_string())); + } + + #[test] + fn test_apply_board_isa_none_is_noop() { + let mut config = get_ch32v_config_for_mcu("ch32v003").unwrap(); + let before = config.clone(); + apply_board_isa(&mut config, None, None); + assert_eq!(config.compiler_flags.common, before.compiler_flags.common); + assert_eq!(config.linker_flags, before.linker_flags); + } + #[test] fn test_ch32v003_config_parses() { let config = get_ch32v_config_for_mcu("ch32v003").unwrap(); diff --git a/crates/fbuild-build-mcu/src/ch32v/orchestrator.rs b/crates/fbuild-build-mcu/src/ch32v/orchestrator.rs index 795c392c5..c5a5d97ef 100644 --- a/crates/fbuild-build-mcu/src/ch32v/orchestrator.rs +++ b/crates/fbuild-build-mcu/src/ch32v/orchestrator.rs @@ -106,7 +106,12 @@ impl BuildOrchestrator for Ch32vOrchestrator { ); // 7. Build include dirs + compiler - let mcu_config = super::mcu_config::get_ch32v_config_for_mcu(&series)?; + let mut mcu_config = super::mcu_config::get_ch32v_config_for_mcu(&series)?; + super::mcu_config::apply_board_isa( + &mut mcu_config, + ctx.board.march.as_deref(), + ctx.board.mabi.as_deref(), + ); let mut defines = ctx.board.get_defines(); defines.extend(mcu_config.defines_map()); defines.insert(system_series.clone(), "1".to_string()); diff --git a/crates/fbuild-config/src/board/db.rs b/crates/fbuild-config/src/board/db.rs index 7c215b698..62528e16b 100644 --- a/crates/fbuild-config/src/board/db.rs +++ b/crates/fbuild-config/src/board/db.rs @@ -252,6 +252,12 @@ fn flatten_board_entry(entry: &serde_json::Value, board_id: &str) -> HashMap, /// Extra build flags from board definition pub extra_flags: Option, + /// RISC-V ISA string from board JSON `build.march`. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub march: Option, + /// RISC-V ABI string from board JSON `build.mabi`. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub mabi: Option, /// Upload protocol (e.g. "arduino", "esptool", "teensy-gui") pub upload_protocol: Option, /// Upload speed