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 <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-10-05 11:37:44 +08:00
parent e9d9315418
commit 96df91f53b
2 changed files with 111 additions and 49 deletions

View file

@ -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"

View file

@ -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);
}