Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion crates/fbuild-build-mcu/src/ch32v/ch32v_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
82 changes: 77 additions & 5 deletions crates/fbuild-build-mcu/src/ch32v/mcu_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ch32vMcuConfig> {
pub fn get_ch32v_config_for_mcu(series: &str) -> Result<Ch32vMcuConfig> {
// 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();
Expand Down
7 changes: 6 additions & 1 deletion crates/fbuild-build-mcu/src/ch32v/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
6 changes: 6 additions & 0 deletions crates/fbuild-config/src/board/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ fn flatten_board_entry(entry: &serde_json::Value, board_id: &str) -> HashMap<Str
if let Some(flags) = build.get("extra_flags").and_then(|v| v.as_str()) {
d.insert("extra_flags".into(), flags.to_string());
}
if let Some(v) = build.get("march").and_then(|v| v.as_str()) {
d.insert("march".into(), v.to_string());
}
if let Some(v) = build.get("mabi").and_then(|v| v.as_str()) {
d.insert("mabi".into(), v.to_string());
}
if let Some(vid) = build.get("vid").and_then(|v| v.as_str()) {
d.insert("vid".into(), vid.to_string());
}
Expand Down
10 changes: 10 additions & 0 deletions crates/fbuild-config/src/board/loaders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ impl BoardConfig {
usb_product: get("usb_product"),
usb_manufacturer: get("usb_manufacturer"),
extra_flags: get("extra_flags"),
march: get("march"),
mabi: get("mabi"),
upload_protocol: get("upload.protocol")
.or_else(|| props.get("upload.protocol").cloned()),
upload_speed: get("upload.speed").or_else(|| props.get("upload.speed").cloned()),
Expand Down Expand Up @@ -348,6 +350,14 @@ impl BoardConfig {
.get("extra_flags")
.cloned()
.or_else(|| defaults.get("extra_flags").cloned()),
march: overrides
.get("march")
.cloned()
.or_else(|| defaults.get("march").cloned()),
mabi: overrides
.get("mabi")
.cloned()
.or_else(|| defaults.get("mabi").cloned()),
upload_protocol: overrides
.get("upload.protocol")
.cloned()
Expand Down
6 changes: 6 additions & 0 deletions crates/fbuild-config/src/board/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ pub struct BoardConfig {
pub usb_manufacturer: Option<String>,
/// Extra build flags from board definition
pub extra_flags: Option<String>,
/// RISC-V ISA string from board JSON `build.march`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub march: Option<String>,
/// RISC-V ABI string from board JSON `build.mabi`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mabi: Option<String>,
/// Upload protocol (e.g. "arduino", "esptool", "teensy-gui")
pub upload_protocol: Option<String>,
/// Upload speed
Expand Down
Loading