diff --git a/Cargo.toml b/Cargo.toml index ec3ee872..e453e235 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,7 @@ inflections = "1.1.0" log = { version = "~0.4", features = ["std"] } quote = "0.3.15" svd-parser = "0.7" -syn = "0.11.11" + +[dependencies.syn] +version = "0.11.11" +features = ["full"] diff --git a/src/generate/device.rs b/src/generate/device.rs index abe353f5..c45666a4 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -1,4 +1,6 @@ -use quote::Tokens; +use quote::{Tokens, ToTokens}; +use std::fs::File; +use std::io::Write; use crate::svd::Device; use syn::Ident; @@ -6,13 +8,14 @@ use crate::errors::*; use crate::util::{self, ToSanitizedUpperCase}; use crate::Target; -use crate::generate::{interrupt, peripheral, generic}; +use crate::generate::{interrupt, peripheral}; /// Whole device generation pub fn render( d: &Device, target: Target, nightly: bool, + generic_mod: bool, device_x: &mut String, ) -> Result> { let mut out = vec![]; @@ -136,7 +139,22 @@ pub fn render( } } - out.extend(generic::render()?); + let generic_file = std::str::from_utf8(include_bytes!("generic.rs")).unwrap(); + if generic_mod { + writeln!(File::create("generic.rs").unwrap(), "{}", generic_file).unwrap(); + } else { + let mut tokens = Tokens::new(); + (syn::parse_crate(generic_file)?).to_tokens(&mut tokens); + + out.push(quote! { + #[allow(unused_imports)] + use generic::*; + ///Common register and bit access and modify traits + pub mod generic { + #tokens + } + }); + } for p in &d.peripherals { if target == Target::CortexM && core_peripherals.contains(&&*p.name.to_uppercase()) { diff --git a/src/generate/generic.rs b/src/generate/generic.rs index adf9b80e..331ee56b 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -1,234 +1,190 @@ -use quote::Tokens; - -use crate::errors::*; - -/// Generates generic bit munging code -pub fn render() -> Result> { - let mut code = vec![]; - let mut generic_items = vec![]; - - generic_items.push(quote! { - use core::marker; - - ///This trait shows that register has `read` method - /// - ///Registers marked with `Writable` can be also `modify`'ed - pub trait Readable {} - - ///This trait shows that register has `write`, `write_with_zero` and `reset` method - /// - ///Registers marked with `Readable` can be also `modify`'ed - pub trait Writable {} - - ///Reset value of the register - /// - ///This value is initial value for `write` method. - ///It can be also directly writed to register by `reset` method. - pub trait ResetValue { - ///Register size - type Type; - ///Reset value of the register - fn reset_value() -> Self::Type; - } +use core::marker; + +///This trait shows that register has `read` method +/// +///Registers marked with `Writable` can be also `modify`'ed +pub trait Readable {} + +///This trait shows that register has `write`, `write_with_zero` and `reset` method +/// +///Registers marked with `Readable` can be also `modify`'ed +pub trait Writable {} + +///Reset value of the register +/// +///This value is initial value for `write` method. +///It can be also directly writed to register by `reset` method. +pub trait ResetValue { + ///Register size + type Type; + ///Reset value of the register + fn reset_value() -> Self::Type; +} - ///Converting enumerated values to bits - pub trait ToBits { - ///Conversion method - fn _bits(&self) -> N; - } - }); +///Converting enumerated values to bits +pub trait ToBits { + ///Conversion method + fn _bits(&self) -> N; +} - generic_items.push(quote! { - ///This structure provides volatile access to register - pub struct Reg { - register: vcell::VolatileCell, - _marker: marker::PhantomData, - } +///This structure provides volatile access to register +pub struct Reg { + register: vcell::VolatileCell, + _marker: marker::PhantomData, +} - unsafe impl Send for Reg { } - - impl Reg - where - Self: Readable, - U: Copy - { - ///Reads the contents of `Readable` register - /// - ///See [reading](https://rust-embedded.github.io/book/start/registers.html#reading) in book. - #[inline(always)] - pub fn read(&self) -> R { - R {bits: self.register.get(), _reg: marker::PhantomData} - } - } +unsafe impl Send for Reg { } + +impl Reg +where + Self: Readable, + U: Copy +{ + ///Reads the contents of `Readable` register + /// + ///See [reading](https://rust-embedded.github.io/book/start/registers.html#reading) in book. + #[inline(always)] + pub fn read(&self) -> R { + R {bits: self.register.get(), _reg: marker::PhantomData} + } +} - impl Reg - where - Self: ResetValue + Writable, - U: Copy, - { - ///Writes the reset value to `Writable` register - #[inline(always)] - pub fn reset(&self) { - self.register.set(Self::reset_value()) - } - } - }); - - generic_items.push(quote! { - impl Reg - where - Self: ResetValue + Writable, - U: Copy - { - ///Writes bits to `Writable` register - /// - ///See [writing](https://rust-embedded.github.io/book/start/registers.html#writing) in book. - #[inline(always)] - pub fn write(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W - { - self.register.set(f(&mut W {bits: Self::reset_value(), _reg: marker::PhantomData}).bits); - } - } - }); - - generic_items.push(quote! { - impl Reg - where - Self: Writable, - U: Copy + Default - { - ///Writes Zero to `Writable` register - #[inline(always)] - pub fn write_with_zero(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W - { - self.register.set(f(&mut W {bits: U::default(), _reg: marker::PhantomData }).bits); - } - } - }); - - generic_items.push(quote! { - impl Reg - where - Self: Readable + Writable, - U: Copy, - { - ///Modifies the contents of the register - /// - ///See [modifying](https://rust-embedded.github.io/book/start/registers.html#modifying) in book. - #[inline(always)] - pub fn modify(&self, f: F) - where - for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W - { - let bits = self.register.get(); - self.register.set(f(&R {bits, _reg: marker::PhantomData}, &mut W {bits, _reg: marker::PhantomData}).bits); - } - } - }); +impl Reg +where + Self: ResetValue + Writable, + U: Copy, +{ + ///Writes the reset value to `Writable` register + #[inline(always)] + pub fn reset(&self) { + self.register.set(Self::reset_value()) + } +} - generic_items.push(quote! { - ///Register/field reader - pub struct R { - pub(crate) bits: U, - _reg: marker::PhantomData, - } +impl Reg +where + Self: ResetValue + Writable, + U: Copy +{ + ///Writes bits to `Writable` register + /// + ///See [writing](https://rust-embedded.github.io/book/start/registers.html#writing) in book. + #[inline(always)] + pub fn write(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W + { + self.register.set(f(&mut W {bits: Self::reset_value(), _reg: marker::PhantomData}).bits); + } +} - impl R - where - U: Copy - { - ///Create new instance of reader - #[inline(always)] - pub(crate) fn new(bits: U) -> Self { - Self { - bits, - _reg: marker::PhantomData, - } - } - ///Read raw bits from register/field - #[inline(always)] - pub fn bits(&self) -> U { - self.bits - } - } - }); - - generic_items.push(quote! { - impl PartialEq for R - where - U: PartialEq, - FI: ToBits - { - fn eq(&self, other: &FI) -> bool { - self.bits.eq(&other._bits()) - } - } - }); - - generic_items.push(quote! { - impl R { - ///Value of the field as raw bits - #[inline(always)] - pub fn bit(&self) -> bool { - self.bits - } - ///Returns `true` if the bit is clear (0) - #[inline(always)] - pub fn bit_is_clear(&self) -> bool { - !self.bit() - } - ///Returns `true` if the bit is set (1) - #[inline(always)] - pub fn bit_is_set(&self) -> bool { - self.bit() - } - } - }); - - generic_items.push(quote! { - ///Register writer - pub struct W { - ///Writable bits - pub bits: U, - _reg: marker::PhantomData, - } - }); - - generic_items.push(quote! { - impl W { - ///Writes raw bits to the register - #[inline(always)] - pub fn bits(&mut self, bits: U) -> &mut Self { - self.bits = bits; - self - } - } - }); +impl Reg +where + Self: Writable, + U: Copy + Default +{ + ///Writes Zero to `Writable` register + #[inline(always)] + pub fn write_with_zero(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W + { + self.register.set(f(&mut W {bits: U::default(), _reg: marker::PhantomData }).bits); + } +} +impl Reg +where + Self: Readable + Writable, + U: Copy, +{ + ///Modifies the contents of the register + /// + ///See [modifying](https://rust-embedded.github.io/book/start/registers.html#modifying) in book. + #[inline(always)] + pub fn modify(&self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W + { + let bits = self.register.get(); + self.register.set(f(&R {bits, _reg: marker::PhantomData}, &mut W {bits, _reg: marker::PhantomData}).bits); + } +} - generic_items.push(quote! { - ///Used if enumerated values cover not the whole range - #[derive(Clone,Copy,PartialEq)] - pub enum Variant { - ///Expected variant - Val(T), - ///Raw bits - Res(U), - } - }); - - code.push(quote! { - #[allow(unused_imports)] - use generic::*; - ///Common register and bit access and modify traits - pub mod generic { - #(#generic_items)* - } - }); +///Register/field reader +pub struct R { + pub(crate) bits: U, + _reg: marker::PhantomData, +} + +impl R +where + U: Copy +{ + ///Create new instance of reader + #[inline(always)] + pub(crate) fn new(bits: U) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + ///Read raw bits from register/field + #[inline(always)] + pub fn bits(&self) -> U { + self.bits + } +} + +impl PartialEq for R +where + U: PartialEq, + FI: ToBits +{ + fn eq(&self, other: &FI) -> bool { + self.bits.eq(&other._bits()) + } +} + +impl R { + ///Value of the field as raw bits + #[inline(always)] + pub fn bit(&self) -> bool { + self.bits + } + ///Returns `true` if the bit is clear (0) + #[inline(always)] + pub fn bit_is_clear(&self) -> bool { + !self.bit() + } + ///Returns `true` if the bit is set (1) + #[inline(always)] + pub fn bit_is_set(&self) -> bool { + self.bit() + } +} + +///Register writer +pub struct W { + ///Writable bits + pub bits: U, + _reg: marker::PhantomData, +} + +impl W { + ///Writes raw bits to the register + #[inline(always)] + pub fn bits(&mut self, bits: U) -> &mut Self { + self.bits = bits; + self + } +} - Ok(code) +///Used if enumerated values cover not the whole range +#[derive(Clone,Copy,PartialEq)] +pub enum Variant { + ///Expected variant + Val(T), + ///Raw bits + Res(U), } diff --git a/src/generate/mod.rs b/src/generate/mod.rs index 6500943f..54216bfb 100644 --- a/src/generate/mod.rs +++ b/src/generate/mod.rs @@ -1,5 +1,4 @@ pub mod device; -pub mod generic; pub mod interrupt; pub mod peripheral; pub mod register; diff --git a/src/lib.rs b/src/lib.rs index e4a5b8f9..7445dc72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -462,7 +462,7 @@ pub fn generate(xml: &str, target: Target, nightly: bool) -> Result let device = svd::parse(xml).unwrap(); //TODO(AJM) let mut device_x = String::new(); - let items = generate::device::render(&device, target, nightly, &mut device_x) + let items = generate::device::render(&device, target, nightly, false, &mut device_x) .or(Err(SvdError::Render))?; let mut lib_rs = String::new(); diff --git a/src/main.rs b/src/main.rs index 729b660a..1a0f13c0 100755 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,12 @@ fn run() -> Result<()> { .long("nightly") .help("Enable features only available to nightly rustc"), ) + .arg( + Arg::with_name("generic_mod") + .long("generic_mod") + .short("g") + .help("Push generic mod in separate file"), + ) .arg( Arg::with_name("log_level") .long("log") @@ -90,8 +96,10 @@ fn run() -> Result<()> { let nightly = matches.is_present("nightly_features"); + let generic_mod = matches.is_present("generic_mod"); + let mut device_x = String::new(); - let items = generate::device::render(&device, target, nightly, &mut device_x)?; + let items = generate::device::render(&device, target, nightly, generic_mod, &mut device_x)?; let mut file = File::create("lib.rs").expect("Couldn't create lib.rs file"); for item in items {