Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions src/generate/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,20 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result<T

let ty = quote!(#common_path::Reg<#reg_ty, #access>);
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,
&quote!(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 {
Expand All @@ -74,14 +81,21 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result<T

let ty = util::relative_path(block_path, path);
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,
&quote!(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 { #ty::from_ptr(self.ptr.wrapping_add(#offset + #offs_expr) as _) }
pub const fn #name(self) -> #array_ty {
#constructor
}
));
} else {
Expand Down Expand Up @@ -123,6 +137,12 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result<T

#items
}

impl #common_path::FromPtr for #name {
unsafe fn from_ptr(ptr: *mut u8) -> Self {
unsafe { #name::from_ptr(ptr as *mut ()) }
}
}
};

Ok(out)
Expand Down
146 changes: 146 additions & 0 deletions src/generate/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,149 @@ impl<T: Copy, A: Read + Write> Reg<T, A> {
self.write_value(val);
}
}

pub trait FromPtr: Copy {
unsafe fn from_ptr(ptr: *mut u8) -> Self;
}

impl<T: Copy, A: Access> FromPtr for Reg<T, A> {
unsafe fn from_ptr(ptr: *mut u8) -> Self {
unsafe { Reg::<T, A>::from_ptr(ptr as *mut T) }
}
}

pub struct Array<T> {
ptr: *mut u8,
stride: usize,
len: usize,
_type: PhantomData<T>,
}

pub struct ArrayIter<T> {
parent: T,
}

impl<T: Clone> Clone for Array<T> {
fn clone(&self) -> Self {
Self {
ptr: self.ptr,
stride: self.stride,
len: self.len,
_type: self._type,
}
}
}
impl<T: Copy> Copy for Array<T> {}

impl<T> Array<T> {
#[inline(always)]
pub const fn len(&self) -> usize {
self.len
}
}

impl<T: FromPtr> Array<T> {
#[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<T: FromPtr> IntoIterator for Array<T> {
type Item = T;
type IntoIter = ArrayIter<Array<T>>;

fn into_iter(self) -> Self::IntoIter {
ArrayIter { parent: self }
}
}

impl<T: FromPtr> Iterator for ArrayIter<Array<T>> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
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<T> {
ptr: *mut u8,
offsets: &'static [usize],
_type: PhantomData<T>,
}

impl<T: Clone> Clone for CursedArray<T> {
fn clone(&self) -> Self {
Self {
ptr: self.ptr,
offsets: self.offsets,
_type: self._type,
}
}
}
impl<T: Copy> Copy for CursedArray<T> {}

impl<T> CursedArray<T> {
#[inline(always)]
pub const fn len(&self) -> usize {
self.offsets.len()
}
}

impl<T: FromPtr> CursedArray<T> {
#[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<T: FromPtr> IntoIterator for CursedArray<T> {
type Item = T;
type IntoIter = ArrayIter<CursedArray<T>>;

fn into_iter(self) -> Self::IntoIter {
ArrayIter { parent: self }
}
}

impl<T: FromPtr> Iterator for ArrayIter<CursedArray<T>> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
if self.parent.len() == 0 {
return None;
}

let el = self.parent.get(0);
self.parent.offsets = &self.parent.offsets[1..];
Some(el)
}
}
15 changes: 13 additions & 2 deletions src/generate/fieldset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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]
Expand All @@ -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!(
Expand Down Expand Up @@ -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]
Expand All @@ -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!(
Expand Down
36 changes: 35 additions & 1 deletion src/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>();
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;
Expand Down