1use crate::error::Error;
2use serde::{Serialize, Serializer};
3use std::fmt;
4use std::str::FromStr;
5#[derive(Debug, Serialize)]
6pub struct Page {
7 #[serde(serialize_with = "to_hex32_string")]
8 pub(crate) address: u32,
9 pub(crate) size: u32,
10}
11
12fn to_hex32_string<S>(value: &u32, s: S) -> Result<S::Ok, S::Error>
13where
14 S: Serializer,
15{
16 s.serialize_str(&format!("0x{:08X}", value))
17}
18
19#[derive(Debug, Serialize)]
20pub struct MemoryLayout {
21 pages: Vec<Page>,
22}
23
24impl FromStr for MemoryLayout {
25 type Err = Error;
26 fn from_str(s: &str) -> Result<Self, Error> {
27 let s = &s.replace("0x", "");
28 let mut sp = s.split('/');
29 let address = sp.nth(1).ok_or_else(|| Error::MemoryLayout(s.into()))?;
30 let mut address =
31 u32::from_str_radix(&address, 16).map_err(|_| Error::MemoryLayout(s.into()))?;
32 let mut pages = Vec::new();
33 for p in sp
34 .next()
35 .ok_or_else(|| Error::MemoryLayout(format!("Missing pages in {}", s)))?
36 .split(',')
37 {
38 let mut keyval = p.split('*');
39 let page_count: u32 = keyval
40 .next()
41 .ok_or_else(|| Error::MemoryLayout(p.into()))?
42 .parse()
43 .map_err(|_| Error::MemoryLayout(p.into()))?;
44 let valprefix = keyval.next().ok_or_else(|| Error::MemoryLayout(p.into()))?;
45 let size = valprefix.trim_matches(char::is_alphabetic);
46 let prefix = valprefix.trim_matches(char::is_numeric);
47 let mut size: u32 = size.parse().map_err(|_| Error::MemoryLayout(size.into()))?;
48 match &prefix[0..1] {
49 "K" => size *= 1024,
50 "M" => size *= 1024 * 1024,
51 _ => {
52 return Err(Error::MemoryLayout(format!("Invalid prefix {}", prefix)));
53 }
54 }
55 for _ in 0..page_count {
56 pages.push(Page { address, size });
57 address += size;
58 }
59 }
60 Ok(Self { pages })
61 }
62}
63
64impl fmt::Display for MemoryLayout {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 writeln!(f, "Show memory layout:")?;
67 writeln!(f)?;
68 for (i, p) in self.pages.iter().enumerate() {
69 writeln!(
70 f,
71 "{}: Start: 0x{:08X} Size: {} bytes",
72 i, p.address, p.size
73 )?;
74 }
75
76 write!(f, "")
77 }
78}
79
80impl MemoryLayout {
81 pub fn pages(&self) -> &Vec<Page> {
82 &self.pages
83 }
84
85 pub fn num_pages(&self, mut address: u32, length: u32) -> Result<usize, Error> {
87 let mut pages = 0;
88 let end = address + length;
89 while address < end {
90 let p = self.address(address)?;
91 address += p.size;
92 pages += 1;
93 }
94 Ok(pages)
95 }
96
97 pub fn address(&self, address: u32) -> Result<Page, Error> {
98 for p in &self.pages {
99 if address >= p.address && address < p.address + p.size {
100 return Ok(Page {
101 address: p.address,
102 size: p.size,
103 });
104 }
105 }
106 Err(Error::Address(address))
107 }
108}
109
110mod tests {
111 #[test]
112 fn test_memory_address() {
113 use super::MemoryLayout;
114 use std::str::FromStr;
115 let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K").unwrap();
119 assert_eq!(true, m.address(0x0800_0000).is_err());
120 let p = m.address(0x0801_0100).unwrap();
121 assert_eq!(0x0801_0000, p.address);
122 assert_eq!(0x4000, p.size);
123 let p = m.address(0x0801_4000).unwrap();
124 assert_eq!(0x0801_4000, p.address);
125 assert_eq!(0x4000, p.size);
126
127 let p = m.address(0x0801_8001).unwrap();
128 assert_eq!(0x0801_8000, p.address);
129 assert_eq!(0x10000, p.size);
130 assert_eq!(true, m.address(0x0802_7FFF).is_ok());
131
132 assert_eq!(true, m.address(0x0802_8000).is_err());
133 }
134 #[test]
135 fn test_memory_num_pages() {
136 use super::MemoryLayout;
137 use std::str::FromStr;
138 let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K").unwrap();
142 assert_eq!(true, m.num_pages(0x0800_0000, 0xFFFF).is_err());
143 let n = m.num_pages(0x0801_0000, 0xFFFF).unwrap();
144 assert_eq!(3, n);
145
146 let n = m.num_pages(0x0801_0000, 0x2000).unwrap();
147 assert_eq!(1, n);
148
149 let n = m.num_pages(0x0801_0000, 0x4000).unwrap();
150 assert_eq!(1, n);
151
152 let n = m.num_pages(0x0801_0000, 0x4001).unwrap();
153 assert_eq!(2, n);
154
155 let n = m.num_pages(0x0801_4000, 0x2000).unwrap();
156 assert_eq!(1, n);
157
158 let n = m.num_pages(0x0801_4000, 0x8000).unwrap();
159 assert_eq!(2, n);
160 }
161 #[test]
162 fn test_memory_from() {
163 use super::MemoryLayout;
164 use std::str::FromStr;
165 assert_eq!(true, MemoryLayout::from_str("/").is_err());
166 let m = MemoryLayout::from_str("/0x08008000");
167 assert_eq!(true, m.is_err());
168
169 let m = MemoryLayout::from_str("/0x08001000/02*16K");
170 assert_eq!(true, m.is_ok());
171 let m = m.unwrap();
172 let p = m.pages();
173 assert_eq!(2, p.len());
174 assert_eq!(16384, p.iter().nth(0).unwrap().size);
175 assert_eq!(16384, p.iter().nth(1).unwrap().size);
176
177 let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K");
178 assert_eq!(true, m.is_ok());
179 let m = m.unwrap();
180 let p = m.pages();
181 assert_eq!(3, p.len());
182 assert_eq!(16384, p.iter().nth(0).unwrap().size);
183 assert_eq!(16384, p.iter().nth(1).unwrap().size);
184 assert_eq!(65536, p.iter().nth(2).unwrap().size);
185 }
186}