use bit_field::BitField;
use riscv::{clear, read_csr_as, set, set_clear_csr, write_csr};
#[derive(Copy, Clone, Debug)]
pub struct Vsstatus {
bits: usize,
}
impl Vsstatus {
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
#[inline]
pub fn from_bits(x: usize) -> Self {
Vsstatus { bits: x }
}
#[inline]
pub unsafe fn write(&self) {
unsafe { _write(self.bits) };
}
#[inline]
pub fn sd(&self) -> usize {
self.bits.get_bits(60..64)
}
#[inline]
pub fn set_sd(&mut self, val: usize) {
self.bits.set_bits(60..64, val);
}
#[inline]
pub fn uxl(&self) -> UxlValues {
UxlValues::from(self.bits.get_bits(32..34))
}
#[inline]
pub fn set_uxl(&mut self, val: UxlValues) {
self.bits.set_bits(32..34, val as usize);
}
#[inline]
pub fn mxr(&self) -> bool {
self.bits.get_bit(19)
}
#[inline]
pub fn set_mxr(&mut self, val: bool) {
self.bits.set_bit(19, val);
}
#[inline]
pub fn sum(&self) -> bool {
self.bits.get_bit(18)
}
#[inline]
pub fn set_sum(&mut self, val: bool) {
self.bits.set_bit(18, val);
}
#[inline]
pub fn xs(&self) -> usize {
self.bits.get_bits(15..17)
}
#[inline]
pub fn set_xs(&mut self, val: usize) {
self.bits.set_bits(15..17, val);
}
#[inline]
pub fn fs(&self) -> usize {
self.bits.get_bits(13..15)
}
#[inline]
pub fn set_fs(&mut self, val: usize) {
self.bits.set_bits(13..15, val);
}
#[inline]
pub fn spp(&self) -> bool {
self.bits.get_bit(8)
}
#[inline]
pub fn set_spp(&mut self, val: bool) {
self.bits.set_bit(8, val);
}
#[inline]
pub fn ube(&self) -> bool {
self.bits.get_bit(6)
}
#[inline]
pub fn set_ube(&mut self, val: bool) {
self.bits.set_bit(6, val);
}
#[inline]
pub fn spie(&self) -> bool {
self.bits.get_bit(5)
}
#[inline]
pub fn set_spie(&mut self, val: bool) {
self.bits.set_bit(5, val);
}
#[inline]
pub fn sie(&self) -> bool {
self.bits.get_bit(1)
}
#[inline]
pub fn set_sie(&mut self, val: bool) {
self.bits.set_bit(1, val);
}
}
read_csr_as!(Vsstatus, 0x200);
write_csr!(0x200);
set!(0x200);
clear!(0x200);
set_clear_csr!(
, set_mxr, clear_mxr, 1 << 19);
set_clear_csr!(
, set_sum, clear_sum, 1 << 18);
set_clear_csr!(
, set_spp, clear_spp, 1 << 8);
set_clear_csr!(
, set_ube, clear_ube, 1 << 6);
set_clear_csr!(
, set_spie, clear_spie, 1 << 5);
set_clear_csr!(
, set_sie, clear_sie, 1 << 1);
#[derive(Copy, Clone, Debug)]
#[repr(usize)]
pub enum UxlValues {
Uxl32 = 1,
Uxl64 = 2,
Uxl128 = 3,
}
impl UxlValues {
fn from(x: usize) -> Self {
match x {
1 => Self::Uxl32,
2 => Self::Uxl64,
3 => Self::Uxl128,
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vsstatus_from_bits() {
let vsstatus = Vsstatus::from_bits(0x123456789ABCDEF0);
assert_eq!(vsstatus.bits(), 0x123456789ABCDEF0);
}
#[test]
fn test_vsstatus_sd() {
let mut vsstatus = Vsstatus::from_bits(0);
vsstatus.set_sd(0xA);
assert_eq!(vsstatus.sd(), 0xA);
assert_eq!(vsstatus.bits() & (0xF << 60), 0xA << 60);
vsstatus.set_sd(0);
assert_eq!(vsstatus.sd(), 0);
vsstatus.set_sd(0xF); assert_eq!(vsstatus.sd(), 0xF);
}
#[test]
fn test_vsstatus_uxl() {
let mut vsstatus = Vsstatus::from_bits(0);
vsstatus.set_uxl(UxlValues::Uxl32);
assert!(matches!(vsstatus.uxl(), UxlValues::Uxl32));
assert_eq!(vsstatus.bits() & (0b11 << 32), 1 << 32);
vsstatus.set_uxl(UxlValues::Uxl64);
assert!(matches!(vsstatus.uxl(), UxlValues::Uxl64));
assert_eq!(vsstatus.bits() & (0b11 << 32), 2 << 32);
vsstatus.set_uxl(UxlValues::Uxl128);
assert!(matches!(vsstatus.uxl(), UxlValues::Uxl128));
assert_eq!(vsstatus.bits() & (0b11 << 32), 3 << 32);
}
#[test]
fn test_vsstatus_boolean_fields() {
let mut vsstatus = Vsstatus::from_bits(0);
assert!(!vsstatus.mxr());
vsstatus.set_mxr(true);
assert!(vsstatus.mxr());
assert_eq!(vsstatus.bits() & (1 << 19), 1 << 19);
assert!(!vsstatus.sum());
vsstatus.set_sum(true);
assert!(vsstatus.sum());
assert_eq!(vsstatus.bits() & (1 << 18), 1 << 18);
assert!(!vsstatus.spp());
vsstatus.set_spp(true);
assert!(vsstatus.spp());
assert_eq!(vsstatus.bits() & (1 << 8), 1 << 8);
assert!(!vsstatus.ube());
vsstatus.set_ube(true);
assert!(vsstatus.ube());
assert_eq!(vsstatus.bits() & (1 << 6), 1 << 6);
assert!(!vsstatus.spie());
vsstatus.set_spie(true);
assert!(vsstatus.spie());
assert_eq!(vsstatus.bits() & (1 << 5), 1 << 5);
assert!(!vsstatus.sie());
vsstatus.set_sie(true);
assert!(vsstatus.sie());
assert_eq!(vsstatus.bits() & (1 << 1), 1 << 1);
}
#[test]
fn test_vsstatus_xs() {
let mut vsstatus = Vsstatus::from_bits(0);
vsstatus.set_xs(0x2);
assert_eq!(vsstatus.xs(), 0x2);
assert_eq!(vsstatus.bits() & (0b11 << 15), 0x2 << 15);
vsstatus.set_xs(0);
assert_eq!(vsstatus.xs(), 0);
vsstatus.set_xs(0x3); assert_eq!(vsstatus.xs(), 0x3);
}
#[test]
fn test_vsstatus_fs() {
let mut vsstatus = Vsstatus::from_bits(0);
vsstatus.set_fs(0x2);
assert_eq!(vsstatus.fs(), 0x2);
assert_eq!(vsstatus.bits() & (0b11 << 13), 0x2 << 13);
vsstatus.set_fs(0);
assert_eq!(vsstatus.fs(), 0);
vsstatus.set_fs(0x3); assert_eq!(vsstatus.fs(), 0x3);
}
#[test]
fn test_uxl_values_from() {
assert!(matches!(UxlValues::from(1), UxlValues::Uxl32));
assert!(matches!(UxlValues::from(2), UxlValues::Uxl64));
assert!(matches!(UxlValues::from(3), UxlValues::Uxl128));
}
#[test]
#[should_panic]
fn test_uxl_values_from_invalid() {
UxlValues::from(0);
}
#[test]
fn test_vsstatus_all_fields() {
let mut vsstatus = Vsstatus::from_bits(0);
vsstatus.set_sd(0xB);
vsstatus.set_uxl(UxlValues::Uxl64);
vsstatus.set_mxr(true);
vsstatus.set_sum(true);
vsstatus.set_xs(0x2);
vsstatus.set_fs(0x3);
vsstatus.set_spp(true);
vsstatus.set_ube(true);
vsstatus.set_spie(true);
vsstatus.set_sie(true);
assert_eq!(vsstatus.sd(), 0xB);
assert!(matches!(vsstatus.uxl(), UxlValues::Uxl64));
assert!(vsstatus.mxr());
assert!(vsstatus.sum());
assert_eq!(vsstatus.xs(), 0x2);
assert_eq!(vsstatus.fs(), 0x3);
assert!(vsstatus.spp());
assert!(vsstatus.ube());
assert!(vsstatus.spie());
assert!(vsstatus.sie());
}
#[test]
fn test_vsstatus_copy_clone() {
let vsstatus1 = Vsstatus::from_bits(0x123456789ABCDEF0);
let vsstatus2 = vsstatus1;
let vsstatus3 = vsstatus1.clone();
assert_eq!(vsstatus1.bits(), vsstatus2.bits());
assert_eq!(vsstatus1.bits(), vsstatus3.bits());
}
}