diff --git a/Cargo.lock b/Cargo.lock index b826560..5ef333e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,7 @@ version = "0.1.0" dependencies = [ "anyhow", "env_logger", + "heck", "log", "proc-macro2", "quote", @@ -109,6 +110,12 @@ dependencies = [ "log", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "humantime" version = "2.1.0" diff --git a/Cargo.toml b/Cargo.toml index b5b5d77..6328c5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0.95" env_logger = "0.11.6" +heck = "0.5" log = "0.4" proc-macro2 = "1.0.93" quote = "1.0" diff --git a/src/generator.rs b/src/generator.rs index 8be3b60..47ebd86 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -1,6 +1,10 @@ //! Generate register interface rust code from types in [`crate::types`]. -use crate::types::{Block, Module, ModuleBlockElements}; +use crate::{ + type_traits::GetName, + types::{Block, Module, ModuleBlockElements}, +}; +use heck::{ToSnakeCase, ToUpperCamelCase}; use proc_macro2::TokenStream; use quote::quote; @@ -40,43 +44,65 @@ impl CodeGen for ModuleBlockElements { impl CodeGen for Block { fn generate_register_interface(self) -> proc_macro2::TokenStream { - let name = self.name; + let snake_case_name = self.name.to_snake_case(); + let upper_camel_name = self.name.to_upper_camel_case(); + let addr = format!("0x{:x}", self.addr); let desc = self.desc.unwrap_or("".to_string()); + let accessor_methods = { + let mut out = TokenStream::new(); + for child_name in self.elements.iter().map(|e| e.get_name()) { + let snake_case_name = child_name.to_snake_case(); + let upper_camel_name = child_name.to_upper_camel_case(); + + out.extend(quote! { + pub fn #snake_case_name(&self) -> #snake_case_name::#upper_camel_name { + #snake_case_name::#upper_camel_name::new(self.mem_ptr) + } + }); + } + + out + }; + + let child_mods = { + let mut out = TokenStream::new(); + for child_mod in self.elements.into_iter() { + let module = child_mod.generate_register_interface(); + out.extend(module); + } + + out + }; + quote! { - pub mod #name { + pub mod #snake_case_name { #[doc = #desc] - + use std::marker::PhantomData; - + use super::RegisterInterface; - - pub mod control; - pub mod status; - - pub(crate) const SLR0_OFFSET: usize = 0x0000; - pub(crate) const SLR0_SIZE: usize = 0x4000; - + + #child_mods + + const OFFSET: usize = #addr; + //pub(crate) const SIZE: usize = 0x4000; + /// Access to SLR0. - pub struct Slr0<'a> { + pub struct #upper_camel_name<'a> { mem_ptr: *mut u32, _marker: PhantomData<&'a mut RegisterInterface>, } - - impl Slr0<'_> { - pub(crate) fn new(ptr: *mut u32) -> Self { - Slr0 { - mem_ptr: ptr, + + impl #upper_camel_name<'_> { + pub(crate) fn new(parent_ptr: *mut u32) -> Self { + #upper_camel_name { + mem_ptr: unsafe { parent_ptr.add(OFFSET) }, _marker: PhantomData, } } - pub fn control(&self) -> control::Control { - control::Control::new(unsafe { self.mem_ptr.add(control::OFFSET) }) - } - - pub fn status(&self) -> status::Status { - status::Status::new(unsafe { self.mem_ptr.add(status::OFFSET) }) - } + + #accessor_methods } } } diff --git a/src/lib.rs b/src/lib.rs index 0d7723e..863641c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! Root document [`types::Module::from_xml_dom`] pub mod types; +pub mod type_traits; pub mod parser; pub mod converter; pub mod generator; diff --git a/src/type_traits.rs b/src/type_traits.rs new file mode 100644 index 0000000..a31512f --- /dev/null +++ b/src/type_traits.rs @@ -0,0 +1,30 @@ +//! Util traits to get info from types in [`crate::types`]. + +use crate::types::{Block, ModuleBlockElements, Register}; + +pub(crate) trait GetName { + fn get_name(&self) -> String; +} + +impl GetName for ModuleBlockElements { + fn get_name(&self) -> String { + match self { + ModuleBlockElements::Block(block) => block.get_name(), + ModuleBlockElements::Register(register) => register.get_name(), + ModuleBlockElements::Memory(memory) => todo!(), + ModuleBlockElements::Fifo(fifo) => todo!(), + } + } +} + +impl GetName for Block { + fn get_name(&self) -> String { + self.name.clone() + } +} + +impl GetName for Register { + fn get_name(&self) -> String { + self.name.clone() + } +}