use bit_field::BitField;
use riscv::{clear, read_csr_as, set, set_clear_csr, write_csr};
#[derive(Copy, Clone, Debug)]
pub struct Hstatus {
bits: usize,
}
impl Hstatus {
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
#[inline]
pub fn from_bits(x: usize) -> Self {
Hstatus { bits: x }
}
#[inline]
pub unsafe fn write(&self) {
unsafe { _write(self.bits) };
}
#[inline]
pub fn vsxl(&self) -> VsxlValues {
VsxlValues::from(self.bits.get_bits(32..34))
}
#[inline]
pub fn set_vsxl(&mut self, val: VsxlValues) {
self.bits.set_bits(32..34, val as usize);
}
#[inline]
pub fn vtsr(&self) -> bool {
self.bits.get_bit(22)
}
#[inline]
pub fn set_vtsr(&mut self, val: bool) {
self.bits.set_bit(22, val);
}
#[inline]
pub fn vtw(&self) -> bool {
self.bits.get_bit(21)
}
#[inline]
pub fn set_vtw(&mut self, val: bool) {
self.bits.set_bit(21, val);
}
#[inline]
pub fn vtvm(&self) -> bool {
self.bits.get_bit(20)
}
#[inline]
pub fn set_vtvm(&mut self, val: bool) {
self.bits.set_bit(20, val);
}
#[inline]
pub fn vgein(&self) -> usize {
self.bits.get_bits(12..18)
}
#[inline]
pub fn set_vgein(&mut self, val: usize) {
self.bits.set_bits(12..18, val);
}
#[inline]
pub fn hu(&self) -> bool {
self.bits.get_bit(9)
}
#[inline]
pub fn set_hu(&mut self, val: bool) {
self.bits.set_bit(9, val);
}
#[inline]
pub fn spvp(&self) -> bool {
self.bits.get_bit(8)
}
#[inline]
pub fn set_spvp(&mut self, val: bool) {
self.bits.set_bit(8, val);
}
#[inline]
pub fn spv(&self) -> bool {
self.bits.get_bit(7)
}
#[inline]
pub fn set_spv(&mut self, val: bool) {
self.bits.set_bit(7, val);
}
#[inline]
pub fn gva(&self) -> bool {
self.bits.get_bit(6)
}
#[inline]
pub fn set_gva(&mut self, val: bool) {
self.bits.set_bit(6, val);
}
#[inline]
pub fn vsbe(&self) -> bool {
self.bits.get_bit(5)
}
#[inline]
pub fn set_vsbe(&mut self, val: bool) {
self.bits.set_bit(5, val);
}
}
read_csr_as!(Hstatus, 0x600);
write_csr!(0x600);
set!(0x600);
clear!(0x600);
set_clear_csr!(
, set_vtsr, clear_vtsr, 1 << 22);
set_clear_csr!(
, set_vtw, clear_vtw, 1 << 21);
set_clear_csr!(
, set_vtvm, clear_vtvm, 1 << 20);
set_clear_csr!(
, set_hu, clear_hu, 1 << 9);
set_clear_csr!(
, set_spvp, clear_spvp, 1 << 8);
set_clear_csr!(
, set_spv, clear_spv, 1 << 7);
set_clear_csr!(
, set_gva, clear_gva, 1 << 6);
set_clear_csr!(
, set_vsbe, clear_vsbe, 1 << 5);
#[derive(Copy, Clone, Debug)]
#[repr(usize)]
pub enum VsxlValues {
Vsxl32 = 1,
Vsxl64 = 2,
Vsxl128 = 3,
}
impl VsxlValues {
fn from(x: usize) -> Self {
match x {
1 => Self::Vsxl32,
2 => Self::Vsxl64,
3 => Self::Vsxl128,
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hstatus_from_bits() {
let hstatus = Hstatus::from_bits(0x12345678);
assert_eq!(hstatus.bits(), 0x12345678);
}
#[test]
fn test_hstatus_vsxl() {
let mut hstatus = Hstatus::from_bits(0);
hstatus.set_vsxl(VsxlValues::Vsxl32);
assert_eq!(hstatus.vsxl() as usize, 1);
assert_eq!(hstatus.bits() & (0b11 << 32), 1 << 32);
hstatus.set_vsxl(VsxlValues::Vsxl64);
assert_eq!(hstatus.vsxl() as usize, 2);
assert_eq!(hstatus.bits() & (0b11 << 32), 2 << 32);
hstatus.set_vsxl(VsxlValues::Vsxl128);
assert_eq!(hstatus.vsxl() as usize, 3);
assert_eq!(hstatus.bits() & (0b11 << 32), 3 << 32);
}
#[test]
fn test_hstatus_boolean_fields() {
let mut hstatus = Hstatus::from_bits(0);
assert!(!hstatus.vtsr());
hstatus.set_vtsr(true);
assert!(hstatus.vtsr());
assert_eq!(hstatus.bits() & (1 << 22), 1 << 22);
hstatus.set_vtsr(false);
assert!(!hstatus.vtsr());
assert_eq!(hstatus.bits() & (1 << 22), 0);
assert!(!hstatus.vtw());
hstatus.set_vtw(true);
assert!(hstatus.vtw());
assert_eq!(hstatus.bits() & (1 << 21), 1 << 21);
assert!(!hstatus.vtvm());
hstatus.set_vtvm(true);
assert!(hstatus.vtvm());
assert_eq!(hstatus.bits() & (1 << 20), 1 << 20);
assert!(!hstatus.hu());
hstatus.set_hu(true);
assert!(hstatus.hu());
assert_eq!(hstatus.bits() & (1 << 9), 1 << 9);
assert!(!hstatus.spvp());
hstatus.set_spvp(true);
assert!(hstatus.spvp());
assert_eq!(hstatus.bits() & (1 << 8), 1 << 8);
assert!(!hstatus.spv());
hstatus.set_spv(true);
assert!(hstatus.spv());
assert_eq!(hstatus.bits() & (1 << 7), 1 << 7);
assert!(!hstatus.gva());
hstatus.set_gva(true);
assert!(hstatus.gva());
assert_eq!(hstatus.bits() & (1 << 6), 1 << 6);
assert!(!hstatus.vsbe());
hstatus.set_vsbe(true);
assert!(hstatus.vsbe());
assert_eq!(hstatus.bits() & (1 << 5), 1 << 5);
}
#[test]
fn test_hstatus_vgein() {
let mut hstatus = Hstatus::from_bits(0);
hstatus.set_vgein(0x15); assert_eq!(hstatus.vgein(), 0x15);
assert_eq!(hstatus.bits() & (0x3F << 12), 0x15 << 12);
hstatus.set_vgein(0);
assert_eq!(hstatus.vgein(), 0);
hstatus.set_vgein(0x3F); assert_eq!(hstatus.vgein(), 0x3F);
assert_eq!(hstatus.bits() & (0x3F << 12), 0x3F << 12);
}
#[test]
fn test_vsxl_values_from() {
assert!(matches!(VsxlValues::from(1), VsxlValues::Vsxl32));
assert!(matches!(VsxlValues::from(2), VsxlValues::Vsxl64));
assert!(matches!(VsxlValues::from(3), VsxlValues::Vsxl128));
}
#[test]
#[should_panic]
fn test_vsxl_values_from_invalid() {
VsxlValues::from(0);
}
#[test]
fn test_hstatus_multiple_fields() {
let mut hstatus = Hstatus::from_bits(0);
hstatus.set_vtsr(true);
hstatus.set_vgein(0x2A);
hstatus.set_hu(true);
hstatus.set_vsxl(VsxlValues::Vsxl64);
assert!(hstatus.vtsr());
assert_eq!(hstatus.vgein(), 0x2A);
assert!(hstatus.hu());
assert!(matches!(hstatus.vsxl(), VsxlValues::Vsxl64));
let expected_bits = (1 << 22) | (0x2A << 12) | (1 << 9) | (2 << 32);
assert_eq!(hstatus.bits(), expected_bits);
}
#[test]
fn test_hstatus_copy_clone() {
let hstatus1 = Hstatus::from_bits(0x12345678);
let hstatus2 = hstatus1;
let hstatus3 = hstatus1.clone();
assert_eq!(hstatus1.bits(), hstatus2.bits());
assert_eq!(hstatus1.bits(), hstatus3.bits());
}
}