macro_rules! instruction {
($(#[$attr:meta])*, unsafe $fnname:ident, $asm:expr, $($options:tt)*) => (
$(#[$attr])*
#[inline(always)]
pub unsafe fn $fnname() {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!($asm, $($options)*);
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
unimplemented!();
}
);
($(#[$attr:meta])*, $fnname:ident, $asm:expr, $($options:tt)*) => (
$(#[$attr])*
#[inline(always)]
pub fn $fnname() {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
unsafe { core::arch::asm!($asm, $($options)*) };
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
unimplemented!();
}
)
}
instruction!(
, nop, "nop", options(nomem, nostack, preserves_flags));
instruction!(
,wfi, "wfi", options(nomem, nostack, preserves_flags));
instruction!(
, unsafe ebreak, "ebreak", options(nomem, nostack, preserves_flags));
instruction!(
, unsafe ecall, "ecall", options(nomem, nostack, preserves_flags));
instruction!(
, sfence_vma_all, "sfence.vma", options(nostack));
instruction!(
, fence, "fence", options(nostack));
instruction!(
, fence_i, "fence.i", options(nostack));
#[inline(always)]
#[cfg_attr(
not(any(target_arch = "riscv32", target_arch = "riscv64")),
allow(unused_variables)
)]
pub fn sfence_vma(asid: usize, addr: usize) {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
unsafe {
core::arch::asm!("sfence.vma {}, {}", in(reg) addr, in(reg) asid, options(nostack));
}
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
unimplemented!();
}
#[inline]
#[cfg_attr(
not(any(target_arch = "riscv32", target_arch = "riscv64")),
allow(unused_variables)
)]
pub fn delay(cycles: u32) {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
{
let real_cyc = 1 + cycles / 2;
unsafe {
core::arch::asm!(
"2:",
"addi {0}, {0}, -1",
"bne {0}, zero, 2b",
inout(reg) real_cyc => _,
options(nomem, nostack),
);
}
}
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
unimplemented!();
}