11//! Assembly instructions
22
33macro_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+
4143instruction ! (
4244 /// `EBREAK` instruction wrapper
4345 ///
4446 /// Generates a breakpoint exception.
45- , unsafe ebreak, "ebreak" ) ;
47+ , unsafe ebreak, "ebreak" , options( nomem, nostack) ) ;
48+
4649instruction ! (
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+
5263instruction ! (
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+
6173instruction ! (
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+
7587instruction ! (
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+ ) ]
146141pub 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