diff --git a/src/generate/block.rs b/src/generate/block.rs index e223ec3d..68c2e9ed 100644 --- a/src/generate/block.rs +++ b/src/generate/block.rs @@ -46,13 +46,20 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result); if let Some(array) = &i.array { - let (len, offs_expr) = super::process_array(array); + let super::ArrayDescription { + array_ty, + constructor, + } = super::process_ptr_array( + array, + "e!(self.ptr.wrapping_add(#offset)), + &ty, + &common_path, + ); items.extend(quote!( #doc #[inline(always)] - pub const fn #name(self, n: usize) -> #ty { - assert!(n < #len); - unsafe { #common_path::Reg::from_ptr(self.ptr.wrapping_add(#offset + #offs_expr) as _) } + pub const fn #name(self) -> #array_ty { + #constructor } )); } else { @@ -74,14 +81,21 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result #ty { - assert!(n < #len); - unsafe { #ty::from_ptr(self.ptr.wrapping_add(#offset + #offs_expr) as _) } + pub const fn #name(self) -> #array_ty { + #constructor } )); } else { @@ -123,6 +137,12 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result Self { + unsafe { #name::from_ptr(ptr as *mut ()) } + } + } }; Ok(out) diff --git a/src/generate/common.rs b/src/generate/common.rs index a380a64e..876924dd 100644 --- a/src/generate/common.rs +++ b/src/generate/common.rs @@ -83,3 +83,149 @@ impl Reg { self.write_value(val); } } + +pub trait FromPtr: Copy { + unsafe fn from_ptr(ptr: *mut u8) -> Self; +} + +impl FromPtr for Reg { + unsafe fn from_ptr(ptr: *mut u8) -> Self { + unsafe { Reg::::from_ptr(ptr as *mut T) } + } +} + +pub struct Array { + ptr: *mut u8, + stride: usize, + len: usize, + _type: PhantomData, +} + +pub struct ArrayIter { + parent: T, +} + +impl Clone for Array { + fn clone(&self) -> Self { + Self { + ptr: self.ptr, + stride: self.stride, + len: self.len, + _type: self._type, + } + } +} +impl Copy for Array {} + +impl Array { + #[inline(always)] + pub const fn len(&self) -> usize { + self.len + } +} + +impl Array { + #[inline(always)] + pub const unsafe fn from_ptr(ptr: *mut u8, stride: usize, len: usize) -> Self { + Self { + ptr, + stride, + len, + _type: PhantomData, + } + } + + #[inline(always)] + pub fn get(&self, n: usize) -> T { + assert!(n < self.len()); + unsafe { T::from_ptr(self.ptr.wrapping_add(n * self.stride)) } + } +} + +impl IntoIterator for Array { + type Item = T; + type IntoIter = ArrayIter>; + + fn into_iter(self) -> Self::IntoIter { + ArrayIter { parent: self } + } +} + +impl Iterator for ArrayIter> { + type Item = T; + + fn next(&mut self) -> Option { + if self.parent.len == 0 { + return None; + } + + let el = self.parent.get(0); + self.parent.ptr = self.parent.ptr.wrapping_add(self.parent.stride); + self.parent.len -= 1; + Some(el) + } +} + +pub struct CursedArray { + ptr: *mut u8, + offsets: &'static [usize], + _type: PhantomData, +} + +impl Clone for CursedArray { + fn clone(&self) -> Self { + Self { + ptr: self.ptr, + offsets: self.offsets, + _type: self._type, + } + } +} +impl Copy for CursedArray {} + +impl CursedArray { + #[inline(always)] + pub const fn len(&self) -> usize { + self.offsets.len() + } +} + +impl CursedArray { + #[inline(always)] + pub const unsafe fn from_ptr(ptr: *mut u8, offsets: &'static [usize]) -> Self { + Self { + ptr, + offsets, + _type: PhantomData, + } + } + + #[inline(always)] + pub fn get(&self, n: usize) -> T { + assert!(n < self.len()); + unsafe { T::from_ptr(self.ptr.wrapping_add(self.offsets[n])) } + } +} + +impl IntoIterator for CursedArray { + type Item = T; + type IntoIter = ArrayIter>; + + fn into_iter(self) -> Self::IntoIter { + ArrayIter { parent: self } + } +} + +impl Iterator for ArrayIter> { + type Item = T; + + fn next(&mut self) -> Option { + if self.parent.len() == 0 { + return None; + } + + let el = self.parent.get(0); + self.parent.offsets = &self.parent.offsets[1..]; + Some(el) + } +} diff --git a/src/generate/fieldset.rs b/src/generate/fieldset.rs index d64f7c47..c6f81fad 100644 --- a/src/generate/fieldset.rs +++ b/src/generate/fieldset.rs @@ -26,6 +26,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu for f in sorted(&fs.fields, |f| (f.bit_offset.clone(), f.name.clone())) { let name = Ident::new(&f.name, span); let name_set = Ident::new(&format!("set_{}", f.name), span); + let name_len = Ident::new(&format!("{}_len", f.name), span); let off_in_reg = f.bit_offset.clone(); let _bit_size = f.bit_size as usize; let mask = util::hex(1u64.wrapping_shl(f.bit_size).wrapping_sub(1)); @@ -83,7 +84,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu BitOffset::Regular(off_in_reg) => { let off_in_reg = off_in_reg as usize; if let Some(array) = &f.array { - let (len, offs_expr) = super::process_array(array); + let (len, offs_expr) = super::process_field_array(array); items.extend(quote!( #doc #[must_use] @@ -101,6 +102,11 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu let offs = #off_in_reg + #offs_expr; self.0 = (self.0 & !(#mask << offs)) | (((#to_bits) & #mask) << offs); } + #doc + #[inline(always)] + pub const fn #name_len(&self) -> usize { + #len + } )); } else { items.extend(quote!( @@ -142,7 +148,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } if let Some(array) = &f.array { - let (len, offs_expr) = super::process_array(array); + let (len, offs_expr) = super::process_field_array(array); items.extend(quote!( #doc #[must_use] @@ -161,6 +167,11 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu #( let offs = #off_in_reg + #offs_expr; self.0 = (self.0 & !(#mask << offs)) | (((#to_bits >> #off_in_val) & #mask) << offs); )*; } + #doc + #[inline(always)] + pub const fn #name_len(&self) -> usize { + #len + } )); } else { items.extend(quote!( diff --git a/src/generate/mod.rs b/src/generate/mod.rs index 54ce3d0e..28ed7e4a 100644 --- a/src/generate/mod.rs +++ b/src/generate/mod.rs @@ -227,7 +227,41 @@ fn split_path(s: &str) -> (Vec<&str>, &str) { (v, n) } -fn process_array(array: &Array) -> (usize, TokenStream) { +struct ArrayDescription { + array_ty: TokenStream, + constructor: TokenStream, +} + +fn process_ptr_array( + array: &Array, + ptr: &TokenStream, + ty: &TokenStream, + common_path: &TokenStream, +) -> ArrayDescription { + match array { + Array::Regular(array) => { + let len = array.len as usize; + let stride = array.stride as usize; + ArrayDescription { + array_ty: quote!(#common_path::Array<#ty>), + constructor: quote!(unsafe { #common_path::Array::from_ptr(#ptr, #stride, #len) }), + } + } + Array::Cursed(array) => { + let offsets = array + .offsets + .iter() + .map(|&x| x as usize) + .collect::>(); + ArrayDescription { + array_ty: quote!(#common_path::CursedArray<#ty>), + constructor: quote!(unsafe { #common_path::CursedArray::from_ptr(#ptr, &[#(#offsets),*]) }), + } + } + } +} + +fn process_field_array(array: &Array) -> (usize, TokenStream) { match array { Array::Regular(array) => { let len = array.len as usize;