1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Floating-point control and status register

use bit_field::BitField;

/// Floating-point control and status register
#[derive(Clone, Copy, Debug)]
pub struct FCSR {
    bits: u32,
}

/// Accrued Exception Flags
#[derive(Clone, Copy, Debug)]
pub struct Flags(u32);

/// Accrued Exception Flag
#[derive(Clone, Copy, Debug)]
pub enum Flag {
    /// Inexact
    NX = 0b00001,

    /// Underflow
    UF = 0b00010,

    /// Overflow
    OF = 0b00100,

    /// Divide by Zero
    DZ = 0b01000,

    /// Invalid Operation
    NV = 0b10000,
}

impl Flags {
    /// Inexact
    #[inline]
    pub fn nx(&self) -> bool {
        self.0.get_bit(0)
    }

    /// Underflow
    #[inline]
    pub fn uf(&self) -> bool {
        self.0.get_bit(1)
    }

    /// Overflow
    #[inline]
    pub fn of(&self) -> bool {
        self.0.get_bit(2)
    }

    /// Divide by Zero
    #[inline]
    pub fn dz(&self) -> bool {
        self.0.get_bit(3)
    }

    /// Invalid Operation
    #[inline]
    pub fn nv(&self) -> bool {
        self.0.get_bit(4)
    }
}

/// Rounding Mode
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RoundingMode {
    RoundToNearestEven = 0b000,
    RoundTowardsZero = 0b001,
    RoundDown = 0b010,
    RoundUp = 0b011,
    RoundToNearestMaxMagnitude = 0b100,
    Invalid = 0b111,
}

impl FCSR {
    /// Returns the contents of the register as raw bits
    pub fn bits(&self) -> u32 {
        self.bits
    }

    /// Accrued Exception Flags
    #[inline]
    pub fn fflags(&self) -> Flags {
        Flags(self.bits.get_bits(0..5))
    }

    /// Rounding Mode
    #[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);

/// Reads the CSR
#[inline]
pub fn read() -> FCSR {
    FCSR {
        bits: unsafe { _read() as u32 },
    }
}

/// Writes the CSR
#[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);
}

/// Resets `fflags` field bits
#[inline]
pub unsafe fn clear_flags() {
    let mask = 0b11111;
    _clear(mask);
}

/// Resets `fflags` field bit
#[inline]
pub unsafe fn clear_flag(flag: Flag) {
    _clear(flag as usize);
}