1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::cmp;

use crate::Result;

/// Parses the peripheral `address` and `size` from the `reg` property.
///
/// See the `reg` entry in the Device Tree specification (section 2.3.6, spec v0.4).
pub fn parse_reg(
    node: &device_tree::Node,
    addr_cells: usize,
    size_cells: usize,
) -> Result<(u64, u32)> {
    let reg = node.prop_u32_list("reg")?;

    let address = reg
        .iter()
        .take(addr_cells)
        .enumerate()
        .map(|(i, &r)| (r as u64) << (32 * (addr_cells - i).saturating_sub(1)))
        .sum();

    let size = reg
        .iter()
        .skip(addr_cells)
        .take(size_cells)
        .enumerate()
        .map(|(i, &r)| (r as u64) << (32 * (size_cells - i).saturating_sub(1)))
        .sum::<u64>() as u32;

    Ok((address, size))
}

/// Parses the `ranges` property triplet `(child_bus, parent_bus, length)`.
///
/// See the `ranges` entry in the Device Tree specification (section 2.3.8, spec v0.4).
pub fn parse_ranges(node: &device_tree::Node, parent_addr_cells: usize) -> Result<(u64, u64, u64)> {
    let addr_cells = node.prop_u32("#address-cells")? as usize;
    let size_cells = node.prop_u32("#size-cells")? as usize;
    let ranges = node.prop_u32_list("ranges")?;

    let child_bus = ranges
        .iter()
        .take(parent_addr_cells)
        .enumerate()
        .map(|(i, &r)| (r as u64) << (32 * (parent_addr_cells - i).saturating_sub(1)))
        .sum();

    let parent_bus = ranges
        .iter()
        .skip(parent_addr_cells)
        .take(addr_cells)
        .enumerate()
        .map(|(i, &r)| (r as u64) << (32 * (addr_cells - i).saturating_sub(1)))
        .sum();

    let length = ranges
        .iter()
        .skip(parent_addr_cells + addr_cells)
        .take(size_cells)
        .enumerate()
        .map(|(i, &r)| (r as u64) << (32 * (size_cells - i).saturating_sub(1)))
        .sum();

    Ok((child_bus, parent_bus, length))
}

/// Parses the `interrupts` property.
///
/// # Parameters
///
/// - `node`: Device Tree node to parse
/// - `default_name`: default interrupt name (used if `interrupt-names` property is absent)
/// - `count`: optional peripheral count if more than one of its type exists
pub fn parse_interrupts(
    node: &device_tree::Node,
    default_name: &str,
    count: Option<usize>,
) -> Result<Vec<svd::Interrupt>> {
    // TODO: attempt to parse using `#interrupt-cells` value?
    let ints = node.prop_u32_list("interrupts")?;

    // `interrupt-names` is an unspecified property as of v0.4, so it may not be present
    let int_names: Vec<String> = match node.prop_str_list("interrupt-names") {
        Ok(n) => n.into_iter().map(|n| n.to_uppercase()).collect(),
        Err(_err) => {
            if ints.len() > 1 {
                // make sure we have a unique name for each interrupt if missing `interrupt-names`
                let n = default_name.to_uppercase();
                (0..ints.len()).map(|i| format!("{n}{i}")).collect()
            } else {
                // use the `default_name` as the interrupt name
                [default_name.to_uppercase()].into()
            }
        }
    };

    let len = cmp::min(ints.len(), int_names.len());

    let count_str = count.map(|c| format!("{c}")).unwrap_or_default();

    Ok(ints
        .into_iter()
        .take(len)
        .zip(int_names.into_iter().take(len))
        .filter_map(|(int, name)| {
            svd::Interrupt::builder()
                .name(format!("{name}{count_str}"))
                .value(int)
                .build(svd::ValidateLevel::Strict)
                .ok()
        })
        .collect())
}