Browse Source

Add fcsr register

Vadim Kaushan 6 years ago
parent
commit
4ad2150a24
3 changed files with 135 additions and 0 deletions
  1. 2 0
      asm.S
  2. 131 0
      src/register/fcsr.rs
  3. 2 0
      src/register/mod.rs

+ 2 - 0
asm.S

@@ -24,6 +24,8 @@ __sfence_vma:
     sfence.vma a0, a1
     ret
 
+REG_READ_WRITE(fcsr, 0x003)
+REG_SET_CLEAR(fcsr, 0x003)
 
 // M-mode registers
 REG_READ(mcause, 0x342)

+ 131 - 0
src/register/fcsr.rs

@@ -0,0 +1,131 @@
+//! 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
+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, __read_fcsr);
+write_csr!(0x003, __write_fcsr);
+clear!(0x003, __clear_fcsr);
+
+/// 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);
+}

+ 2 - 0
src/register/mod.rs

@@ -13,6 +13,8 @@
 #[macro_use]
 mod macros;
 
+pub mod fcsr;
+
 pub mod mcause;
 pub mod mcycle;
 pub mod mcycleh;