diff --git a/Cargo.lock b/Cargo.lock index dfaf1ae..b826560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,8 @@ dependencies = [ "anyhow", "env_logger", "log", + "proc-macro2", + "quote", "roxmltree", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 8a02725..b5b5d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,5 +15,7 @@ path = "src/lib.rs" anyhow = "1.0.95" env_logger = "0.11.6" log = "0.4" +proc-macro2 = "1.0.93" +quote = "1.0" roxmltree = "0.20" thiserror = "2.0" diff --git a/src/converter.rs b/src/converter.rs index c9fcabe..5483282 100644 --- a/src/converter.rs +++ b/src/converter.rs @@ -1,4 +1,4 @@ -//! Convert DOM to register interface, complementing optional parameters. +//! Convert DOM to register interface defined in [`crate::types`], complementing optional parameters. use std::{num, str}; diff --git a/src/generator.rs b/src/generator.rs new file mode 100644 index 0000000..8be3b60 --- /dev/null +++ b/src/generator.rs @@ -0,0 +1,84 @@ +//! Generate register interface rust code from types in [`crate::types`]. + +use crate::types::{Block, Module, ModuleBlockElements}; +use proc_macro2::TokenStream; +use quote::quote; + +pub trait CodeGen { + fn generate_register_interface(self) -> proc_macro2::TokenStream; +} + +impl CodeGen for Module { + fn generate_register_interface(self) -> proc_macro2::TokenStream { + let mut out = TokenStream::new(); + if !self.elements_bitstring.is_empty() { + todo!("bitstring generation is not yet implemented") + } + + let child_mods = self + .elements_other + .into_iter() + .map(|e| e.generate_register_interface()); + for child in child_mods { + out.extend(child); + } + + out + } +} + +impl CodeGen for ModuleBlockElements { + fn generate_register_interface(self) -> proc_macro2::TokenStream { + match self { + ModuleBlockElements::Block(block) => block.generate_register_interface(), + ModuleBlockElements::Register(register) => todo!(), + ModuleBlockElements::Memory(memory) => todo!(), + ModuleBlockElements::Fifo(fifo) => todo!(), + } + } +} + +impl CodeGen for Block { + fn generate_register_interface(self) -> proc_macro2::TokenStream { + let name = self.name; + let desc = self.desc.unwrap_or("".to_string()); + + quote! { + pub mod #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; + + /// Access to SLR0. + pub struct Slr0<'a> { + mem_ptr: *mut u32, + _marker: PhantomData<&'a mut RegisterInterface>, + } + + impl Slr0<'_> { + pub(crate) fn new(ptr: *mut u32) -> Self { + Slr0 { + mem_ptr: ptr, + _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) }) + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 477c59e..0d7723e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod types; pub mod parser; pub mod converter; +pub mod generator; diff --git a/src/main.rs b/src/main.rs index b042c79..79d45c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::fs; use anyhow::Result; -use endcap_sl_software_ri_generator::types; +use endcap_sl_software_ri_generator::{generator::CodeGen, types}; fn main() -> Result<()> { env_logger::init(); @@ -21,5 +21,7 @@ fn main() -> Result<()> { let register_map = types::Module::from_xml_dom(doc.root_element())?; println!("read: {:#?}", register_map); + println!("{}", register_map.generate_register_interface()); + Ok(()) } diff --git a/src/types.rs b/src/types.rs index fa4ba30..c3bfd3f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,3 +1,5 @@ +//! Register type definition. + #[derive(Debug)] pub struct Module { pub name: String,