Skip to content

Commit 60800c1

Browse files
Merge pull request #246 from rust-embedded/asm
`riscv`: align assembly functions with `cortex-m`
2 parents b3a42fd + 2ba1abf commit 60800c1

File tree

2 files changed

+70
-73
lines changed

2 files changed

+70
-73
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313

1414
### Changed
1515

16+
- Align assembly functions with `cortex-m`
1617
- Use CSR helper macros to define `marchid` register
1718
- Re-use `try_*` functions in `mcountinhibit`
1819
- Use CSR helper macros to define `mcause` register

riscv/src/asm.rs

Lines changed: 69 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
11
//! Assembly instructions
22
33
macro_rules! instruction {
4-
($(#[$attr:meta])*, unsafe $fnname:ident, $asm:expr) => (
4+
($(#[$attr:meta])*, unsafe $fnname:ident, $asm:expr, $($options:tt)*) => (
55
$(#[$attr])*
6-
#[inline]
6+
#[inline(always)]
77
pub unsafe fn $fnname() {
8-
match () {
9-
#[cfg(riscv)]
10-
() => core::arch::asm!($asm),
11-
12-
#[cfg(not(riscv))]
13-
() => unimplemented!(),
14-
}
8+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
9+
core::arch::asm!($asm, $($options)*);
10+
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
11+
unimplemented!();
1512
}
1613
);
17-
($(#[$attr:meta])*, $fnname:ident, $asm:expr) => (
14+
($(#[$attr:meta])*, $fnname:ident, $asm:expr, $($options:tt)*) => (
1815
$(#[$attr])*
19-
#[inline]
16+
#[inline(always)]
2017
pub fn $fnname() {
21-
match () {
22-
#[cfg(riscv)]
23-
() => unsafe { core::arch::asm!($asm) },
24-
25-
#[cfg(not(riscv))]
26-
() => unimplemented!(),
27-
}
18+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
19+
unsafe { core::arch::asm!($asm, $($options)*) };
20+
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
21+
unimplemented!();
2822
}
2923
);
3024
}
@@ -37,18 +31,35 @@ instruction!(
3731
///
3832
/// This function generates a no-operation; it's useful to prevent delay loops from being
3933
/// optimized away.
40-
, nop, "nop");
34+
, nop, "nop", options(nomem, nostack));
35+
36+
instruction!(
37+
/// `WFI` instruction wrapper
38+
///
39+
/// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.
40+
/// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP.
41+
, wfi, "wfi", options(nomem, nostack));
42+
4143
instruction!(
4244
/// `EBREAK` instruction wrapper
4345
///
4446
/// Generates a breakpoint exception.
45-
, unsafe ebreak, "ebreak");
47+
, unsafe ebreak, "ebreak", options(nomem, nostack));
48+
4649
instruction!(
47-
/// `WFI` instruction wrapper
50+
/// `ECALL` instruction wrapper
4851
///
49-
/// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.
50-
/// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP.
51-
, wfi, "wfi");
52+
/// Generates an exception for a service request to the execution environment.
53+
/// When executed in U-mode, S-mode, or M-mode, it generates an environment-call-from-U-mode
54+
/// exception, environment-call-from-S-mode exception, or environment-call-from-M-mode exception,
55+
/// respectively, and performs no other operation.
56+
///
57+
/// # Note
58+
///
59+
/// The ECALL instruction will **NOT** save and restore the stack pointer, as it triggers an exception.
60+
/// The stack pointer must be saved and restored accordingly by the exception handler.
61+
, unsafe ecall, "ecall", options(nomem, nostack));
62+
5263
instruction!(
5364
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
5465
///
@@ -57,7 +68,8 @@ instruction!(
5768
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
5869
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
5970
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
60-
, sfence_vma_all, "sfence.vma");
71+
, sfence_vma_all, "sfence.vma", options(nostack));
72+
6173
instruction!(
6274
/// `FENCE` instruction wrapper
6375
///
@@ -66,12 +78,12 @@ instruction!(
6678
/// (O), memory reads (R), and memory writes (W) may be ordered with respect to any combination
6779
/// of the same. Informally, no other RISC-V hart or external device can observe any operation in the
6880
/// successor set following a FENCE before any operation in the predecessor set preceding the FENCE.
69-
/// Chapter 17 provides a precise description of the RISC-V memory consistency model.
7081
///
7182
/// The FENCE instruction also orders memory reads and writes made by the hart as observed by
7283
/// memory reads and writes made by an external device. However, FENCE does not order observations
7384
/// of events made by an external device using any other signaling mechanism.
74-
, fence, "fence");
85+
, fence, "fence", options(nostack));
86+
7587
instruction!(
7688
/// `FENCE.I` instruction wrapper
7789
///
@@ -89,7 +101,7 @@ instruction!(
89101
/// The unused fields in the FENCE.I instruction, imm\[11:0\], rs1, and rd, are reserved for
90102
/// finer-grain fences in future extensions. For forward compatibility, base
91103
/// implementations shall ignore these fields, and standard software shall zero these fields.
92-
, fence_i, "fence.i");
104+
, fence_i, "fence.i", options(nostack));
93105

94106
/// `SFENCE.VMA` instruction wrapper
95107
///
@@ -98,38 +110,18 @@ instruction!(
98110
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
99111
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
100112
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
101-
#[inline]
102-
#[allow(unused_variables)]
103-
pub unsafe fn sfence_vma(asid: usize, addr: usize) {
104-
match () {
105-
#[cfg(riscv)]
106-
() => core::arch::asm!("sfence.vma {0}, {1}", in(reg) addr, in(reg) asid),
107-
108-
#[cfg(not(riscv))]
109-
() => unimplemented!(),
110-
}
111-
}
112-
113-
/// `ECALL` instruction wrapper
114-
///
115-
/// Generates an exception for a service request to the execution environment.
116-
/// When executed in U-mode, S-mode, or M-mode, it generates an environment-call-from-U-mode
117-
/// exception, environment-call-from-S-mode exception, or environment-call-from-M-mode exception,
118-
/// respectively, and performs no other operation.
119-
///
120-
/// # Note
121-
///
122-
/// The ECALL instruction will **NOT** save and restore the stack pointer, as it triggers an exception.
123-
/// The stack pointer must be saved and restored accordingly by the exception handler.
124-
#[inline]
125-
pub unsafe fn ecall() {
126-
match () {
127-
#[cfg(riscv)]
128-
() => core::arch::asm!("ecall", options(nostack)),
129-
130-
#[cfg(not(riscv))]
131-
() => unimplemented!(),
132-
}
113+
#[inline(always)]
114+
#[cfg_attr(
115+
not(any(target_arch = "riscv32", target_arch = "riscv64")),
116+
allow(unused_variables)
117+
)]
118+
pub fn sfence_vma(asid: usize, addr: usize) {
119+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
120+
unsafe {
121+
core::arch::asm!("sfence.vma {0}, {1}", in(reg) addr, in(reg) asid, options(nostack));
122+
};
123+
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
124+
unimplemented!();
133125
}
134126

135127
/// Blocks the program for *at least* `cycles` CPU cycles.
@@ -142,22 +134,26 @@ pub unsafe fn ecall() {
142134
/// timer-less initialization of peripherals if and only if accurate timing is not essential. In
143135
/// any other case please use a more accurate method to produce a delay.
144136
#[inline]
145-
#[allow(unused_variables)]
137+
#[cfg_attr(
138+
not(any(target_arch = "riscv32", target_arch = "riscv64")),
139+
allow(unused_variables)
140+
)]
146141
pub fn delay(cycles: u32) {
147142
match () {
148-
#[cfg(riscv)]
149-
() => unsafe {
143+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
144+
() => {
150145
let real_cyc = 1 + cycles / 2;
151-
core::arch::asm!(
152-
"2:",
153-
"addi {0}, {0}, -1",
154-
"bne {0}, zero, 2b",
155-
inout(reg) real_cyc => _,
156-
options(nomem, nostack),
157-
)
158-
},
159-
160-
#[cfg(not(riscv))]
146+
unsafe {
147+
core::arch::asm!(
148+
"2:",
149+
"addi {0}, {0}, -1",
150+
"bne {0}, zero, 2b",
151+
inout(reg) real_cyc => _,
152+
options(nomem, nostack),
153+
);
154+
}
155+
}
156+
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
161157
() => unimplemented!(),
162158
}
163159
}

0 commit comments

Comments
 (0)