x86_64/registers/
mxcsr.rs

1//! Functions to read and write MXCSR register.
2
3#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
4pub use self::x86_64::*;
5
6use bitflags::bitflags;
7
8bitflags! {
9    /// MXCSR register.
10    #[repr(transparent)]
11    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
12    pub struct MxCsr: u32 {
13        /// Invalid operation
14        const INVALID_OPERATION = 1 << 0;
15        /// Denormal
16        const DENORMAL = 1 << 1;
17        /// Divide-by-zero
18        const DIVIDE_BY_ZERO = 1 << 2;
19        /// Overflow
20        const OVERFLOW = 1 << 3;
21        /// Underflow
22        const UNDERFLOW = 1 << 4;
23        /// Precision
24        const PRECISION = 1 << 5;
25        /// Denormals are zeros
26        const DENORMALS_ARE_ZEROS = 1 << 6;
27        /// Invalid operation mask
28        const INVALID_OPERATION_MASK = 1 << 7;
29        /// Denormal mask
30        const DENORMAL_MASK = 1 << 8;
31        /// Divide-by-zero mask
32        const DIVIDE_BY_ZERO_MASK = 1 << 9;
33        /// Overflow mask
34        const OVERFLOW_MASK = 1 << 10;
35        /// Underflow mask
36        const UNDERFLOW_MASK = 1 << 11;
37        /// Precision mask
38        const PRECISION_MASK = 1 << 12;
39        /// Toward negative infinity
40        const ROUNDING_CONTROL_NEGATIVE = 1 << 13;
41        /// Toward positive infinity
42        const ROUNDING_CONTROL_POSITIVE = 1 << 14;
43        /// Toward zero (positive + negative)
44        const ROUNDING_CONTROL_ZERO = 3 << 13;
45        /// Flush to zero
46        const FLUSH_TO_ZERO = 1 << 15;
47    }
48}
49
50impl Default for MxCsr {
51    /// Return the default MXCSR value at reset, as documented in Intel SDM volume 2A.
52    #[inline]
53    fn default() -> Self {
54        MxCsr::INVALID_OPERATION_MASK
55            | MxCsr::DENORMAL_MASK
56            | MxCsr::DIVIDE_BY_ZERO_MASK
57            | MxCsr::OVERFLOW_MASK
58            | MxCsr::UNDERFLOW_MASK
59            | MxCsr::PRECISION_MASK
60    }
61}
62
63#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
64mod x86_64 {
65    use super::*;
66    use core::arch::asm;
67
68    /// Read the value of MXCSR.
69    #[inline]
70    pub fn read() -> MxCsr {
71        let mut mxcsr: u32 = 0;
72        unsafe {
73            asm!("stmxcsr [{}]", in(reg) &mut mxcsr, options(nostack, preserves_flags));
74        }
75        MxCsr::from_bits_truncate(mxcsr)
76    }
77
78    /// Write MXCSR.
79    #[inline]
80    pub fn write(mxcsr: MxCsr) {
81        unsafe {
82            asm!("ldmxcsr [{}]", in(reg) &mxcsr, options(nostack, readonly));
83        }
84    }
85
86    /// Update MXCSR.
87    #[inline]
88    pub fn update<F>(f: F)
89    where
90        F: FnOnce(&mut MxCsr),
91    {
92        let mut mxcsr = self::read();
93        f(&mut mxcsr);
94        self::write(mxcsr);
95    }
96
97    #[cfg(test)]
98    mod test {
99        use crate::registers::mxcsr::*;
100
101        #[test]
102        fn mxcsr_default() {
103            let mxcsr = read();
104            assert_eq!(mxcsr, MxCsr::from_bits_truncate(0x1F80));
105        }
106
107        #[test]
108        fn mxcsr_read() {
109            let mxcsr = read();
110            assert_eq!(mxcsr, MxCsr::default());
111        }
112
113        #[test]
114        fn mxcsr_write() {
115            let mxcsr = read();
116            write(mxcsr);
117            assert_eq!(mxcsr, read());
118        }
119    }
120}