@@ -20,45 +20,70 @@ macro_rules! instruction {
20
20
#[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
21
21
unimplemented!( ) ;
22
22
}
23
- ) ;
23
+ )
24
24
}
25
25
26
26
instruction ! (
27
- /// `nop ` instruction wrapper
27
+ /// `NOP ` instruction wrapper
28
28
///
29
29
/// The `NOP` instruction does not change any architecturally visible state, except for
30
- /// advancing the pc and incrementing any applicable performance counters.
30
+ /// advancing the PC and incrementing any applicable performance counters.
31
31
///
32
32
/// This function generates a no-operation; it's useful to prevent delay loops from being
33
33
/// optimized away.
34
- , nop, "nop" , options( nomem, nostack) ) ;
34
+ , nop, "nop" , options( nomem, nostack, preserves_flags ) ) ;
35
35
36
36
instruction ! (
37
37
/// `WFI` instruction wrapper
38
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) ) ;
39
+ /// Provides a hint to the implementation that the current hart can be stalled until an
40
+ /// interrupt might need servicing. The WFI instruction is just a hint, and a legal
41
+ /// implementation is to implement WFI as a NOP.
42
+ ///
43
+ /// # Behavior
44
+ ///
45
+ /// - May cause the hart to enter a low-power state
46
+ /// - Will be interrupted by any enabled interrupt
47
+ /// - No guarantee of actual power savings (implementation-dependent)
48
+ , wfi, "wfi" , options( nomem, nostack, preserves_flags) ) ;
42
49
43
50
instruction ! (
44
51
/// `EBREAK` instruction wrapper
45
52
///
46
- /// Generates a breakpoint exception.
47
- , unsafe ebreak, "ebreak" , options( nomem, nostack) ) ;
53
+ /// Generates a breakpoint exception for use by debuggers.
54
+ ///
55
+ /// # Behavior
56
+ ///
57
+ /// When executed, this instruction causes a breakpoint exception to be raised,
58
+ /// which will typically be handled by a debugger or exception handler.
59
+ ///
60
+ /// # Safety
61
+ ///
62
+ /// This function is unsafe because it unconditionally generates an exception,
63
+ /// which can disrupt normal program flow. Only call this when you intend to
64
+ /// trigger a breakpoint.
65
+ , unsafe ebreak, "ebreak" , options( nomem, nostack, preserves_flags) ) ;
48
66
49
67
instruction ! (
50
68
/// `ECALL` instruction wrapper
51
69
///
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.
70
+ /// Generates an environment call exception for system services.
56
71
///
57
- /// # Note
72
+ /// # Behavior
58
73
///
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) ) ;
74
+ /// When executed in different privilege modes:
75
+ /// - U-mode: Generates environment-call-from-U-mode exception
76
+ /// - S-mode: Generates environment-call-from-S-mode exception
77
+ /// - M-mode: Generates environment-call-from-M-mode exception
78
+ ///
79
+ /// # Safety
80
+ ///
81
+ /// This function is unsafe because:
82
+ /// - It unconditionally generates an exception
83
+ /// - The stack pointer is **NOT** automatically saved/restored
84
+ /// - The exception handler is responsible for proper context management
85
+ /// - Improper use can crash the system
86
+ , unsafe ecall, "ecall" , options( nomem, nostack, preserves_flags) ) ;
62
87
63
88
instruction ! (
64
89
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
@@ -118,8 +143,8 @@ instruction!(
118
143
pub fn sfence_vma ( asid : usize , addr : usize ) {
119
144
#[ cfg( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ]
120
145
unsafe {
121
- core:: arch:: asm!( "sfence.vma {0 }, {1 }" , in( reg) addr, in( reg) asid, options( nostack) ) ;
122
- } ;
146
+ core:: arch:: asm!( "sfence.vma {}, {}" , in( reg) addr, in( reg) asid, options( nostack) ) ;
147
+ }
123
148
#[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
124
149
unimplemented ! ( ) ;
125
150
}
@@ -139,21 +164,19 @@ pub fn sfence_vma(asid: usize, addr: usize) {
139
164
allow( unused_variables)
140
165
) ]
141
166
pub fn delay ( cycles : u32 ) {
142
- match ( ) {
143
- #[ cfg( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ]
144
- ( ) => {
145
- let real_cyc = 1 + cycles / 2 ;
146
- unsafe {
147
- core:: arch:: asm!(
167
+ #[ cfg( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ]
168
+ {
169
+ let real_cyc = 1 + cycles / 2 ;
170
+ unsafe {
171
+ core:: arch:: asm!(
148
172
"2:" ,
149
173
"addi {0}, {0}, -1" ,
150
174
"bne {0}, zero, 2b" ,
151
175
inout( reg) real_cyc => _,
152
176
options( nomem, nostack) ,
153
- ) ;
154
- }
177
+ ) ;
155
178
}
156
- #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
157
- ( ) => unimplemented ! ( ) ,
158
179
}
180
+ #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
181
+ unimplemented ! ( ) ;
159
182
}
0 commit comments