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