1
1
//! Assembly instructions
2
2
3
3
macro_rules! instruction {
4
- ( $( #[ $attr: meta] ) * , unsafe $fnname: ident, $asm: expr) => (
4
+ ( $( #[ $attr: meta] ) * , unsafe $fnname: ident, $asm: expr, $ ( $options : tt ) * ) => (
5
5
$( #[ $attr] ) *
6
- #[ inline]
6
+ #[ inline( always ) ]
7
7
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!( ) ;
15
12
}
16
13
) ;
17
- ( $( #[ $attr: meta] ) * , $fnname: ident, $asm: expr) => (
14
+ ( $( #[ $attr: meta] ) * , $fnname: ident, $asm: expr, $ ( $options : tt ) * ) => (
18
15
$( #[ $attr] ) *
19
- #[ inline]
16
+ #[ inline( always ) ]
20
17
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!( ) ;
28
22
}
29
23
) ;
30
24
}
@@ -37,18 +31,35 @@ instruction!(
37
31
///
38
32
/// This function generates a no-operation; it's useful to prevent delay loops from being
39
33
/// 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
+
41
43
instruction ! (
42
44
/// `EBREAK` instruction wrapper
43
45
///
44
46
/// Generates a breakpoint exception.
45
- , unsafe ebreak, "ebreak" ) ;
47
+ , unsafe ebreak, "ebreak" , options( nomem, nostack) ) ;
48
+
46
49
instruction ! (
47
- /// `WFI ` instruction wrapper
50
+ /// `ECALL ` instruction wrapper
48
51
///
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
+
52
63
instruction ! (
53
64
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
54
65
///
@@ -57,7 +68,8 @@ instruction!(
57
68
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
58
69
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
59
70
/// `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
+
61
73
instruction ! (
62
74
/// `FENCE` instruction wrapper
63
75
///
@@ -66,12 +78,12 @@ instruction!(
66
78
/// (O), memory reads (R), and memory writes (W) may be ordered with respect to any combination
67
79
/// of the same. Informally, no other RISC-V hart or external device can observe any operation in the
68
80
/// 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.
70
81
///
71
82
/// The FENCE instruction also orders memory reads and writes made by the hart as observed by
72
83
/// memory reads and writes made by an external device. However, FENCE does not order observations
73
84
/// of events made by an external device using any other signaling mechanism.
74
- , fence, "fence" ) ;
85
+ , fence, "fence" , options( nostack) ) ;
86
+
75
87
instruction ! (
76
88
/// `FENCE.I` instruction wrapper
77
89
///
@@ -89,7 +101,7 @@ instruction!(
89
101
/// The unused fields in the FENCE.I instruction, imm\[11:0\], rs1, and rd, are reserved for
90
102
/// finer-grain fences in future extensions. For forward compatibility, base
91
103
/// implementations shall ignore these fields, and standard software shall zero these fields.
92
- , fence_i, "fence.i" ) ;
104
+ , fence_i, "fence.i" , options ( nostack ) ) ;
93
105
94
106
/// `SFENCE.VMA` instruction wrapper
95
107
///
@@ -98,38 +110,18 @@ instruction!(
98
110
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
99
111
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
100
112
/// `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 ! ( ) ;
133
125
}
134
126
135
127
/// Blocks the program for *at least* `cycles` CPU cycles.
@@ -142,22 +134,26 @@ pub unsafe fn ecall() {
142
134
/// timer-less initialization of peripherals if and only if accurate timing is not essential. In
143
135
/// any other case please use a more accurate method to produce a delay.
144
136
#[ inline]
145
- #[ allow( unused_variables) ]
137
+ #[ cfg_attr(
138
+ not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ,
139
+ allow( unused_variables)
140
+ ) ]
146
141
pub fn delay ( cycles : u32 ) {
147
142
match ( ) {
148
- #[ cfg( riscv ) ]
149
- ( ) => unsafe {
143
+ #[ cfg( any ( target_arch = "riscv32" , target_arch = "riscv64" ) ) ]
144
+ ( ) => {
150
145
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" ) ) ) ]
161
157
( ) => unimplemented ! ( ) ,
162
158
}
163
159
}
0 commit comments