use super::ir::{MicrochipBoard, MicrochipChip, MicrochipClocksConfig, MicrochipIr};
use anyhow::{Context, Result, anyhow};
use indexmap::IndexMap;
use std::path::Path;
pub fn yaml_to_chip(text: &str) -> Result<MicrochipChip> {
serde_yaml::from_str(text).context("parse microchip chip yaml")
}
pub fn yaml_to_board(text: &str) -> Result<MicrochipBoard> {
serde_yaml::from_str(text).context("parse microchip board yaml")
}
pub fn load_chip_db(name: &str) -> Result<MicrochipChip> {
let text = rlvgl_chips_microchip::chip_yaml(name)
.ok_or_else(|| anyhow!("microchip chipdb has no chip named '{name}'"))?;
yaml_to_chip(text).with_context(|| format!("parsing chipdb chip '{name}'"))
}
pub fn load_board_db(name: &str) -> Result<MicrochipBoard> {
let text = rlvgl_chips_microchip::board_yaml(name)
.ok_or_else(|| anyhow!("microchip chipdb has no board named '{name}'"))?;
yaml_to_board(text).with_context(|| format!("parsing chipdb board '{name}'"))
}
pub fn load_chip_file(path: &Path) -> Result<MicrochipChip> {
let text = std::fs::read_to_string(path)
.with_context(|| format!("read chip yaml {}", path.display()))?;
yaml_to_chip(&text).with_context(|| format!("parse chip yaml {}", path.display()))
}
pub fn load_board_file(path: &Path) -> Result<MicrochipBoard> {
let text = std::fs::read_to_string(path)
.with_context(|| format!("read board yaml {}", path.display()))?;
yaml_to_board(&text).with_context(|| format!("parse board yaml {}", path.display()))
}
pub fn merge(chip: MicrochipChip, board: MicrochipBoard) -> Result<MicrochipIr> {
if board.chip != chip.name {
return Err(anyhow!(
"board '{}' targets chip '{}' but loaded chip spec is '{}'",
board.name,
board.chip,
chip.name
));
}
validate_pins_against_chip(&chip, &board)?;
let clocks = default_clocks(&chip);
let pins = board.pins.clone();
Ok(MicrochipIr {
version: "0.1".to_string(),
chip,
board,
clocks,
pins,
metadata: IndexMap::new(),
})
}
fn default_clocks(chip: &MicrochipChip) -> MicrochipClocksConfig {
MicrochipClocksConfig {
cpu_hz: chip.clock_tree.cpu_hz,
apba_hz: chip.clock_tree.apba_hz,
apbb_hz: chip.clock_tree.apbb_hz,
apbc_hz: chip.clock_tree.apbc_hz.unwrap_or(0),
apbd_hz: chip.clock_tree.apbd_hz.unwrap_or(0),
xosc_hz: chip.clock_tree.xosc_hz.unwrap_or(0),
dfll_target_hz: chip.clock_tree.dfll_target_hz.unwrap_or(0),
dpll_target_hz: chip.clock_tree.dpll_target_hz.unwrap_or(0),
kernels: IndexMap::new(),
}
}
fn validate_pins_against_chip(chip: &MicrochipChip, board: &MicrochipBoard) -> Result<()> {
for pin in &board.pins {
if !chip.io_mux.iter().any(|p| p.pad == pin.pad) {
return Err(anyhow!(
"board '{}' assigns pad '{}' but chip '{}' does not expose it",
board.name,
pin.pad,
chip.name
));
}
}
let mut seen: IndexMap<&str, &str> = IndexMap::new();
for pin in &board.pins {
if let Some(label) = pin.label.as_deref()
&& let Some(prev) = seen.insert(label, &pin.pad)
{
return Err(anyhow!(
"board '{}' reuses label '{}' on pads {} and {}",
board.name,
label,
prev,
pin.pad
));
}
}
Ok(())
}