use bit_field::BitField;
#[derive(Clone, Copy, Debug)]
pub struct FCSR {
bits: u32,
}
#[derive(Clone, Copy, Debug)]
pub struct Flags(u32);
#[derive(Clone, Copy, Debug)]
pub enum Flag {
NX = 0b00001,
UF = 0b00010,
OF = 0b00100,
DZ = 0b01000,
NV = 0b10000,
}
impl Flags {
#[inline]
pub fn nx(&self) -> bool {
self.0.get_bit(0)
}
#[inline]
pub fn uf(&self) -> bool {
self.0.get_bit(1)
}
#[inline]
pub fn of(&self) -> bool {
self.0.get_bit(2)
}
#[inline]
pub fn dz(&self) -> bool {
self.0.get_bit(3)
}
#[inline]
pub fn nv(&self) -> bool {
self.0.get_bit(4)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RoundingMode {
RoundToNearestEven = 0b000,
RoundTowardsZero = 0b001,
RoundDown = 0b010,
RoundUp = 0b011,
RoundToNearestMaxMagnitude = 0b100,
Invalid = 0b111,
}
impl FCSR {
#[inline]
pub fn bits(&self) -> u32 {
self.bits
}
#[inline]
pub fn fflags(&self) -> Flags {
Flags(self.bits.get_bits(0..5))
}
#[inline]
pub fn frm(&self) -> RoundingMode {
match self.bits.get_bits(5..8) {
0b000 => RoundingMode::RoundToNearestEven,
0b001 => RoundingMode::RoundTowardsZero,
0b010 => RoundingMode::RoundDown,
0b011 => RoundingMode::RoundUp,
0b100 => RoundingMode::RoundToNearestMaxMagnitude,
_ => RoundingMode::Invalid,
}
}
}
read_csr!(0x003);
write_csr!(0x003);
clear!(0x003);
#[inline]
pub fn read() -> FCSR {
FCSR {
bits: unsafe { _read() as u32 },
}
}
#[inline]
pub unsafe fn set_rounding_mode(frm: RoundingMode) {
let old = read();
let bits = ((frm as u32) << 5) | old.fflags().0;
_write(bits as usize);
}
#[inline]
pub unsafe fn clear_flags() {
let mask = 0b11111;
_clear(mask);
}
#[inline]
pub unsafe fn clear_flag(flag: Flag) {
_clear(flag as usize);
}