@@ -4,6 +4,9 @@ use syn::{parse_macro_input, DeriveInput};
44
55mod riscv;
66
7+ #[ cfg( feature = "riscv-rt" ) ]
8+ mod riscv_rt;
9+
710/// Attribute-like macro that implements the traits of the `riscv-types` crate for a given enum.
811///
912/// As these traits are unsafe, the macro must be called with the `unsafe` keyword followed by the trait name.
@@ -59,3 +62,185 @@ pub fn pac_enum(attr: TokenStream, item: TokenStream) -> TokenStream {
5962 }
6063 . into ( )
6164}
65+
66+ /// Attribute to mark which function will be called before jumping to the entry point.
67+ /// You must enable the `post-init` feature in the `riscv-rt` crate to use this macro.
68+ ///
69+ /// In contrast with `__pre_init`, this function is called after the static variables
70+ /// are initialized, so it is safe to access them. It is also safe to run Rust code.
71+ ///
72+ /// The function must have the signature of `[unsafe] fn([usize])`, where the argument
73+ /// corresponds to the hart ID of the current hart. This is useful for multi-hart systems
74+ /// to perform hart-specific initialization.
75+ ///
76+ /// # IMPORTANT
77+ ///
78+ /// This attribute can appear at most *once* in the dependency graph.
79+ ///
80+ /// # Examples
81+ ///
82+ /// ```
83+ /// #[riscv_macros::post_init]
84+ /// unsafe fn before_main(hart_id: usize) {
85+ /// // do something here
86+ /// }
87+ /// ```
88+ #[ cfg( feature = "riscv-rt" ) ]
89+ #[ proc_macro_attribute]
90+ pub fn post_init ( args : TokenStream , input : TokenStream ) -> TokenStream {
91+ riscv_rt:: Fn :: post_init ( args, input)
92+ }
93+
94+ /// Attribute to declare the entry point of the program
95+ ///
96+ /// The specified function will be called by the reset handler *after* RAM has been initialized.
97+ /// If present, the FPU will also be enabled before the function is called.
98+ ///
99+ /// # Signature
100+ ///
101+ /// ## Regular Usage
102+ ///
103+ /// The type of the specified function must be `[unsafe] fn([usize[, usize[, usize]]]) -> !` (never ending function).
104+ /// The optional arguments correspond to the values passed in registers `a0`, `a1`, and `a2`.
105+ /// The first argument holds the hart ID of the current hart, which is useful for multi-hart systems.
106+ /// The other two arguments are currently unused and reserved for future use.
107+ ///
108+ /// ## With U-Boot
109+ ///
110+ /// This runtime supports being booted by U-Boot. In this case, the entry point function
111+ /// must have the signature `[unsafe] fn([c_int[, *const *const c_char]]) -> !`, where the first argument
112+ /// corresponds to the `argc` parameter and the second argument corresponds to the `argv` parameter passed by U-Boot.
113+ ///
114+ /// Remember to enable the `u-boot` feature in the `riscv-rt` crate to use this functionality.
115+ ///
116+ /// # IMPORTANT
117+ ///
118+ /// This attribute can appear at most *once* in the dependency graph.
119+ ///
120+ /// The entry point will be called by the reset handler. The program can't reference to the entry
121+ /// point, much less invoke it.
122+ ///
123+ /// # Examples
124+ ///
125+ /// ``` no_run
126+ /// #[riscv_macros::entry]
127+ /// fn main() -> ! {
128+ /// loop {
129+ /// /* .. */
130+ /// }
131+ /// }
132+ /// ```
133+ #[ cfg( feature = "riscv-rt" ) ]
134+ #[ proc_macro_attribute]
135+ pub fn entry ( args : TokenStream , input : TokenStream ) -> TokenStream {
136+ riscv_rt:: Fn :: entry ( args, input)
137+ }
138+
139+ /// Attribute to declare an exception handler.
140+ ///
141+ /// The function must have the signature `[unsafe] fn([&[mut] riscv_rt::TrapFrame]) [-> !]`.
142+ ///
143+ /// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::ExceptionNumber` trait.
144+ ///
145+ /// # Example
146+ ///
147+ /// ``` ignore,no_run
148+ /// #[riscv_rt::exception(riscv::interrupt::Exception::LoadMisaligned)]
149+ /// fn load_misaligned(trap_frame: &mut riscv_rt::TrapFrame) -> ! {
150+ /// loop{};
151+ /// }
152+ /// ```
153+ #[ cfg( feature = "riscv-rt" ) ]
154+ #[ proc_macro_attribute]
155+ pub fn exception ( args : TokenStream , input : TokenStream ) -> TokenStream {
156+ riscv_rt:: Fn :: trap ( args, input, riscv_rt:: TrapType :: Exception )
157+ }
158+
159+ /// Attribute to declare a core interrupt handler.
160+ ///
161+ /// The function must have the signature `[unsafe] fn() [-> !]`.
162+ ///
163+ /// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::CoreInterruptNumber` trait.
164+ ///
165+ /// If the `v-trap` feature is enabled, this macro generates the corresponding interrupt trap handler in assembly.
166+ /// This feature relies on the `RISCV_RT_BASE_ISA` environment variable being set to one of
167+ /// `rv32i`, `rv32e`, `rv64i`, or `rv64e`. Otherwise, this will **panic**.
168+ ///
169+ /// # Example
170+ ///
171+ /// ``` ignore,no_run
172+ /// #[riscv_rt::core_interrupt(riscv::interrupt::Interrupt::SupervisorSoft)]
173+ /// fn supervisor_soft() -> ! {
174+ /// loop{};
175+ /// }
176+ /// ```
177+ #[ cfg( feature = "riscv-rt" ) ]
178+ #[ proc_macro_attribute]
179+ pub fn core_interrupt ( args : TokenStream , input : TokenStream ) -> TokenStream {
180+ riscv_rt:: Fn :: trap ( args, input, riscv_rt:: TrapType :: CoreInterrupt )
181+ }
182+
183+ /// Attribute to declare an external interrupt handler.
184+ ///
185+ /// The function must have the signature `[unsafe] fn() [-> !]`.
186+ ///
187+ /// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::ExternalInterruptNumber` trait.
188+ ///
189+ /// # Example
190+ ///
191+ /// ``` ignore,no_run
192+ /// #[riscv_rt::external_interrupt(e310x::interrupt::Interrupt::GPIO0)]
193+ /// fn gpio0() -> ! {
194+ /// loop{};
195+ /// }
196+ /// ```
197+ #[ cfg( feature = "riscv-rt" ) ]
198+ #[ proc_macro_attribute]
199+ pub fn external_interrupt ( args : TokenStream , input : TokenStream ) -> TokenStream {
200+ riscv_rt:: Fn :: trap ( args, input, riscv_rt:: TrapType :: ExternalInterrupt )
201+ }
202+
203+ /// Temporary patch macro to deal with LLVM bug.
204+ ///
205+ /// # Note
206+ ///
207+ /// This macro is intended to be used internally by the `riscv-rt` crate. Do not use it directly in your code.
208+ #[ cfg( feature = "riscv-rt" ) ]
209+ #[ proc_macro]
210+ pub fn rvrt_llvm_arch_patch ( _input : TokenStream ) -> TokenStream {
211+ let q = if let Ok ( arch) = std:: env:: var ( "RISCV_RT_LLVM_ARCH_PATCH" ) {
212+ let patch = format ! ( ".attribute arch,\" {arch}\" " ) ;
213+ quote ! { core:: arch:: global_asm!{ #patch} }
214+ } else {
215+ quote ! ( compile_error!( "RISCV_RT_LLVM_ARCH_PATCH is not set" ) )
216+ } ;
217+ q. into ( )
218+ }
219+
220+ /// Generates assembly code required for the default handling of traps.
221+ ///
222+ /// The main routine generated is `_default_start_trap`. If no `_start_trap` function
223+ /// is defined, the linker will use this function as the default trap entry point.
224+ ///
225+ /// If the `pre-default-start-trap` feature is enabled, the generated code will also
226+ /// include a call to a user-defined function `_pre_default_start_trap` at the beginning
227+ /// of the `_default_start_trap` routine.
228+ ///
229+ /// If the `rt-v-trap` feature is enabled, the macro will also include the assembly code
230+ /// for the `_start_DefaultInterrupt_trap` and `_continue_interrupt_trap` routines, which
231+ /// are required for handling core interrupts in vectored trap mode.
232+ ///
233+ /// # Note
234+ ///
235+ /// This macro is intended to be used internally by the `riscv-rt` crate. Do not use it directly in your code.
236+ #[ cfg( feature = "riscv-rt" ) ]
237+ #[ proc_macro]
238+ pub fn rvrt_default_start_trap ( _input : TokenStream ) -> TokenStream {
239+ match riscv_rt:: asm:: RiscvArch :: try_from_env ( ) {
240+ Some ( arch) => arch. default_start_trap ( ) . into ( ) ,
241+ None => quote ! {
242+ compile_error!( "RISCV_RT_BASE_ISA environment variable is not set or is invalid" ) ;
243+ }
244+ . into ( ) ,
245+ }
246+ }
0 commit comments