pub mod zve64x;
use crate::registers::general_purpose::{RegType, Register};
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum VsStatus {
Off = 0,
Initial = 1,
Clean = 2,
Dirty = 3,
}
impl VsStatus {
#[inline(always)]
pub const fn from_bits(bits: u8) -> Self {
match bits & 0b11 {
0 => Self::Off,
1 => Self::Initial,
2 => Self::Clean,
_ => Self::Dirty,
}
}
#[inline(always)]
pub const fn to_bits(self) -> u8 {
self as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Vlmul {
M1 = 0b000,
M2 = 0b001,
M4 = 0b010,
M8 = 0b011,
Mf8 = 0b101,
Mf4 = 0b110,
Mf2 = 0b111,
}
impl Vlmul {
#[inline(always)]
pub const fn from_bits(bits: u8) -> Option<Self> {
match bits & 0b111 {
0b000 => Some(Self::M1),
0b001 => Some(Self::M2),
0b010 => Some(Self::M4),
0b011 => Some(Self::M8),
0b101 => Some(Self::Mf8),
0b110 => Some(Self::Mf4),
0b111 => Some(Self::Mf2),
_ => None,
}
}
#[inline(always)]
pub const fn to_bits(self) -> u8 {
self as u8
}
#[inline(always)]
pub const fn vlmax(self, vlen_bits: u32, sew_bits: u32) -> u32 {
match self {
Self::M1 => vlen_bits / sew_bits,
Self::M2 => (vlen_bits * 2) / sew_bits,
Self::M4 => (vlen_bits * 4) / sew_bits,
Self::M8 => (vlen_bits * 8) / sew_bits,
Self::Mf2 => vlen_bits / (sew_bits * 2),
Self::Mf4 => vlen_bits / (sew_bits * 4),
Self::Mf8 => vlen_bits / (sew_bits * 8),
}
}
#[inline(always)]
pub const fn register_count(self) -> u8 {
match self {
Self::Mf8 | Self::Mf4 | Self::Mf2 | Self::M1 => 1,
Self::M2 => 2,
Self::M4 => 4,
Self::M8 => 8,
}
}
#[inline(always)]
pub const fn as_fraction(self) -> (u8, u8) {
match self {
Self::Mf8 => (1, 8),
Self::Mf4 => (1, 4),
Self::Mf2 => (1, 2),
Self::M1 => (1, 1),
Self::M2 => (2, 1),
Self::M4 => (4, 1),
Self::M8 => (8, 1),
}
}
#[inline(always)]
pub const fn index_register_count(self, index_eew: Eew, sew: Vsew) -> Option<u8> {
let (lmul_num, lmul_den) = self.as_fraction();
let num = u16::from(index_eew.bits()) * u16::from(lmul_num);
let den = u16::from(sew.bits()) * u16::from(lmul_den);
let g = if num < den { num } else { den };
let (n, d) = (num / g, den / g);
let legal = matches!(
(n, d),
(1, 8) | (1, 4) | (1, 2) | (1, 1) | (2, 1) | (4, 1) | (8, 1)
);
if !legal {
return None;
}
Some(if d > 1 { 1 } else { n as u8 })
}
#[inline(always)]
pub const fn data_register_count(self, eew: Eew, sew: Vsew) -> Option<u8> {
self.index_register_count(eew, sew)
}
}
impl fmt::Display for Vlmul {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::M1 => write!(f, "m1"),
Self::M2 => write!(f, "m2"),
Self::M4 => write!(f, "m4"),
Self::M8 => write!(f, "m8"),
Self::Mf8 => write!(f, "mf8"),
Self::Mf4 => write!(f, "mf4"),
Self::Mf2 => write!(f, "mf2"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Vsew {
E8 = 0b000,
E16 = 0b001,
E32 = 0b010,
E64 = 0b011,
}
impl Vsew {
#[inline(always)]
pub const fn from_bits(bits: u8) -> Option<Self> {
match bits & 0b111 {
0b000 => Some(Self::E8),
0b001 => Some(Self::E16),
0b010 => Some(Self::E32),
0b011 => Some(Self::E64),
_ => None,
}
}
#[inline(always)]
pub const fn to_bits(self) -> u8 {
self as u8
}
#[inline(always)]
pub const fn bits(self) -> u8 {
match self {
Self::E8 => 8,
Self::E16 => 16,
Self::E32 => 32,
Self::E64 => 64,
}
}
#[inline(always)]
pub const fn bytes(self) -> u8 {
match self {
Self::E8 => 1,
Self::E16 => 2,
Self::E32 => 4,
Self::E64 => 8,
}
}
#[inline(always)]
pub const fn as_eew(self) -> Eew {
match self {
Self::E8 => Eew::E8,
Self::E16 => Eew::E16,
Self::E32 => Eew::E32,
Self::E64 => Eew::E64,
}
}
}
impl fmt::Display for Vsew {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::E8 => write!(f, "e8"),
Self::E16 => write!(f, "e16"),
Self::E32 => write!(f, "e32"),
Self::E64 => write!(f, "e64"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Eew {
E8 = 0b000,
E16 = 0b101,
E32 = 0b110,
E64 = 0b111,
}
impl Eew {
pub const MAX_BYTES: u8 = 8;
#[inline(always)]
pub const fn from_width(width: u8) -> Option<Self> {
match width {
0b000 => Some(Self::E8),
0b101 => Some(Self::E16),
0b110 => Some(Self::E32),
0b111 => Some(Self::E64),
_ => None,
}
}
#[inline(always)]
pub const fn bits(self) -> u8 {
match self {
Self::E8 => 8,
Self::E16 => 16,
Self::E32 => 32,
Self::E64 => 64,
}
}
#[inline(always)]
pub const fn bytes(self) -> u8 {
match self {
Self::E8 => 1,
Self::E16 => 2,
Self::E32 => 4,
Self::E64 => 8,
}
}
}
impl fmt::Display for Eew {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.bits().fmt(f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Vxrm {
Rnu = 0b00,
Rne = 0b01,
Rdn = 0b10,
Rod = 0b11,
}
impl Vxrm {
#[inline(always)]
pub const fn from_bits(bits: u8) -> Self {
match bits & 0b11 {
0b00 => Self::Rnu,
0b01 => Self::Rne,
0b10 => Self::Rdn,
_ => Self::Rod,
}
}
#[inline(always)]
pub const fn to_bits(self) -> u8 {
self as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Vtype<const ELEN: u32, const VLEN: u32> {
vma: bool,
vta: bool,
vsew: Vsew,
vlmul: Vlmul,
}
impl<const ELEN: u32, const VLEN: u32> Vtype<ELEN, VLEN> {
pub const fn vma(&self) -> bool {
self.vma
}
pub const fn vta(&self) -> bool {
self.vta
}
pub const fn vsew(&self) -> Vsew {
self.vsew
}
pub const fn vlmul(&self) -> Vlmul {
self.vlmul
}
#[inline(always)]
pub const fn from_raw<Reg>(raw: Reg::Type) -> Option<Self>
where
Reg: [const] Register,
{
let raw = raw.as_u64();
if (raw >> 8) != 0 {
return None;
}
let vlmul_bits = (raw & 0b111) as u8;
let vsew_bits = ((raw >> 3) & 0b111) as u8;
let vta = ((raw >> 6) & 1) != 0;
let vma = ((raw >> 7) & 1) != 0;
let vlmul = Vlmul::from_bits(vlmul_bits)?;
let vsew = Vsew::from_bits(vsew_bits)?;
let sew = vsew.bits();
if u32::from(sew) > ELEN {
return None;
}
if vlmul.vlmax(VLEN, u32::from(sew)) == 0 {
return None;
}
Some(Self {
vma,
vta,
vsew,
vlmul,
})
}
#[inline(always)]
pub const fn to_raw<Reg>(self) -> Reg::Type
where
Reg: [const] Register,
{
let mut raw = 0u8;
raw |= self.vlmul.to_bits();
raw |= self.vsew.to_bits() << 3;
if self.vta {
raw |= 1 << 6;
}
if self.vma {
raw |= 1 << 7;
}
Reg::Type::from(raw)
}
#[inline(always)]
pub const fn illegal_raw<Reg>() -> Reg::Type
where
Reg: [const] Register,
{
let vill_bit = Reg::XLEN - 1;
Reg::Type::from(1u8) << vill_bit
}
}