@@ -20,45 +20,70 @@ macro_rules! instruction {
2020 #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
2121 unimplemented!( ) ;
2222 }
23- ) ;
23+ )
2424}
2525
2626instruction ! (
27- /// `nop ` instruction wrapper
27+ /// `NOP ` instruction wrapper
2828 ///
2929 /// 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.
3131 ///
3232 /// This function generates a no-operation; it's useful to prevent delay loops from being
3333 /// optimized away.
34- , nop, "nop" , options( nomem, nostack) ) ;
34+ , nop, "nop" , options( nomem, nostack, preserves_flags ) ) ;
3535
3636instruction ! (
3737 /// `WFI` instruction wrapper
3838 ///
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) ) ;
4249
4350instruction ! (
4451 /// `EBREAK` instruction wrapper
4552 ///
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) ) ;
4866
4967instruction ! (
5068 /// `ECALL` instruction wrapper
5169 ///
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.
5671 ///
57- /// # Note
72+ /// # Behavior
5873 ///
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) ) ;
6287
6388instruction ! (
6489 /// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
@@ -118,8 +143,8 @@ instruction!(
118143pub fn sfence_vma ( asid : usize , addr : usize ) {
119144 #[ cfg( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ]
120145 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+ }
123148 #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
124149 unimplemented ! ( ) ;
125150}
@@ -139,21 +164,19 @@ pub fn sfence_vma(asid: usize, addr: usize) {
139164 allow( unused_variables)
140165) ]
141166pub 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!(
148172 "2:" ,
149173 "addi {0}, {0}, -1" ,
150174 "bne {0}, zero, 2b" ,
151175 inout( reg) real_cyc => _,
152176 options( nomem, nostack) ,
153- ) ;
154- }
177+ ) ;
155178 }
156- #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
157- ( ) => unimplemented ! ( ) ,
158179 }
180+ #[ cfg( not( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) ) ]
181+ unimplemented ! ( ) ;
159182}
0 commit comments