use crate::constants::*;
use core::arch::asm;
const FPCR_RMODE_SHIFT: u64 = 22;
const FPCR_RMODE_MASK: u64 = 0b11 << FPCR_RMODE_SHIFT;
const FPCR_FZ_BIT: u64 = 1 << 24;
fn read_fpcr() -> u64 {
let v: u64;
unsafe { asm!("mrs {}, FPCR", out(reg) v, options(nomem, nostack, preserves_flags)) };
v
}
fn write_fpcr(v: u64) {
unsafe { asm!("msr FPCR, {}", in(reg) v, options(nomem, nostack, preserves_flags)) };
}
#[inline]
pub fn _MM_GET_ROUNDING_MODE() -> u32 {
let rmode = (read_fpcr() & FPCR_RMODE_MASK) >> FPCR_RMODE_SHIFT;
match rmode {
0b00 => _MM_ROUND_NEAREST,
0b01 => _MM_ROUND_UP,
0b10 => _MM_ROUND_DOWN,
_ => _MM_ROUND_TOWARD_ZERO,
}
}
#[inline]
pub fn _MM_SET_ROUNDING_MODE(mode: u32) {
let rmode: u64 = match mode {
_MM_ROUND_NEAREST => 0b00,
_MM_ROUND_UP => 0b01,
_MM_ROUND_DOWN => 0b10,
_ => 0b11,
};
let fpcr = (read_fpcr() & !FPCR_RMODE_MASK) | (rmode << FPCR_RMODE_SHIFT);
write_fpcr(fpcr);
}
#[inline]
pub fn _MM_GET_FLUSH_ZERO_MODE() -> u32 {
if read_fpcr() & FPCR_FZ_BIT != 0 {
_MM_FLUSH_ZERO_ON
} else {
_MM_FLUSH_ZERO_OFF
}
}
#[inline]
pub fn _MM_SET_FLUSH_ZERO_MODE(mode: u32) {
let fpcr = read_fpcr();
let next = if mode == _MM_FLUSH_ZERO_ON {
fpcr | FPCR_FZ_BIT
} else {
fpcr & !FPCR_FZ_BIT
};
write_fpcr(next);
}
#[inline]
pub fn _MM_GET_DENORMALS_ZERO_MODE() -> u32 {
if read_fpcr() & FPCR_FZ_BIT != 0 {
_MM_DENORMALS_ZERO_ON
} else {
_MM_DENORMALS_ZERO_OFF
}
}
#[inline]
pub fn _MM_SET_DENORMALS_ZERO_MODE(mode: u32) {
let fpcr = read_fpcr();
let next = if mode == _MM_DENORMALS_ZERO_ON {
fpcr | FPCR_FZ_BIT
} else {
fpcr & !FPCR_FZ_BIT
};
write_fpcr(next);
}
#[inline]
pub fn _mm_getcsr() -> u32 {
_MM_GET_ROUNDING_MODE() | _MM_GET_FLUSH_ZERO_MODE() | _MM_GET_DENORMALS_ZERO_MODE()
}
#[inline]
pub fn _mm_setcsr(a: u32) {
_MM_SET_ROUNDING_MODE(a & _MM_ROUND_MASK);
let flush = (a & _MM_FLUSH_ZERO_MASK != 0) || (a & _MM_DENORMALS_ZERO_MASK != 0);
_MM_SET_FLUSH_ZERO_MODE(if flush {
_MM_FLUSH_ZERO_ON
} else {
_MM_FLUSH_ZERO_OFF
});
}