use super::ir::*;
use anyhow::{Context, Result, bail};
use std::path::Path;
pub fn yaml_to_chip(text: &str) -> Result<RenesasChip> {
serde_yaml::from_str(text).context("parse Renesas chip YAML")
}
pub fn yaml_to_board(text: &str) -> Result<RenesasBoard> {
serde_yaml::from_str(text).context("parse Renesas board YAML")
}
pub fn load_chip_db(name: &str) -> Result<RenesasChip> {
let text = rlvgl_chips_renesas::chip_yaml(name)
.with_context(|| format!("no Renesas chip '{name}' in db"))?;
yaml_to_chip(text)
}
pub fn load_board_db(name: &str) -> Result<RenesasBoard> {
let text = rlvgl_chips_renesas::board_yaml(name)
.with_context(|| format!("no Renesas board '{name}' in db"))?;
yaml_to_board(text)
}
pub fn load_chip_file(path: &Path) -> Result<RenesasChip> {
let text = std::fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
yaml_to_chip(&text)
}
pub fn load_board_file(path: &Path) -> Result<RenesasBoard> {
let text = std::fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
yaml_to_board(&text)
}
pub fn merge(chip: RenesasChip, board: RenesasBoard) -> Result<RenesasIr> {
if !board.chip.eq_ignore_ascii_case(&chip.name) {
bail!(
"board chip '{}' does not match chip name '{}'",
board.chip,
chip.name
);
}
validate_pins(&chip, &board)?;
let clocks = RenesasClocksConfig {
cpu_hz: chip.cpu_hz,
pclka_hz: chip.clock_tree.pclka_hz,
pclkb_hz: chip.clock_tree.pclkb_hz,
pclkc_hz: chip.clock_tree.pclkc_hz,
pclkd_hz: chip.clock_tree.pclkd_hz,
};
let pins = board.pins.clone();
Ok(RenesasIr {
chip,
board,
clocks,
pins,
})
}
fn validate_pins(chip: &RenesasChip, board: &RenesasBoard) -> Result<()> {
let mut labels_seen = std::collections::HashSet::new();
let mut pins_seen = std::collections::HashSet::new();
for pin in &board.pins {
let port_entry = chip
.gpio_ports
.iter()
.find(|gp| gp.port == pin.port)
.with_context(|| format!("port {} not in chip gpio_ports", pin.port))?;
if pin.pin >= port_entry.pin_count {
bail!(
"P{}{}: pin {} out of range (port {} has {} pins)",
pin.port,
pin.pin,
pin.pin,
pin.port,
port_entry.pin_count
);
}
let key = (pin.port, pin.pin);
if !pins_seen.insert(key) {
bail!("P{}{} assigned more than once", pin.port, pin.pin);
}
if let Some(psel_val) = pin.psel {
let pfs_entry = chip.pfs_table.iter().find(|e| {
e.pin
== (RenesasPortPin {
port: pin.port,
pin: pin.pin,
})
});
if let Some(entry) = pfs_entry {
let has_match = entry.functions.iter().any(|f| f.psel == psel_val);
if !has_match {
bail!(
"P{}{}: psel {} not found in chip PFS table for this pin",
pin.port,
pin.pin,
psel_val
);
}
}
}
if let Some(periph) = &pin.peripheral {
if !chip.peripherals.contains_key(periph.as_str()) {
bail!(
"P{}{} references peripheral '{}' not in chip",
pin.port,
pin.pin,
periph
);
}
}
if let Some(label) = &pin.label {
if !labels_seen.insert(label.clone()) {
bail!("duplicate label '{}'", label);
}
}
}
Ok(())
}