svd-generator 0.2.0

Converts device information from flattened device tree into an SVD description
Documentation
use crate::svd::register::{
    create_bit_range, create_cluster, create_field, create_register, create_register_properties,
};
use crate::Result;

/// Creates a StarFive JH7110 SYS Pinctrl GPO DOEN register.
pub fn create() -> Result<svd::RegisterCluster> {
    Ok(svd::RegisterCluster::Cluster(create_cluster(
        "func_sel",
        "Registers used to configure the function selector of the system signal indicated by the register name.",
        0x29c,
        &[
            create_register_func_sel0()?,
            create_register_func_sel1()?,
            create_register_func_sel2()?,
            create_register_func_sel3()?,
            create_register_func_sel4()?,
            create_register_func_sel5()?,
            create_register_func_sel6()?,
        ],
        None,
    )?))
}

/// Function selector category.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
enum FuncSel {
    #[default]
    Gmac = 0,
    Gpio = 1,
    DvpData = 2,
    DvpHsync = 3,
    DvpVsync = 4,
    DvpClock = 5,
}

impl From<&FuncSel> for &'static str {
    fn from(val: &FuncSel) -> Self {
        match val {
            FuncSel::Gmac => "Function selector of GMAC1_RXC: * Function 0: u0_sys_crg.clk_gmac1_rgmii_rx, * Function 1: u0_sys_crg.clk_gmac1_rmii_ref, * Function 2: None, * Function 3: None",
            FuncSel::Gpio => "GPIO function selector: * Function 0: See Function Description no page 84 for more information, * Function 1: See Full Multiplexing for more information, * Function 2: See Function 2 for more information, * Function 3: See Function 3 for more information",
            FuncSel::DvpData => "Function Selector of DVP_DATA[idx], see Function 2 for more information",
            FuncSel::DvpHsync => "Function Selector of DVP_HSYNC, see Function 2 for more information",
            FuncSel::DvpVsync => "Function Selector of DVP_VSYNC, see Function 2 for more information",
            FuncSel::DvpClock => "Function Selector of DVP_CLK, see Function 2 for more information",
        }
    }
}

/// Convenience wrapper for field name, function selector, and bit range tuple.
type NameFuncRange = (String, FuncSel, svd::BitRange);

fn create_register_func_sel(idx: u32, nfra: &[NameFuncRange]) -> Result<svd::RegisterCluster> {
    let addr = idx * 4;
    Ok(svd::RegisterCluster::Register(create_register(
        format!("func_sel{idx}").as_str(),
        format!("SYS IOMUX CFG SAIF SYSCFG Function Selector {addr}").as_str(),
        addr,
        create_register_properties(32, 0)?,
        Some(
            nfra.iter()
                .filter_map(|(fname, func, range)| {
                    create_field(
                        fname.as_str(),
                        func.into(),
                        *range,
                        svd::Access::ReadWrite,
                        None,
                    )
                    .ok()
                })
                .collect::<Vec<svd::Field>>()
                .as_ref(),
        ),
        None,
    )?))
}

fn create_register_func_sel0() -> Result<svd::RegisterCluster> {
    let nfras = (0..11)
        .filter_map(|idx| {
            if idx == 0 {
                Some((
                    "pad_gmac1_rxc".into(),
                    FuncSel::Gmac,
                    create_bit_range("[1:0]").ok()?,
                ))
            } else {
                let pad = idx - 1;
                let bit = 2 + (pad * 3);
                let bit_end = bit + 2;

                Some((
                    format!("pad_gpio1{pad}"),
                    FuncSel::Gpio,
                    create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
                ))
            }
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(0, nfras.as_ref())
}

fn create_register_func_sel1() -> Result<svd::RegisterCluster> {
    let nfras = (0..10)
        .filter_map(|idx| {
            let pad = 20 + idx;
            let bit = idx * 3;
            let bit_end = bit + 2;

            Some((
                format!("pad_gpio{pad}"),
                FuncSel::Gpio,
                create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
            ))
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(1, nfras.as_ref())
}

fn create_register_func_sel2() -> Result<svd::RegisterCluster> {
    let nfras = (0..11)
        .filter_map(|idx| {
            let pad = 30 + idx;
            let bit = idx * 3;
            let bit_end = bit + 2;

            Some((
                format!("pad_gpio{pad}"),
                FuncSel::Gpio,
                create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
            ))
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(2, nfras.as_ref())
}

fn create_register_func_sel3() -> Result<svd::RegisterCluster> {
    let nfras = (0..11)
        .filter_map(|idx| {
            let pad = 41 + idx;
            let bit = idx * 3;
            let bit_end = bit + 2;

            Some((
                format!("pad_gpio{pad}"),
                FuncSel::Gpio,
                create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
            ))
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(3, nfras.as_ref())
}

fn create_register_func_sel4() -> Result<svd::RegisterCluster> {
    let nfras = (0..12)
        .filter_map(|idx| {
            if idx < 11 {
                let pad = 52 + idx;
                let (bit, bit_end) = if idx < 4 {
                    (idx * 2, (idx * 2) + 1)
                } else {
                    (idx * 3, (idx * 3) + 2)
                };

                Some((
                    format!("pad_gpio{pad}"),
                    FuncSel::Gpio,
                    create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
                ))
            } else {
                Some((
                    "pad_gpio63".into(),
                    FuncSel::Gpio,
                    create_bit_range("[31:30]").ok()?,
                ))
            }
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(4, nfras.as_ref())
}

fn create_register_func_sel5() -> Result<svd::RegisterCluster> {
    // indexes get a little weird here...
    let nfras = [6, 7, 8, 9, 0, 10, 11, 1, 2, 3, 4]
        .iter()
        .enumerate()
        .filter_map(|(idx, &pad)| {
            if idx == 0 {
                Some((
                    "pad_gpio6".into(),
                    FuncSel::Gpio,
                    create_bit_range("[1:0]").ok()?,
                ))
            } else if idx < 5 {
                let bit = idx * 2;
                let bit_end = bit + 2;

                Some((
                    format!("pad_gpio{pad}"),
                    FuncSel::Gpio,
                    create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
                ))
            } else {
                let bit = 11 + ((idx - 5) * 3);
                let bit_end = bit + 2;

                Some((
                    format!("vin_dvp_data{pad}"),
                    FuncSel::DvpData,
                    create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
                ))
            }
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(5, nfras.as_ref())
}

fn create_register_func_sel6() -> Result<svd::RegisterCluster> {
    let nfras = (0..8)
        .filter_map(|idx| {
            if idx < 6 {
                let data = 5 + idx;
                let bit = idx * 3;
                let bit_end = bit + 2;

                Some((
                    format!("vin_dvp_data{data}"),
                    FuncSel::DvpData,
                    create_bit_range(format!("[{bit_end}:{bit}]").as_str()).ok()?,
                ))
            } else if idx == 6 {
                Some((
                    "vin_dvp_hvalid".into(),
                    FuncSel::DvpHsync,
                    create_bit_range("[17:15]").ok()?,
                ))
            } else if idx == 7 {
                Some((
                    "vin_dvp_vvalid".into(),
                    FuncSel::DvpVsync,
                    create_bit_range("[20:18]").ok()?,
                ))
            } else {
                Some((
                    "dvp_clk".into(),
                    FuncSel::DvpClock,
                    create_bit_range("[23:21]").ok()?,
                ))
            }
        })
        .collect::<Vec<NameFuncRange>>();

    create_register_func_sel(6, nfras.as_ref())
}