forked from libre-chip/cpu
		
	WIP: add ArrayVec
This commit is contained in:
		
							parent
							
								
									2cfd54ba88
								
							
						
					
					
						commit
						60341e22af
					
				
					 2 changed files with 266 additions and 0 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||||
| // See Notices.txt for copyright information
 | // See Notices.txt for copyright information
 | ||||||
| 
 | 
 | ||||||
|  | pub mod array_vec; | ||||||
| pub mod tree_reduce; | pub mod tree_reduce; | ||||||
| 
 | 
 | ||||||
| pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize { | pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize { | ||||||
|  |  | ||||||
							
								
								
									
										265
									
								
								crates/cpu/src/util/array_vec.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								crates/cpu/src/util/array_vec.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,265 @@ | ||||||
|  | // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||||
|  | // See Notices.txt for copyright information
 | ||||||
|  | 
 | ||||||
|  | use fayalite::{ | ||||||
|  |     expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd}, | ||||||
|  |     int::SizeType, | ||||||
|  |     intern::{Intern, Interned}, | ||||||
|  |     prelude::*, | ||||||
|  |     ty::{MatchVariantWithoutScope, StaticType, TypeProperties}, | ||||||
|  | }; | ||||||
|  | use std::{marker::PhantomData, ops::Index}; | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||||||
|  | pub struct Length<Max: Size> { | ||||||
|  |     ty: UInt, | ||||||
|  |     _phantom: PhantomData<Max>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: Size> Length<Max> { | ||||||
|  |     pub fn new(max: Max::SizeType) -> Self { | ||||||
|  |         Self { | ||||||
|  |             ty: UInt::range_inclusive(0..=Max::as_usize(max)), | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn ty(self) -> UInt { | ||||||
|  |         self.ty | ||||||
|  |     } | ||||||
|  |     pub fn zero(self) -> Expr<Self> { | ||||||
|  |         Self::from_uint_unchecked(self.ty.zero()) | ||||||
|  |     } | ||||||
|  |     pub fn from_uint_unchecked(v: impl ToExpr<Type = UInt>) -> Expr<Self> { | ||||||
|  |         Expr::from_canonical(Expr::canonical(v.to_expr())) | ||||||
|  |     } | ||||||
|  |     pub fn cast_from_uint_unchecked<SrcWidth: Size>( | ||||||
|  |         self, | ||||||
|  |         v: impl ToExpr<Type = UIntType<SrcWidth>>, | ||||||
|  |     ) -> Expr<Self> { | ||||||
|  |         Self::from_uint_unchecked(v.to_expr().cast_to(self.ty)) | ||||||
|  |     } | ||||||
|  |     pub fn as_uint(this: impl ToExpr<Type = Self>) -> Expr<UInt> { | ||||||
|  |         let this = this.to_expr(); | ||||||
|  |         this.cast_to(Expr::ty(this).ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: Size, DestWidth: Size> ExprCastTo<UIntType<DestWidth>> for Length<Max> { | ||||||
|  |     fn cast_to(src: Expr<Self>, to_type: UIntType<DestWidth>) -> Expr<UIntType<DestWidth>> { | ||||||
|  |         Expr::<UInt>::from_canonical(Expr::canonical(src)).cast_to(to_type) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[allow(non_upper_case_globals)] | ||||||
|  | pub const Length: __LengthWithoutGenerics = __LengthWithoutGenerics {}; | ||||||
|  | 
 | ||||||
|  | #[non_exhaustive] | ||||||
|  | pub struct __LengthWithoutGenerics {} | ||||||
|  | 
 | ||||||
|  | impl<M: SizeType> Index<M> for __LengthWithoutGenerics { | ||||||
|  |     type Output = Length<M::Size>; | ||||||
|  | 
 | ||||||
|  |     fn index(&self, max: M) -> &Self::Output { | ||||||
|  |         Interned::into_inner(Length::new(max).intern_sized()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: Size> Type for Length<Max> { | ||||||
|  |     type BaseType = UInt; | ||||||
|  |     type MaskType = Bool; | ||||||
|  |     type MatchVariant = Expr<Self>; | ||||||
|  |     type MatchActiveScope = (); | ||||||
|  |     type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>; | ||||||
|  |     type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>; | ||||||
|  |     fn match_variants( | ||||||
|  |         this: Expr<Self>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|  |     ) -> Self::MatchVariantsIter { | ||||||
|  |         let _ = source_location; | ||||||
|  |         std::iter::once(MatchVariantWithoutScope(this)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn mask_type(&self) -> Self::MaskType { | ||||||
|  |         Bool | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn canonical(&self) -> CanonicalType { | ||||||
|  |         self.ty.canonical() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn from_canonical(canonical_type: CanonicalType) -> Self { | ||||||
|  |         let ty = <UInt>::from_canonical(canonical_type); | ||||||
|  |         if let Some(known_max) = Max::KNOWN_VALUE { | ||||||
|  |             assert_eq!(ty, UInt::range_inclusive(0..=known_max)); | ||||||
|  |         } | ||||||
|  |         Self { | ||||||
|  |             ty, | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn source_location() -> SourceLocation { | ||||||
|  |         SourceLocation::caller() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: KnownSize> StaticType for Length<Max> { | ||||||
|  |     const TYPE: Self = Self { | ||||||
|  |         ty: UInt { | ||||||
|  |             width: Max::VALUE.next_power_of_two().ilog2() as usize, | ||||||
|  |         }, | ||||||
|  |         _phantom: PhantomData, | ||||||
|  |     }; | ||||||
|  |     const MASK_TYPE: Self::MaskType = Bool; | ||||||
|  |     const TYPE_PROPERTIES: TypeProperties = { | ||||||
|  |         let mut p = <UInt<1>>::TYPE_PROPERTIES; | ||||||
|  |         p.bit_width = Self::TYPE.ty.width; | ||||||
|  |         p | ||||||
|  |     }; | ||||||
|  |     const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: Size> ExprPartialEq<Self> for Length<Max> { | ||||||
|  |     fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_eq(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  |     fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_ne(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<Max: Size> ExprPartialOrd<Self> for Length<Max> { | ||||||
|  |     fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_lt(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  |     fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_le(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  |     fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_gt(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  |     fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         Self::as_uint(lhs).cmp_ge(Self::as_uint(rhs)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
 | ||||||
|  | #[hdl] | ||||||
|  | pub struct ArrayVec<T: Type, N: Size> { | ||||||
|  |     elements: ArrayType<T, N>, | ||||||
|  |     len: Length<N>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Type, N: Size> ArrayVec<T, N> { | ||||||
|  |     #[hdl] | ||||||
|  |     pub fn new(self) -> Expr<Self> { | ||||||
|  |         #[hdl] | ||||||
|  |         ArrayVec { | ||||||
|  |             elements: self.elements.uninit(), | ||||||
|  |             len: self.len.zero(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn element(self) -> T { | ||||||
|  |         self.elements.element() | ||||||
|  |     } | ||||||
|  |     pub fn elements_ty(self) -> ArrayType<T, N> { | ||||||
|  |         self.elements | ||||||
|  |     } | ||||||
|  |     pub fn elements_unchecked(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<T, N>> { | ||||||
|  |         this.to_expr().elements | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     pub fn from_parts_unchecked( | ||||||
|  |         elements: impl ToExpr<Type = ArrayType<T, N>>, | ||||||
|  |         len: impl ToExpr<Type = Length<N>>, | ||||||
|  |     ) -> Expr<Self> { | ||||||
|  |         let elements = elements.to_expr(); | ||||||
|  |         let len = len.to_expr(); | ||||||
|  |         assert_eq!( | ||||||
|  |             Length::new(N::from_usize(Expr::ty(elements).len())), | ||||||
|  |             Expr::ty(len), | ||||||
|  |             "len type mismatch", | ||||||
|  |         ); | ||||||
|  |         #[hdl] | ||||||
|  |         Self { elements, len } | ||||||
|  |     } | ||||||
|  |     pub fn len_ty(self) -> Length<N> { | ||||||
|  |         self.len | ||||||
|  |     } | ||||||
|  |     pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> { | ||||||
|  |         this.to_expr().len | ||||||
|  |     } | ||||||
|  |     pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> { | ||||||
|  |         let len = Self::len(this); | ||||||
|  |         len.cmp_eq(Expr::ty(len).zero()) | ||||||
|  |     } | ||||||
|  |     pub fn capacity(self) -> usize { | ||||||
|  |         self.elements.len() | ||||||
|  |     } | ||||||
|  |     pub fn get_unchecked<Idx>(this: impl ToExpr<Type = Self>, index: Idx) -> Expr<T> | ||||||
|  |     where | ||||||
|  |         ArrayType<T, N>: ExprIndex<Idx, Output = T>, | ||||||
|  |     { | ||||||
|  |         this.to_expr().elements[index] | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     pub fn for_each(this: impl ToExpr<Type = Self>, mut f: impl FnMut(usize, Expr<T>)) { | ||||||
|  |         let this = this.to_expr(); | ||||||
|  |         for (index, element) in this.elements.into_iter().enumerate() { | ||||||
|  |             #[hdl] | ||||||
|  |             if index.cmp_lt(Length::as_uint(this.len)) { | ||||||
|  |                 f(index, element); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> { | ||||||
|  |         ArrayVec { | ||||||
|  |             elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())], | ||||||
|  |             len: self.len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     pub fn map<U: Type>( | ||||||
|  |         this: impl ToExpr<Type = Self>, | ||||||
|  |         new_element_ty: U, | ||||||
|  |         mut f: impl FnMut(usize, Expr<T>) -> Expr<U>, | ||||||
|  |     ) -> Expr<ArrayVec<U, N>> { | ||||||
|  |         let this = this.to_expr(); | ||||||
|  |         #[hdl] | ||||||
|  |         let mapped_array_vec = wire(Expr::ty(this).mapped_ty(new_element_ty)); | ||||||
|  |         connect(mapped_array_vec.len, this.len); | ||||||
|  |         Self::for_each(this, |index, element| { | ||||||
|  |             connect(mapped_array_vec[index], f(index, element)); | ||||||
|  |         }); | ||||||
|  |         mapped_array_vec | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> { | ||||||
|  |         let this = this.to_expr(); | ||||||
|  |         #[hdl] | ||||||
|  |         let array_vec_as_array_of_options = wire( | ||||||
|  |             ArrayType[HdlOption[Expr::ty(this).element()]] | ||||||
|  |                 [N::from_usize(Expr::ty(this).capacity())], | ||||||
|  |         ); | ||||||
|  |         for element in array_vec_as_array_of_options { | ||||||
|  |             connect(element, Expr::ty(element).HdlNone()); | ||||||
|  |         } | ||||||
|  |         Self::for_each(this, |index, element| { | ||||||
|  |             connect(array_vec_as_array_of_options[index], HdlSome(element)) | ||||||
|  |         }); | ||||||
|  |         array_vec_as_array_of_options | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Type, N: Size, Idx, IdxWidth: Size> ExprIndex<Idx> for ArrayVec<T, N> | ||||||
|  | where | ||||||
|  |     ArrayType<T, N>: ExprIndex<Idx, Output = T>, | ||||||
|  |     Idx: ToExpr<Type = UIntType<IdxWidth>>, | ||||||
|  | { | ||||||
|  |     type Output = T; | ||||||
|  | 
 | ||||||
|  |     fn expr_index(this: &Expr<Self>, index: Idx) -> &Expr<Self::Output> { | ||||||
|  |         // TODO: add assert that index is in-bounds
 | ||||||
|  |         <ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue