1use std::collections::BTreeMap;
2use std::fs::File;
3use std::io;
4
5pub struct CsrMemoryRegion {
6 pub start: u32,
7 pub length: u32,
8}
9
10pub struct CsrConfig {
11 pub regions: BTreeMap<String, CsrMemoryRegion>,
12}
13
14const PAGE_SIZE: u32 = 4096;
15
16#[derive(Debug)]
17pub enum ConfigError {
18 NumberParseError(String, std::num::ParseIntError),
20
21 IoError(io::Error),
23}
24
25impl std::convert::From<io::Error> for ConfigError {
26 fn from(e: io::Error) -> ConfigError { ConfigError::IoError(e) }
27}
28
29pub fn get_base(value: &str) -> (&str, u32) {
30 if value.starts_with("0x") {
31 (value.trim_start_matches("0x"), 16)
32 } else if value.starts_with("0X") {
33 (value.trim_start_matches("0X"), 16)
34 } else if value.starts_with("0b") {
35 (value.trim_start_matches("0b"), 2)
36 } else if value.starts_with("0B") {
37 (value.trim_start_matches("0B"), 2)
38 } else if value.starts_with('0') && value != "0" {
39 (value.trim_start_matches('0'), 8)
40 } else {
41 (value, 10)
42 }
43}
44
45pub fn parse_u32(value: &str) -> Result<u32, ConfigError> {
46 let (value, base) = get_base(value);
47 u32::from_str_radix(value, base).map_err(|e| ConfigError::NumberParseError(value.to_owned(), e))
48}
49
50pub fn parse_csr_csv(filename: &str) -> Result<CsrConfig, ConfigError> {
51 let mut map = BTreeMap::new();
52 let file = File::open(filename)?;
53
54 let mut csr_base = 0;
55 let mut csr_top = 0;
56
57 let mut rdr = csv::ReaderBuilder::new().flexible(true).from_reader(file);
58 for result in rdr.records() {
59 if let Ok(r) = result {
60 if r.is_empty() {
61 eprintln!("csv: ignoring blank line");
62 continue;
63 }
64 match &r[0] {
65 "csr_base" => {
66 if r.len() < 3 {
67 eprintln!("csv: found csr_base entry, but entry was short");
68 continue;
69 }
70 let base_addr = parse_u32(&r[2])?;
71 if base_addr > csr_top {
72 csr_top = base_addr;
74 }
75 }
76 "memory_region" => {
77 if r.len() < 4 {
78 eprintln!("csv: found memory_region entry, but entry was short");
79 continue;
80 }
81 let region_name = &r[1];
82 let base_addr = parse_u32(&r[2])?;
83 let length = parse_u32(&r[3])?;
84
85 if region_name == "csr" {
86 csr_base = base_addr;
87 } else {
88 map.insert(
89 region_name.to_string().to_lowercase(),
90 CsrMemoryRegion { start: base_addr, length },
91 );
92 }
93 }
94 _ => (),
95 };
96 }
97 }
98
99 if csr_base != 0 && csr_top != 0 {
100 csr_top += 1;
101 csr_top = (csr_top + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
102 map.insert("csr".to_string(), CsrMemoryRegion { start: csr_base, length: csr_top - csr_base });
103 }
104 Ok(CsrConfig { regions: map })
105}