diff --git a/asm.S b/asm.S index 030dfd1..89890be 100644 --- a/asm.S +++ b/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) diff --git a/bin/riscv32imac-unknown-none-elf.a b/bin/riscv32imac-unknown-none-elf.a index 2346b0c..2bb3df2 100644 Binary files a/bin/riscv32imac-unknown-none-elf.a and b/bin/riscv32imac-unknown-none-elf.a differ diff --git a/bin/riscv32imc-unknown-none-elf.a b/bin/riscv32imc-unknown-none-elf.a index 2346b0c..2bb3df2 100644 Binary files a/bin/riscv32imc-unknown-none-elf.a and b/bin/riscv32imc-unknown-none-elf.a differ diff --git a/bin/riscv64gc-unknown-none-elf.a b/bin/riscv64gc-unknown-none-elf.a index 124ca14..a640944 100644 Binary files a/bin/riscv64gc-unknown-none-elf.a and b/bin/riscv64gc-unknown-none-elf.a differ diff --git a/bin/riscv64imac-unknown-none-elf.a b/bin/riscv64imac-unknown-none-elf.a index 124ca14..a640944 100644 Binary files a/bin/riscv64imac-unknown-none-elf.a and b/bin/riscv64imac-unknown-none-elf.a differ diff --git a/src/register/fcsr.rs b/src/register/fcsr.rs new file mode 100644 index 0000000..a6b2b13 --- /dev/null +++ b/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); +} diff --git a/src/register/mod.rs b/src/register/mod.rs index 47914b8..0c38e38 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -13,6 +13,8 @@ #[macro_use] mod macros; +pub mod fcsr; + pub mod mcause; pub mod mcycle; pub mod mcycleh;