diff --git a/svd2utra/src/generate.rs b/svd2utra/src/generate.rs index e87e4faf2..37f493341 100644 --- a/svd2utra/src/generate.rs +++ b/svd2utra/src/generate.rs @@ -5,8 +5,7 @@ use quick_xml::events::{attributes::Attribute, Event}; use quick_xml::reader::Reader; use quick_xml::name::QName; -use std::io::{BufRead, Write}; -use std::path::Path; +use std::io::{BufRead, BufReader, Read, Write}; #[derive(Debug)] pub enum ParseError { @@ -479,9 +478,20 @@ fn parse_memory_regions( loop { match reader.read_event_into(&mut buf) { Ok(Event::Start(ref e)) => match e.name() { - QName(b"memoryRegion") => description + QName(b"memoryRegion") => { + let mut mr = generate_memory_region(reader)?; + // keep adding _ to the end of the name until it's unique + loop { + if description.memory_regions.iter().find(|&m| m.name == mr.name).is_some() { + mr.name.push_str("_"); + continue; + } + break; + } + description .memory_regions - .push(generate_memory_region(reader)?), + .push(mr) + }, _ => panic!("unexpected tag in : {:?}", e), }, Ok(Event::End(ref e)) => match e.name() { @@ -525,6 +535,14 @@ fn generate_constants( _ => panic!("unexpected value in constant: {:?}", maybe_att), } } + // keep adding _ to the end of the name until it's unique + loop { + if description.constants.iter().find(|&c| c.name == constant_descriptor.name).is_some() { + constant_descriptor.name.push_str("_"); + continue; + } + break; + } description.constants.push(constant_descriptor) } _ => panic!("unexpected tag in : {:?}", e), @@ -1014,31 +1032,34 @@ mod tests { Ok(()) } -pub fn parse_svd>(src: P) -> Result { - let mut buf = Vec::new(); - let mut reader = Reader::from_file(src).expect("couldn't open SVD for reading"); +pub fn parse_svd(sources: Vec::) -> Result { let mut description = Description::default(); - loop { - match reader.read_event_into(&mut buf) { - Ok(Event::Start(ref e)) => match e.name() { - QName(b"peripherals") => { - description.peripherals = generate_peripherals(&mut reader)?; - } - QName(b"vendorExtensions") => { - parse_vendor_extensions(&mut reader, &mut description)?; - } + for src in sources { + let mut buf = Vec::new(); + let buf_reader = BufReader::new(src); + let mut reader = Reader::from_reader(buf_reader); + loop { + match reader.read_event_into(&mut buf) { + Ok(Event::Start(ref e)) => match e.name() { + QName(b"peripherals") => { + description.peripherals = generate_peripherals(&mut reader)?; + } + QName(b"vendorExtensions") => { + parse_vendor_extensions(&mut reader, &mut description)?; + } + _ => (), + }, + Ok(Event::Eof) => break, + Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e), _ => (), - }, - Ok(Event::Eof) => break, - Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e), - _ => (), + } + buf.clear(); } - buf.clear(); } Ok(description) } -pub fn generate, U: Write>(src: T, dest: &mut U) -> Result<(), ParseError> { +pub fn generate(src: Vec::, dest: &mut U) -> Result<(), ParseError> { let description = parse_svd(src)?; print_header(dest).or(Err(ParseError::WriteError))?; diff --git a/svd2utra/src/lib.rs b/svd2utra/src/lib.rs index 153db84a1..590be9840 100644 --- a/svd2utra/src/lib.rs +++ b/svd2utra/src/lib.rs @@ -13,6 +13,6 @@ mod tests { fn basic_generate() { DirBuilder::new().recursive(true).create("target").unwrap(); let mut dest = File::create("target/example.rs").unwrap(); - generate("examples/soc.svd", &mut dest).unwrap(); + generate(vec![std::fs::File::open("examples/soc.svd").unwrap()], &mut dest).unwrap(); } } diff --git a/svd2utra/src/main.rs b/svd2utra/src/main.rs index c32bcc0ec..5e40040bb 100644 --- a/svd2utra/src/main.rs +++ b/svd2utra/src/main.rs @@ -11,8 +11,9 @@ fn main() -> Result<(), Box> { let generated_filename = std::env::args().nth(2).ok_or("Must specify destination utralib filename")?; let mut dest_file = std::fs::File::create(generated_filename).expect("couldn't open dest file"); + let src_file = std::fs::File::open(svd_filename).expect("couldn't open source file"); - svd2utra::generate(svd_filename, &mut dest_file)?; + svd2utra::generate(vec![src_file], &mut dest_file)?; Ok(()) } diff --git a/tools/src/bin/create-image.rs b/tools/src/bin/create-image.rs index f127690bf..1c2bb2aa4 100644 --- a/tools/src/bin/create-image.rs +++ b/tools/src/bin/create-image.rs @@ -31,9 +31,12 @@ fn csr_to_config(hv: tools::utils::CsrConfig, ram_config: &mut RamConfig) { fn round_mem(src: u32) -> u32 { (src + 4095) & !4095 } - // Look for the largest "ram" block, which we'll treat as main memory + // Look for the largest memory block, which we'll treat as main memory for (k, v) in &hv.regions { - if k.find("ram").is_some() && v.length > ram_config.size { + if ( + k.find("sram").is_some() // uniquely finds region on Precursor and Cramium (excludes 'reram' correctly) + || k.find("ddr_ram").is_some() // finds region on atsama5d27 uniquely + ) && v.length > ram_config.size { ram_config.size = round_mem(v.length); ram_config.offset = v.start; found_ram_name = Some(k.clone()); @@ -41,12 +44,13 @@ fn csr_to_config(hv: tools::utils::CsrConfig, ram_config: &mut RamConfig) { } if found_ram_name.is_none() { - eprintln!("Error: Couldn't find a memory region named \"ram\" in config file"); + eprintln!("Error: Couldn't find a memory region named \"sram\" in config file"); return; } // Now that we know which block is ram, add the other regions. let found_ram_name = MemoryRegion::make_name(&found_ram_name.unwrap()); + let mut raw_regions = Vec::::new(); for (k, v) in &hv.regions { ram_config.memory_required += round_mem(v.length) / 4096; let region_name = MemoryRegion::make_name(k); @@ -59,11 +63,22 @@ fn csr_to_config(hv: tools::utils::CsrConfig, ram_config: &mut RamConfig) { if round_mem(v.length) == 0 { continue; } - ram_config - .regions - .add(MemoryRegion::new(v.start, round_mem(v.length), region_name)); + raw_regions.push(MemoryRegion::new(v.start, round_mem(v.length), region_name)); } + // condense adjacent regions & eliminate overlapping regions + raw_regions.sort_by(|a, b| a.start.partial_cmp(&b.start).unwrap() ); + let mut candidate_region = raw_regions[0]; + for r in raw_regions[1..].iter() { + if r.start > candidate_region.start + candidate_region.length { + ram_config.regions.add(candidate_region); + candidate_region = r.to_owned(); + } else { + candidate_region.length = (r.start + r.length) - candidate_region.start; + } + } + ram_config.regions.add(candidate_region); } + fn main() { env_logger::init(); let matches = App::new("Xous Image Creator") @@ -113,10 +128,19 @@ fn main() { .short("s") .long("svd") .value_name("SOC_SVD") - .help("soc.csv file from litex") + .help("soc.svd file from litex (system-level)") .takes_value(true) .required_unless_one(&["ram", "svd", "csv"]), ) + .arg( + Arg::with_name("extra-svd") + .long("extra-svd") + .value_name("EXTRA_SVD") + .help("extra SVD files") + .takes_value(true) + .multiple(true) + .number_of_values(1) + ) .arg( Arg::with_name("ram") .short("r") @@ -184,7 +208,8 @@ fn main() { if let Some(soc_svd) = matches.value_of("svd") { let soc_svd_file = std::path::Path::new(soc_svd); - let desc = svd2utra::parse_svd(soc_svd_file).unwrap(); + let svd_file = std::fs::File::open(soc_svd_file).unwrap(); + let desc = svd2utra::parse_svd(vec![svd_file]).unwrap(); let mut map = std::collections::BTreeMap::new(); let mut csr_top = 0; @@ -224,6 +249,42 @@ fn main() { ); } } + // insert additional regions from core.svd, if specified + if matches.is_present("extra-svd") { + let files: Vec<_> = matches.values_of("extra-svd").unwrap().collect(); + for soc_svd in files { + let soc_svd_file = std::path::Path::new(soc_svd); + let svd_file = std::fs::File::open(soc_svd_file).unwrap(); + let desc = svd2utra::parse_svd(vec![svd_file]).unwrap(); + + let mut csr_top = 0; + for peripheral in desc.peripherals { + if peripheral.base > csr_top { + csr_top = peripheral.base; + } + } + for mut region in desc.memory_regions { + loop { + if map.contains_key(®ion.name.to_lowercase()) { + let mut new_name = region.name.to_lowercase(); + new_name.push_str("_"); + region.name = new_name; + continue; + } + break; + } + println!("{}: {:x}", region.name, region.base); + map.insert( + region.name.to_lowercase(), + tools::utils::CsrMemoryRegion { + start: region.base.try_into().unwrap(), + length: region.size.try_into().unwrap(), + }, + ); + } + } + } + csr_to_config(tools::utils::CsrConfig { regions: map }, &mut ram_config); } diff --git a/tools/src/tags/memory.rs b/tools/src/tags/memory.rs index 2d8d531a1..18d0e96e0 100644 --- a/tools/src/tags/memory.rs +++ b/tools/src/tags/memory.rs @@ -11,16 +11,16 @@ macro_rules! make_type { }}; } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone, Copy)] pub struct MemoryRegion { /// Starting offset (in bytes) - start: u32, + pub start: u32, /// Length (in bytes) - length: u32, + pub length: u32, /// Region name (as a type) - name: XousArgumentCode, + pub name: XousArgumentCode, /// Unused _padding: u32, diff --git a/utralib/Cargo.lock b/utralib/Cargo.lock index eadecc703..3ce078c68 100644 --- a/utralib/Cargo.lock +++ b/utralib/Cargo.lock @@ -19,14 +19,16 @@ dependencies = [ [[package]] name = "svd2utra" -version = "0.1.17" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba87b81de81a553ec5904993a676aa29d1583a4f6ab96e03f8b44e4d6c05a61" dependencies = [ "quick-xml", ] [[package]] name = "utralib" -version = "0.1.19" +version = "0.1.20" dependencies = [ "svd2utra", ] diff --git a/utralib/build.rs b/utralib/build.rs index a22661260..172e88407 100644 --- a/utralib/build.rs +++ b/utralib/build.rs @@ -96,27 +96,27 @@ fn main() { // ----- select an SVD file based on a specific revision ----- #[cfg(feature = "precursor-perflib")] - let svd_filename = "precursor/soc-perf.svd"; + let svd_filenames = vec!["precursor/soc-perf.svd"]; #[cfg(feature = "precursor-perflib")] let generated_filename = "src/generated/precursor_perf.rs"; #[cfg(feature = "renode")] - let svd_filename = "renode/renode.svd"; + let svd_filenames = vec!["renode/renode.svd"]; #[cfg(feature = "renode")] let generated_filename = "src/generated/renode.rs"; #[cfg(feature = "precursor-dvt")] - let svd_filename = "precursor/soc-dvt.svd"; + let svd_filenames = vec!["precursor/soc-dvt.svd"]; #[cfg(feature = "precursor-dvt")] let generated_filename = "src/generated/precursor_dvt.rs"; #[cfg(feature = "precursor-pvt")] - let svd_filename = "precursor/soc-pvt.svd"; + let svd_filenames = vec!["precursor/soc-pvt.svd"]; #[cfg(feature = "precursor")] let generated_filename = "src/generated/precursor_pvt.rs"; #[cfg(feature = "atsama5d27")] - let svd_filename = "atsama5d/ATSAMA5D27.svd"; + let svd_filenames = vec!["atsama5d/ATSAMA5D27.svd"]; #[cfg(feature = "atsama5d27")] let generated_filename = "src/generated/atsama5d27.rs"; @@ -128,15 +128,18 @@ fn main() { // $env:CARGO_LOG="cargo::core::compiler::fingerprint=info" #[cfg(not(feature = "hosted"))] { - let svd_file_path = std::path::Path::new(&svd_filename); - println!( - "cargo:rerun-if-changed={}", - svd_file_path.canonicalize().unwrap().display() - ); - + let mut svd_files = Vec::new(); + for svd in svd_filenames.iter() { + let svd_file_path = std::path::Path::new(&svd); + println!( + "cargo:rerun-if-changed={}", + svd_file_path.canonicalize().unwrap().display() + ); + svd_files.push(std::fs::File::open(svd_file_path).unwrap()); + } // Regenerate the utra file in RAM. let mut dest_vec = vec![]; - svd2utra::generate(svd_file_path, &mut dest_vec).unwrap(); + svd2utra::generate(svd_files, &mut dest_vec).unwrap(); // If the file exists, check to see if it is different from what we just generated. // If not, skip writing the new file. @@ -171,7 +174,9 @@ fn main() { .truncate(true) .open(svd_path) .unwrap(); - write!(svd_file, "utralib/{}", svd_filename).unwrap(); + for svd in svd_filenames.iter() { + writeln!(svd_file, "utralib/{}", svd).unwrap(); + } } #[cfg(feature = "hosted")] { diff --git a/xtask/src/builder.rs b/xtask/src/builder.rs index 7a98bd0d2..76c39a5f1 100644 --- a/xtask/src/builder.rs +++ b/xtask/src/builder.rs @@ -5,7 +5,7 @@ use std::{ path::{Path, PathBuf}, process::Command, }; -use crate::{DynError, app_manifest::generate_app_menus, MemorySpec}; +use crate::{DynError, app_manifest::generate_app_menus}; #[allow(dead_code)] #[derive(Copy, Clone, Debug)] @@ -674,8 +674,12 @@ impl Builder { let mut svd_spec_file = OpenOptions::new() .read(true) .open(&svd_spec_path)?; - let mut svd_path = String::new(); - svd_spec_file.read_to_string(&mut svd_path)?; + let mut svd_path_str = String::new(); + svd_spec_file.read_to_string(&mut svd_path_str)?; + let mut svd_paths = Vec::new(); + for line in svd_path_str.lines() { + svd_paths.push(line.to_owned()); + } // ---------- install any pre-built packages ---------- services_path.append(&mut self.fetch_prebuilds()?); @@ -687,7 +691,7 @@ impl Builder { &kernel_path[0], &inie, &inif, - MemorySpec::SvdFile(svd_path) + svd_paths, )?; println!(); println!( @@ -780,7 +784,7 @@ impl Builder { kernel: &String, init: &[String], inif: &[String], - memory_spec: MemorySpec, + memory_spec: Vec::, ) -> Result { let stream = self.stream.to_str(); let mut args = vec!["run", "--package", "tools", "--bin", "create-image", "--"]; @@ -805,10 +809,15 @@ impl Builder { args.push(i); } - match memory_spec { - MemorySpec::SvdFile(ref s) => { - args.push("--svd"); - args.push(s); + if memory_spec.len() == 1 { + args.push("--svd"); + args.push(&memory_spec[0]) + } else { + args.push("--svd"); + args.push(&memory_spec[0]); + for spec in memory_spec[1..].iter() { + args.push("--extra-svd"); + args.push(&spec); } } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index c5dece11c..2071304c0 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -486,10 +486,6 @@ Note: By default, the `ticktimer` will get rebuilt every time. You can skip this type DynError = Box; -enum MemorySpec { - SvdFile(String), -} - /// [cratespecs] are positional arguments, and is a list of 0 to N tokens that immediately /// follow [verb] fn get_cratespecs() -> Vec {