opentitanlib/util/vmem/
mod.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5//! This module contains code for working with Verilog `vmem` files.
6//!
7//! This includes the [`Vmem'] representation which can be parsed from a string.
8
9use std::iter;
10use std::str::FromStr;
11
12mod parser;
13
14use parser::VmemParser;
15pub use parser::{ParseError, ParseResult};
16
17/// Representation of a vmem file.
18///
19/// These files consist of sections which are runs of memory starting at some address.
20#[derive(Clone, Debug, Default, PartialEq, Eq)]
21pub struct Vmem {
22    sections: Vec<Section>,
23}
24
25/// Section of memory at some address in the vmem file.
26#[derive(Clone, Debug, Default, PartialEq, Eq)]
27pub struct Section {
28    pub addr: u32,
29    pub data: Vec<u32>,
30}
31
32impl FromStr for Vmem {
33    type Err = ParseError;
34
35    /// Parse the vmem file from a complete string.
36    fn from_str(s: &str) -> Result<Self, Self::Err> {
37        VmemParser::parse(s)
38    }
39}
40
41impl Vmem {
42    /// Returns an iterator over sections of the vmem file.
43    pub fn sections(&self) -> impl Iterator<Item = &Section> {
44        // Filter out empty sections.
45        self.sections
46            .iter()
47            .filter(|section| !section.data.is_empty())
48    }
49}
50
51/// Represents some value at some address as specified in the vmem file.
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub struct Data {
54    pub addr: u32,
55    pub value: u32,
56}
57
58impl Vmem {
59    /// Returns an iterator over all data of the vmem file.
60    pub fn data_addrs(&self) -> impl Iterator<Item = Data> + '_ {
61        self.sections().flat_map(|section| section.data_addrs())
62    }
63
64    /// Merge all continguous sections together in one section
65    pub fn merge_sections(&mut self) {
66        let mut res: Vec<Section> = Vec::new();
67        // we modify in place as much as possible to avoid copying data uselessly
68        for mut sec in std::mem::take(&mut self.sections) {
69            match res.last_mut() {
70                Some(ref mut last) if { last.addr + last.data.len() as u32 * 4 == sec.addr } => {
71                    last.data.append(&mut sec.data)
72                }
73                _ => res.push(sec),
74            }
75        }
76        self.sections = res
77    }
78}
79
80impl Section {
81    /// Returns an iterator over all data of this section of the vmem file.
82    pub fn data_addrs(&self) -> impl Iterator<Item = Data> + '_ {
83        let addrs = (self.addr..).step_by(4);
84        let values = self.data.iter();
85        iter::zip(addrs, values).map(|(addr, value)| Data {
86            addr,
87            value: *value,
88        })
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use super::*;
95
96    #[test]
97    fn vmem_data() {
98        let vmem = Vmem::from_str("@10 12 23 34 @20 @26 45").unwrap();
99        let expected = [(0x40, 0x12), (0x44, 0x23), (0x48, 0x34), (0x98, 0x45)]
100            .map(|(addr, value)| Data { addr, value });
101
102        let data: Vec<_> = vmem.data_addrs().collect();
103        assert_eq!(data, expected);
104    }
105
106    #[test]
107    fn section_data() {
108        let section = Section {
109            addr: 0x42,
110            data: vec![0x12, 0x23, 0x34, 0x45],
111        };
112        let expected = [(0x42, 0x12), (0x46, 0x23), (0x4a, 0x34), (0x4e, 0x45)]
113            .map(|(addr, value)| Data { addr, value });
114
115        let data: Vec<_> = section.data_addrs().collect();
116        assert_eq!(data, expected);
117    }
118}