Skip to content

Commit

Permalink
riscv: add fallible functions to register macros
Browse files Browse the repository at this point in the history
Adds fallible `try_` function variants to most `register` module macros.
  • Loading branch information
rmsyn committed Jun 28, 2024
1 parent 0f3b9b2 commit 573a8a5
Showing 1 changed file with 270 additions and 0 deletions.
270 changes: 270 additions & 0 deletions riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ macro_rules! read_csr {
() => unimplemented!(),
}
}

/// Attempts to read the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
unsafe fn _try_read() -> $crate::result::Result<usize> {
match () {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
() => {
let r: usize;
core::arch::asm!(concat!("csrrs {0}, ", stringify!($csr_number), ", x0"), out(reg) r);
Ok(r)
}

#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -47,6 +65,24 @@ macro_rules! read_csr_rv32 {
() => unimplemented!(),
}
}

/// Attempts to read the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
unsafe fn _try_read() -> $crate::result::Result<usize> {
match () {
#[cfg(target_arch = "riscv32")]
() => {
let r: usize;
core::arch::asm!(concat!("csrrs {0}, ", stringify!($csr_number), ", x0"), out(reg) r);
Ok(r)
}

#[cfg(not(target_arch = "riscv32"))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -65,6 +101,16 @@ macro_rules! read_csr_as {
bits: unsafe { _read() },
}
}

/// Attempts to reads the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
pub fn try_read() -> $crate::result::Result<$register> {
Ok($register {
bits: unsafe { _try_read()? },
})
}
};
}

Expand All @@ -83,6 +129,16 @@ macro_rules! read_csr_as_rv32 {
bits: unsafe { _read() },
}
}

/// Attempts to reads the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
pub fn try_read() -> $crate::result::Result<$register> {
Ok($register {
bits: unsafe { _try_read()? },
})
}
};
}

Expand All @@ -97,6 +153,14 @@ macro_rules! read_csr_as_usize {
pub fn read() -> usize {
unsafe { _read() }
}

/// Attempts to read the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
pub fn try_read() -> $crate::result::Result<usize> {
unsafe { _try_read() }
}
};
}

Expand All @@ -111,6 +175,14 @@ macro_rules! read_csr_as_usize_rv32 {
pub fn read() -> usize {
unsafe { _read() }
}

/// Attempts to reads the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
pub fn try_read() -> $crate::result::Result<usize> {
unsafe { _try_read() }
}
};
}

Expand All @@ -134,6 +206,24 @@ macro_rules! write_csr {
() => unimplemented!(),
}
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_write(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
() => {
core::arch::asm!(concat!("csrrw x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -157,6 +247,24 @@ macro_rules! write_csr_rv32 {
() => unimplemented!(),
}
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_write(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(target_arch = "riscv32")]
() => {
core::arch::asm!(concat!("csrrw x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(target_arch = "riscv32"))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -171,6 +279,14 @@ macro_rules! write_csr_as {
pub fn write(value: $csr_type) {
unsafe { _write(value.bits) }
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
pub fn try_write(value: $csr_type) -> $crate::result::Result<()> {
unsafe { _try_write(value.bits) }
}
};
}

Expand All @@ -185,6 +301,14 @@ macro_rules! write_csr_as_rv32 {
pub fn write(value: $csr_type) {
unsafe { _write(value.bits) }
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
pub fn try_write(value: $csr_type) -> $crate::result::Result<()> {
unsafe { _try_write(value.bits) }
}
};
}

Expand All @@ -199,6 +323,14 @@ macro_rules! write_csr_as_usize {
pub fn write(bits: usize) {
unsafe { _write(bits) }
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
pub fn try_write(bits: usize) -> $crate::result::Result<()> {
unsafe { _try_write(bits) }
}
};
}

Expand All @@ -213,6 +345,14 @@ macro_rules! write_csr_as_usize_rv32 {
pub fn write(bits: usize) {
unsafe { _write(bits) }
}

/// Attempts to write the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
pub fn try_write(bits: usize) -> $crate::result::Result<()> {
unsafe { _try_write(bits) }
}
};
}

Expand All @@ -234,6 +374,24 @@ macro_rules! set {
() => unimplemented!(),
}
}

/// Attempts to set the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_set(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
() => {
core::arch::asm!(concat!("csrrs x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -255,6 +413,24 @@ macro_rules! set_rv32 {
() => unimplemented!(),
}
}

/// Attempts to set the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_set(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(target_arch = "riscv32")]
() => {
core::arch::asm!(concat!("csrrs x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(target_arch = "riscv32"))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -276,6 +452,24 @@ macro_rules! clear {
() => unimplemented!(),
}
}

/// Attempts to clear the CSR.
///
/// Only implemented for `riscv32` and `riscv64` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_clear(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
() => {
core::arch::asm!(concat!("csrrc x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand All @@ -297,6 +491,23 @@ macro_rules! clear_rv32 {
() => unimplemented!(),
}
}
/// Attempts to clear the CSR.
///
/// Only implemented for `riscv32` targets.
#[inline]
#[allow(unused_variables)]
unsafe fn _try_clear(bits: usize) -> $crate::result::Result<()> {
match () {
#[cfg(target_arch = "riscv32")]
() => {
core::arch::asm!(concat!("csrrc x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
Ok(())
}

#[cfg(not(target_arch = "riscv32"))]
() => Err($crate::result::Error::Unimplemented),
}
}
};
}

Expand Down Expand Up @@ -377,6 +588,39 @@ macro_rules! set_pmp {
value |= byte << (8 * index);
_write(value);
}

/// Attempts to set the pmp configuration corresponding to the index.
///
/// Returns an error if the index is invalid.
#[inline]
pub unsafe fn try_set_pmp(
index: usize,
range: Range,
permission: Permission,
locked: bool,
) -> $crate::result::Result<()> {
let max = if cfg!(target_arch = "riscv32") {
Ok(4usize)
} else if cfg!(target_arch = "riscv64") {
Ok(8usize)
} else {
Err($crate::result::Error::Unimplemented)
}?;

if index < max {
let mut value = _try_read()?;
value &= !(0xFF << (8 * index)); // clear previous value
let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize);
value |= byte << (8 * index);
_try_write(value)
} else {
Err($crate::result::Error::OutOfBounds {
index,
min: 0,
max: max - 1,
})
}
}
};
}

Expand All @@ -395,5 +639,31 @@ macro_rules! clear_pmp {
value &= !(0xFF << (8 * index)); // clear previous value
_write(value);
}

/// Attempts to clear the pmp configuration corresponding to the index.
///
/// Returns an error if the index is invalid.
#[inline]
pub unsafe fn try_clear_pmp(index: usize) -> $crate::result::Result<()> {
let max = if cfg!(target_arch = "riscv32") {
Ok(4usize)
} else if cfg!(target_arch = "riscv64") {
Ok(8usize)
} else {
Err($crate::result::Error::Unimplemented)
}?;

if index < max {
let mut value = _try_read()?;
value &= !(0xFF << (8 * index)); // clear previous value
_try_write(value)
} else {
Err($crate::result::Error::OutOfBounds {
index,
min: 0,
max: max - 1,
})
}
}
};
}

0 comments on commit 573a8a5

Please sign in to comment.