initial commit
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
commit
13966f9b02
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "utra"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Sean Cross <sean@xobs.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quick-xml = "0.19"
|
4742
examples/soc.svd
Normal file
4742
examples/soc.svd
Normal file
File diff suppressed because it is too large
Load Diff
635
src/generate.rs
Normal file
635
src/generate.rs
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
use quick_xml::events::Event;
|
||||||
|
use quick_xml::Reader;
|
||||||
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseError {
|
||||||
|
UnexpectedTag,
|
||||||
|
MissingValue,
|
||||||
|
ParseIntError,
|
||||||
|
NonUTF8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Field {
|
||||||
|
name: String,
|
||||||
|
lsb: usize,
|
||||||
|
msb: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Register {
|
||||||
|
name: String,
|
||||||
|
offset: usize,
|
||||||
|
description: Option<String>,
|
||||||
|
fields: Vec<Field>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Peripheral {
|
||||||
|
name: String,
|
||||||
|
base: usize,
|
||||||
|
size: usize,
|
||||||
|
interrupt: Option<usize>,
|
||||||
|
registers: Vec<Register>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct MemoryRegion {
|
||||||
|
name: String,
|
||||||
|
base: usize,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Description {
|
||||||
|
peripherals: Vec<Peripheral>,
|
||||||
|
memory_regions: Vec<MemoryRegion>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_base(value: &str) -> (&str, u32) {
|
||||||
|
if value.starts_with("0x") {
|
||||||
|
(value.trim_start_matches("0x"), 16)
|
||||||
|
} else if value.starts_with("0X") {
|
||||||
|
(value.trim_start_matches("0X"), 16)
|
||||||
|
} else if value.starts_with("0b") {
|
||||||
|
(value.trim_start_matches("0b"), 2)
|
||||||
|
} else if value.starts_with("0B") {
|
||||||
|
(value.trim_start_matches("0B"), 2)
|
||||||
|
} else if value.starts_with('0') && value != "0" {
|
||||||
|
(value.trim_start_matches('0'), 8)
|
||||||
|
} else {
|
||||||
|
(value, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_usize(value: &[u8]) -> Result<usize, ParseError> {
|
||||||
|
let value_as_str = String::from_utf8(value.to_vec()).or(Err(ParseError::NonUTF8))?;
|
||||||
|
let (value, base) = get_base(&value_as_str);
|
||||||
|
usize::from_str_radix(value, base).or(Err(ParseError::ParseIntError))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_contents<T: BufRead>(reader: &mut Reader<T>) -> Result<String, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let contents = reader
|
||||||
|
.read_event(&mut buf)
|
||||||
|
.map_err(|_| ParseError::UnexpectedTag)?;
|
||||||
|
match contents {
|
||||||
|
Event::Text(t) => t
|
||||||
|
.unescape_and_decode(reader)
|
||||||
|
.map_err(|_| ParseError::NonUTF8),
|
||||||
|
_ => Err(ParseError::UnexpectedTag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_field<T: BufRead>(reader: &mut Reader<T>) -> Result<Field, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut name = None;
|
||||||
|
let mut lsb = None;
|
||||||
|
let mut msb = None;
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => {
|
||||||
|
let tag_name = e
|
||||||
|
.unescape_and_decode(reader)
|
||||||
|
.map_err(|_| ParseError::NonUTF8)?;
|
||||||
|
match tag_name.as_str() {
|
||||||
|
"name" => name = Some(extract_contents(reader)?),
|
||||||
|
"lsb" => lsb = Some(parse_usize(extract_contents(reader)?.as_bytes())?),
|
||||||
|
"msb" => msb = Some(parse_usize(extract_contents(reader)?.as_bytes())?),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Event::End(ref e)) => {
|
||||||
|
if let b"field" = e.name() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => panic!("error parsing: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Field {
|
||||||
|
name: name.ok_or(ParseError::MissingValue)?,
|
||||||
|
lsb: lsb.ok_or(ParseError::MissingValue)?,
|
||||||
|
msb: msb.ok_or(ParseError::MissingValue)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fields<T: BufRead>(
|
||||||
|
reader: &mut Reader<T>,
|
||||||
|
fields: &mut Vec<Field>,
|
||||||
|
) -> Result<(), ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"field" => fields.push(generate_field(reader)?),
|
||||||
|
_ => panic!("unexpected tag in <field>: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::End(ref e)) => match e.name() {
|
||||||
|
b"fields" => {
|
||||||
|
// println!("End fields");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::Text(_)) => (),
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_register<T: BufRead>(reader: &mut Reader<T>) -> Result<Register, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut name = None;
|
||||||
|
let mut offset = None;
|
||||||
|
let description = None;
|
||||||
|
let mut fields = vec![];
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => {
|
||||||
|
let tag_name = e
|
||||||
|
.unescape_and_decode(reader)
|
||||||
|
.map_err(|_| ParseError::NonUTF8)?;
|
||||||
|
match tag_name.as_str() {
|
||||||
|
"name" => name = Some(extract_contents(reader)?),
|
||||||
|
"addressOffset" => {
|
||||||
|
offset = Some(parse_usize(extract_contents(reader)?.as_bytes())?)
|
||||||
|
}
|
||||||
|
"fields" => generate_fields(reader, &mut fields)?,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Event::End(ref e)) => {
|
||||||
|
if let b"register" = e.name() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => panic!("error parsing: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Register {
|
||||||
|
name: name.ok_or(ParseError::MissingValue)?,
|
||||||
|
offset: offset.ok_or(ParseError::MissingValue)?,
|
||||||
|
description,
|
||||||
|
fields,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_registers<T: BufRead>(
|
||||||
|
reader: &mut Reader<T>,
|
||||||
|
registers: &mut Vec<Register>,
|
||||||
|
) -> Result<(), ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"register" => registers.push(generate_register(reader)?),
|
||||||
|
_ => panic!("unexpected tag in <registers>: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::End(ref e)) => match e.name() {
|
||||||
|
b"registers" => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::Text(_)) => (),
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_peripheral<T: BufRead>(reader: &mut Reader<T>) -> Result<Peripheral, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut name = None;
|
||||||
|
let mut base = None;
|
||||||
|
let mut size = None;
|
||||||
|
let mut registers = vec![];
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => {
|
||||||
|
let tag_name = e
|
||||||
|
.unescape_and_decode(reader)
|
||||||
|
.map_err(|_| ParseError::NonUTF8)?;
|
||||||
|
match tag_name.as_str() {
|
||||||
|
"name" => name = Some(extract_contents(reader)?),
|
||||||
|
"baseAddress" => {
|
||||||
|
base = Some(parse_usize(extract_contents(reader)?.as_bytes())?)
|
||||||
|
}
|
||||||
|
"size" => size = Some(parse_usize(extract_contents(reader)?.as_bytes())?),
|
||||||
|
"registers" => generate_registers(reader, &mut registers)?,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Event::End(ref e)) => {
|
||||||
|
if let b"peripheral" = e.name() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => panic!("error parsing: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Peripheral {
|
||||||
|
name: name.ok_or(ParseError::MissingValue)?,
|
||||||
|
base: base.ok_or(ParseError::MissingValue)?,
|
||||||
|
size: size.ok_or(ParseError::MissingValue)?,
|
||||||
|
interrupt: None,
|
||||||
|
registers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_peripherals<T: BufRead>(reader: &mut Reader<T>) -> Result<Vec<Peripheral>, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut peripherals = vec![];
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"peripheral" => peripherals.push(generate_peripheral(reader)?),
|
||||||
|
_ => panic!("unexpected tag in <peripherals>: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::End(ref e)) => match e.name() {
|
||||||
|
b"peripherals" => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::Text(_)) => (),
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(peripherals)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_memory_region<T: BufRead>(reader: &mut Reader<T>) -> Result<MemoryRegion, ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut name = None;
|
||||||
|
let mut base = None;
|
||||||
|
let mut size = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => {
|
||||||
|
let tag_name = e
|
||||||
|
.unescape_and_decode(reader)
|
||||||
|
.map_err(|_| ParseError::NonUTF8)?;
|
||||||
|
match tag_name.as_str() {
|
||||||
|
"name" => name = Some(extract_contents(reader)?),
|
||||||
|
"baseAddress" => {
|
||||||
|
base = Some(parse_usize(extract_contents(reader)?.as_bytes())?)
|
||||||
|
}
|
||||||
|
"size" => size = Some(parse_usize(extract_contents(reader)?.as_bytes())?),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Event::End(ref e)) => {
|
||||||
|
if let b"memoryRegion" = e.name() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => panic!("error parsing: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(MemoryRegion {
|
||||||
|
name: name.ok_or(ParseError::MissingValue)?,
|
||||||
|
base: base.ok_or(ParseError::MissingValue)?,
|
||||||
|
size: size.ok_or(ParseError::MissingValue)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_memory_regions<T: BufRead>(
|
||||||
|
reader: &mut Reader<T>,
|
||||||
|
description: &mut Description,
|
||||||
|
) -> Result<(), ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"memoryRegion" => description
|
||||||
|
.memory_regions
|
||||||
|
.push(generate_memory_region(reader)?),
|
||||||
|
_ => panic!("unexpected tag in <memoryRegions>: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::End(ref e)) => match e.name() {
|
||||||
|
b"memoryRegions" => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::Text(_)) => (),
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_vendor_extensions<T: BufRead>(
|
||||||
|
reader: &mut Reader<T>,
|
||||||
|
description: &mut Description,
|
||||||
|
) -> Result<(), ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"memoryRegions" => parse_memory_regions(reader, description)?,
|
||||||
|
_ => panic!("unexpected tag in <vendorExtensions>: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::End(ref e)) => match e.name() {
|
||||||
|
b"vendorExtensions" => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
},
|
||||||
|
Ok(Event::Text(_)) => (),
|
||||||
|
e => panic!("unhandled value: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_header<U: Write>(out: &mut U) -> std::io::Result<()> {
|
||||||
|
let s = r####"
|
||||||
|
#![cfg_attr(target_os = "none", no_std)]
|
||||||
|
use core::convert::TryInto;
|
||||||
|
pub struct Register {
|
||||||
|
/// Offset of this register within this CSR
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
impl Register {
|
||||||
|
pub const fn new(offset: usize) -> Register {
|
||||||
|
Register { offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct Field {
|
||||||
|
/// A bitmask we use to AND to the value, unshifted.
|
||||||
|
/// E.g. for a width of `3` bits, this mask would be 0b111.
|
||||||
|
mask: usize,
|
||||||
|
/// Offset of the first bit in this field
|
||||||
|
offset: usize,
|
||||||
|
/// A copy of the register address that this field
|
||||||
|
/// is a member of. Ideally this is optimized out by the
|
||||||
|
/// compiler.
|
||||||
|
register: Register,
|
||||||
|
}
|
||||||
|
impl Field {
|
||||||
|
/// Define a new CSR field with the given width at a specified
|
||||||
|
/// offset from the start of the register.
|
||||||
|
pub const fn new(width: usize, offset: usize, register: Register) -> Field {
|
||||||
|
// Asserts don't work in const fn yet.
|
||||||
|
// assert!(width != 0, "field width cannot be 0");
|
||||||
|
// assert!((width + offset) < 32, "field with and offset must fit within a 32-bit value");
|
||||||
|
// It would be lovely if we could call `usize::pow()` in a const fn.
|
||||||
|
let mask = match width {
|
||||||
|
0 => 0,
|
||||||
|
1 => 1,
|
||||||
|
2 => 3,
|
||||||
|
3 => 7,
|
||||||
|
4 => 15,
|
||||||
|
5 => 31,
|
||||||
|
6 => 63,
|
||||||
|
7 => 127,
|
||||||
|
8 => 255,
|
||||||
|
9 => 511,
|
||||||
|
10 => 1023,
|
||||||
|
11 => 2047,
|
||||||
|
12 => 4095,
|
||||||
|
13 => 8191,
|
||||||
|
14 => 16383,
|
||||||
|
15 => 32767,
|
||||||
|
16 => 65535,
|
||||||
|
17 => 131071,
|
||||||
|
18 => 262143,
|
||||||
|
19 => 524287,
|
||||||
|
20 => 1048575,
|
||||||
|
21 => 2097151,
|
||||||
|
22 => 4194303,
|
||||||
|
23 => 8388607,
|
||||||
|
24 => 16777215,
|
||||||
|
25 => 33554431,
|
||||||
|
26 => 67108863,
|
||||||
|
27 => 134217727,
|
||||||
|
28 => 268435455,
|
||||||
|
29 => 536870911,
|
||||||
|
30 => 1073741823,
|
||||||
|
31 => 2147483647,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
Field {
|
||||||
|
mask,
|
||||||
|
offset,
|
||||||
|
register,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct CSR<T> {
|
||||||
|
base: *mut T,
|
||||||
|
}
|
||||||
|
impl<T> CSR<T>
|
||||||
|
where
|
||||||
|
T: core::convert::TryFrom<usize> + core::convert::TryInto<usize> + core::default::Default,
|
||||||
|
{
|
||||||
|
pub fn new(base: *mut T) -> Self {
|
||||||
|
CSR { base }
|
||||||
|
}
|
||||||
|
/// Read the contents of this register
|
||||||
|
pub fn r(&mut self, reg: Register) -> T {
|
||||||
|
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||||
|
unsafe { usize_base.add(reg.offset).read_volatile() }
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// Read a field from this CSR
|
||||||
|
pub fn rf(&mut self, field: Field) -> T {
|
||||||
|
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||||
|
((unsafe { usize_base.add(field.register.offset).read_volatile() } >> field.offset)
|
||||||
|
& field.mask)
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// Read-modify-write a given field in this CSR
|
||||||
|
pub fn rmwf(&mut self, field: Field, value: T) {
|
||||||
|
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||||
|
let value_as_usize: usize = value.try_into().unwrap_or_default() << field.offset;
|
||||||
|
let previous =
|
||||||
|
unsafe { usize_base.add(field.register.offset).read_volatile() } & !field.mask;
|
||||||
|
unsafe {
|
||||||
|
usize_base
|
||||||
|
.add(field.register.offset)
|
||||||
|
.write_volatile(previous | value_as_usize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// Write a given field without reading it first
|
||||||
|
pub fn wfo(&mut self, field: Field, value: T) {
|
||||||
|
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||||
|
let value_as_usize: usize = (value.try_into().unwrap_or_default() & field.mask) << field.offset;
|
||||||
|
unsafe {
|
||||||
|
usize_base
|
||||||
|
.add(field.register.offset)
|
||||||
|
.write_volatile(value_as_usize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// Write the entire contents of a register without reading it first
|
||||||
|
pub fn wo(&mut self, reg: Register, value: T) {
|
||||||
|
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||||
|
let value_as_usize: usize = value.try_into().unwrap_or_default();
|
||||||
|
unsafe { usize_base.add(reg.offset).write_volatile(value_as_usize) };
|
||||||
|
}
|
||||||
|
/// Zero a field from a provided value
|
||||||
|
pub fn zf(&mut self, field: Field, value: T) -> T {
|
||||||
|
let value_as_usize: usize = value.try_into().unwrap_or_default();
|
||||||
|
(value_as_usize & !(field.mask << field.offset))
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// Shift & mask a value to its final field position
|
||||||
|
pub fn ms(&mut self, field: Field, value: T) -> T {
|
||||||
|
let value_as_usize: usize = value.try_into().unwrap_or_default();
|
||||||
|
((value_as_usize & field.mask) << field.offset)
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"####;
|
||||||
|
out.write_all(s.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_memory_regions<U: Write>(regions: &[MemoryRegion], out: &mut U) -> std::io::Result<()> {
|
||||||
|
writeln!(out, "// Physical base addresses of memory regions")?;
|
||||||
|
for region in regions {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"pub const HW_{}_MEM: u32 = 0x{:08x};",
|
||||||
|
region.name, region.base
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"pub const HW_{}_MEM_LEN: u32 = {};",
|
||||||
|
region.name, region.size
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(out)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_peripherals<U: Write>(peripherals: &[Peripheral], out: &mut U) -> std::io::Result<()> {
|
||||||
|
writeln!(out, "// Physical base addresses of registers")?;
|
||||||
|
for peripheral in peripherals {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"pub const HW_{}_BASE : u32 = {};",
|
||||||
|
peripheral.name, peripheral.base
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(out)?;
|
||||||
|
|
||||||
|
writeln!(out, "pub mod utra {{")?;
|
||||||
|
for peripheral in peripherals {
|
||||||
|
writeln!(out)?;
|
||||||
|
writeln!(out, " pub mod {} {{", peripheral.name.to_lowercase())?;
|
||||||
|
for register in &peripheral.registers {
|
||||||
|
writeln!(out)?;
|
||||||
|
if let Some(description) = ®ister.description {
|
||||||
|
writeln!(out, " /// {}", description)?;
|
||||||
|
}
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
" pub const {}: crate::Register = crate::Register::new({});",
|
||||||
|
register.name, register.offset
|
||||||
|
)?;
|
||||||
|
for field in ®ister.fields {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
" pub const {}_{}: crate::Field = crate::Field::new({}, {}, {});",
|
||||||
|
register.name,
|
||||||
|
field.name.to_uppercase(),
|
||||||
|
field.msb + 1 - field.lsb,
|
||||||
|
field.lsb,
|
||||||
|
register.name
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(out, " }}")?;
|
||||||
|
}
|
||||||
|
writeln!(out, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_tests<U: Write>(peripherals: &[Peripheral], out: &mut U) -> std::io::Result<()> {
|
||||||
|
let test_header = r####"
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn compile_check() {
|
||||||
|
use super::*;
|
||||||
|
"####.as_bytes();
|
||||||
|
out.write_all(test_header)?;
|
||||||
|
for peripheral in peripherals {
|
||||||
|
// name = peripheral.find('name')
|
||||||
|
// peri_base = 'HW_' + name.text + '_BASE'
|
||||||
|
// registers = peripheral.find('registers')
|
||||||
|
let mod_name = peripheral.name.to_lowercase();
|
||||||
|
let reg_name = peripheral.name.to_uppercase() + "_csr";
|
||||||
|
writeln!(out, " let mut {}_csr = CSR::new(HW_{}_BASE as *mut u32);", peripheral.name.to_lowercase(), peripheral.name.to_uppercase())?;
|
||||||
|
for register in &peripheral.registers {
|
||||||
|
// name = register.find('name')
|
||||||
|
// offset = register.find('addressOffset')
|
||||||
|
// register_name = name.text
|
||||||
|
writeln!(out, " let foo = {}.r(utra::{}::{});", reg_name, mod_name, register.name.to_lowercase())?;
|
||||||
|
// lib.write(' {}.wo(utra::{}::{}, foo);\n'.format(reg_name, mod_name, register_name))
|
||||||
|
// for fields in register.find('fields'):
|
||||||
|
// field = fields.find('name')
|
||||||
|
// field_name = register_name + '_' + field.text.upper()
|
||||||
|
// lib.write(' let bar = {}.rf(utra::{}::{});\n'.format(reg_name, mod_name, field_name))
|
||||||
|
// lib.write(' {}.rmwf(utra::{}::{}, bar);\n'.format(reg_name, mod_name, field_name))
|
||||||
|
// lib.write(' let mut baz = {}.zf(utra::{}::{}, bar);\n'.format(reg_name, mod_name, field_name))
|
||||||
|
// lib.write(' baz |= {}.ms(utra::{}::{}, 1);\n'.format(reg_name, mod_name, field_name))
|
||||||
|
// lib.write(' {}.wfo(utra::{}::{}, baz);\n'.format(reg_name, mod_name, field_name))
|
||||||
|
}
|
||||||
|
// lib.write('\n')
|
||||||
|
}
|
||||||
|
writeln!(out, " }}")?;
|
||||||
|
writeln!(out, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn generate<T: Read, U: Write>(src: T, dest: &mut U) -> Result<(), ParseError> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let buf_reader = BufReader::new(src);
|
||||||
|
let mut reader = Reader::from_reader(buf_reader);
|
||||||
|
let mut description = Description::default();
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => match e.name() {
|
||||||
|
b"peripherals" => {
|
||||||
|
description.peripherals = generate_peripherals(&mut reader)?;
|
||||||
|
}
|
||||||
|
b"vendorExtensions" => {
|
||||||
|
parse_vendor_extensions(&mut reader, &mut description)?;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
Ok(Event::Eof) => break,
|
||||||
|
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header(dest).unwrap();
|
||||||
|
print_memory_regions(&description.memory_regions, dest).unwrap();
|
||||||
|
print_peripherals(&description.peripherals, dest).unwrap();
|
||||||
|
print_tests(&description.peripherals, dest).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
10
src/lib.rs
Normal file
10
src/lib.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
mod generate;
|
||||||
|
pub use generate::*;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
10
src/main.rs
Normal file
10
src/main.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
mod generate;
|
||||||
|
use generate::*;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let src = File::open("examples/soc.svd").unwrap();
|
||||||
|
let mut dest = File::create("example.rs").unwrap();
|
||||||
|
generate(src, &mut dest).unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user