use crate::isa::rvv::{Sew, Vlmul};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Vl(u64);
impl Vl {
#[inline(always)]
pub const fn new(val: u64) -> Self {
Self(val)
}
#[inline(always)]
pub const fn as_u64(self) -> u64 {
self.0
}
#[inline(always)]
pub const fn as_usize(self) -> usize {
self.0 as usize
}
#[inline(always)]
pub const fn is_zero(self) -> bool {
self.0 == 0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Vlmax(usize);
impl Vlmax {
pub const fn compute(vlen: Vlen, sew: Sew, lmul: Vlmul) -> Self {
let vlen_bits = vlen.bits();
let sew_bits = sew.bits();
let (num, den) = lmul.as_fraction();
Self((vlen_bits / sew_bits) * num / den)
}
#[inline(always)]
pub const fn as_usize(self) -> usize {
self.0
}
#[inline(always)]
pub const fn as_u64(self) -> u64 {
self.0 as u64
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Deserialize)]
#[serde(try_from = "usize")]
pub struct Vlen(usize);
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
#[error("VLEN must be a power of two in [128, 2048], got {0}")]
pub struct InvalidVlen(pub usize);
impl Default for Vlen {
fn default() -> Self {
Self::MIN
}
}
impl TryFrom<usize> for Vlen {
type Error = InvalidVlen;
fn try_from(bits: usize) -> Result<Self, InvalidVlen> {
Self::new(bits)
}
}
impl Vlen {
pub const MIN: Self = Self(128);
pub const MAX: Self = Self(2048);
pub const fn new(val: usize) -> Result<Self, InvalidVlen> {
if !val.is_power_of_two() || val < Self::MIN.0 || val > Self::MAX.0 {
return Err(InvalidVlen(val));
}
Ok(Self(val))
}
pub const fn new_unchecked(val: usize) -> Self {
Self(val)
}
#[inline(always)]
pub const fn bits(self) -> usize {
self.0
}
#[inline(always)]
pub const fn bytes(self) -> usize {
self.0 / 8
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_vlmax_computation() {
let vlen = Vlen::new_unchecked(128);
assert_eq!(Vlmax::compute(vlen, Sew::E8, Vlmul::M1).as_usize(), 16);
assert_eq!(Vlmax::compute(vlen, Sew::E32, Vlmul::M1).as_usize(), 4);
assert_eq!(Vlmax::compute(vlen, Sew::E8, Vlmul::M8).as_usize(), 128);
assert_eq!(Vlmax::compute(vlen, Sew::E64, Vlmul::Mf8).as_usize(), 0);
let vlen256 = Vlen::new_unchecked(256);
assert_eq!(Vlmax::compute(vlen256, Sew::E32, Vlmul::M2).as_usize(), 16);
}
#[test]
fn test_vlen_validation() {
assert!(Vlen::new(128).is_ok());
assert!(Vlen::new(256).is_ok());
assert!(Vlen::new(2048).is_ok());
assert!(Vlen::new(64).is_err());
assert!(Vlen::new(100).is_err());
assert!(Vlen::new(4096).is_err());
}
}