|
@@ -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);
|
|
|
+}
|