From 96df91f53b289a64b3a34fde4e250cf99bc25b58 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 5 Oct 2020 11:37:44 +0800 Subject: [PATCH] create-image: support generating an image from an svd Now that we can parse svd files, support creating an image using an svd instead of a csv file. Signed-off-by: Sean Cross --- tools/Cargo.toml | 1 + tools/src/bin/create-image.rs | 159 +++++++++++++++++++++++----------- 2 files changed, 111 insertions(+), 49 deletions(-) diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 77c9c2f74..83cc36215 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -15,6 +15,7 @@ csv = "1.1" env_logger = "0.7" log = "0" xmas-elf = "0.7.0" +svd2utra = { path = "../svd2utra" } [[bin]] name = "copy-object" diff --git a/tools/src/bin/create-image.rs b/tools/src/bin/create-image.rs index 9e5e6b29c..04af87ad6 100644 --- a/tools/src/bin/create-image.rs +++ b/tools/src/bin/create-image.rs @@ -3,6 +3,7 @@ extern crate clap; extern crate crc; +use std::convert::TryInto; use std::fs::File; use tools::elf::{read_minielf, read_program}; @@ -15,6 +16,52 @@ use tools::xous_arguments::XousArguments; use clap::{App, Arg}; +struct RamConfig { + offset: u32, + size: u32, + name: u32, + regions: MemoryRegions, + memory_required: u32, +} + +fn csr_to_config(hv: tools::utils::CsrConfig, ram_config: &mut RamConfig) { + let mut found_ram_name = None; + fn round_mem(src: u32) -> u32 { + (src + 4095) & !4095 + } + // Look for the largest "ram" 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 { + ram_config.size = round_mem(v.length); + ram_config.offset = v.start; + found_ram_name = Some(k.clone()); + } + } + + if found_ram_name.is_none() { + eprintln!("Error: Couldn't find a memory region named \"ram\" 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()); + for (k, v) in &hv.regions { + ram_config.memory_required += round_mem(v.length) / 4096; + let region_name = MemoryRegion::make_name(k); + // Don't add the RAM section to the extra regions block. + if region_name == found_ram_name { + ram_config.name = region_name; + continue; + } + // Don't add empty sections. + if round_mem(v.length) == 0 { + continue; + } + ram_config + .regions + .add(MemoryRegion::new(v.start, round_mem(v.length), region_name)); + } +} fn main() { env_logger::init(); let matches = App::new("Xous Image Creator") @@ -48,7 +95,16 @@ fn main() { .value_name("CSR_CSV") .help("csr.csv file from litex") .takes_value(true) - .required_unless("ram"), + .required_unless_one(&["ram", "svd", "csv"]), + ) + .arg( + Arg::with_name("svd") + .short("s") + .long("svd") + .value_name("SOC_SVD") + .help("soc.csv file from litex") + .takes_value(true) + .required_unless_one(&["ram", "svd", "csv"]), ) .arg( Arg::with_name("ram") @@ -56,8 +112,8 @@ fn main() { .long("ram") .takes_value(true) .value_name("OFFSET:SIZE") - .required_unless("csv") - .help("RAM offset and size, in the form of [offset]:[size]"), + .help("RAM offset and size, in the form of [offset]:[size]") + .required_unless_one(&["ram", "svd", "csv"]), ) .arg( Arg::with_name("debug") @@ -74,11 +130,13 @@ fn main() { ) .get_matches(); - let mut ram_offset = Default::default(); - let mut ram_size = Default::default(); - let mut ram_name = MemoryRegion::make_name("sram"); - let mut regions = MemoryRegions::new(); - let mut memory_required = 0; + let mut ram_config = RamConfig { + offset: Default::default(), + size: Default::default(), + name: MemoryRegion::make_name("sram"), + regions: MemoryRegions::new(), + memory_required: 0, + }; if let Some(val) = matches.value_of("ram") { let ram_parts: Vec<&str> = val.split(':').collect(); @@ -87,7 +145,7 @@ fn main() { return; } - ram_offset = match parse_u32(ram_parts[0]) { + ram_config.offset = match parse_u32(ram_parts[0]) { Ok(o) => o, Err(e) => { eprintln!("Error: Unable to parse {}: {:?}", ram_parts[0], e); @@ -95,7 +153,7 @@ fn main() { } }; - ram_size = match parse_u32(ram_parts[1]) { + ram_config.size = match parse_u32(ram_parts[1]) { Ok(o) => o, Err(e) => { eprintln!("Error: Unable to parse {}: {:?}", ram_parts[1], e); @@ -103,51 +161,54 @@ fn main() { } }; - memory_required += ram_size / 4096; + ram_config.memory_required += ram_config.size / 4096; } if let Some(csr_csv) = matches.value_of("csv") { let hv = parse_csr_csv(csr_csv).expect("couldn't find csr.csv file"); - let mut found_ram_name = None; - fn round_mem(src: u32) -> u32 { - (src + 4095) & !4095 - } - // Look for the largest "ram" block, which we'll treat as main memory - for (k, v) in &hv.regions { - if k.find("ram").is_some() && v.length > ram_size { - ram_size = round_mem(v.length); - ram_offset = v.start; - found_ram_name = Some(k.clone()); - } - } - - if found_ram_name.is_none() { - eprintln!("Error: Couldn't find a memory region named \"ram\" in csv 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()); - for (k, v) in &hv.regions { - memory_required += round_mem(v.length) / 4096; - let region_name = MemoryRegion::make_name(k); - // Don't add the RAM section to the extra regions block. - if region_name == found_ram_name { - ram_name = region_name; - continue; - } - // Don't add empty sections. - if round_mem(v.length) == 0 { - continue; - } - regions.add(MemoryRegion::new(v.start, round_mem(v.length), region_name)); - } + csr_to_config(hv, &mut ram_config); } - let mut args = XousArguments::new(ram_offset, ram_size, ram_name); + if let Some(soc_svd) = matches.value_of("svd") { + let soc_svd_file = std::fs::File::open(soc_svd).unwrap(); + let desc = svd2utra::parse_svd(soc_svd_file).unwrap(); + let mut map = std::collections::BTreeMap::new(); - if !regions.is_empty() { - args.add(regions); + let mut csr_top = 0; + for peripheral in desc.peripherals { + if peripheral.base > csr_top { + csr_top = peripheral.base; + } + } + for region in desc.memory_regions { + // Ignore the "CSR" region and manually reconstruct it, because this + // region is largely empty and we want to avoid allocating too much space. + if region.name == "CSR" { + const PAGE_SIZE: usize = 4096; + map.insert( + region.name.to_lowercase(), + tools::utils::CsrMemoryRegion { + start: region.base.try_into().unwrap(), + length: (((csr_top - region.base) + PAGE_SIZE) & !(PAGE_SIZE - 1)).try_into().unwrap(), + }, + ); + } else { + 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); + } + + let mut args = XousArguments::new(ram_config.offset, ram_config.size, ram_config.name); + + if !ram_config.regions.is_empty() { + args.add(ram_config.regions); } if matches.is_present("debug") { @@ -194,7 +255,7 @@ fn main() { println!( "Runtime will require {} bytes to track memory allocations", - memory_required + ram_config.memory_required ); println!("Image created in file {}", output_filename); }