| 
270 | 270 | //! ### Core exception handlers  | 
271 | 271 | //!  | 
272 | 272 | //! This functions are called when corresponding exception occurs.  | 
273 |  | -//! You can define an exception handler with one of the following names:  | 
274 |  | -//! * `InstructionMisaligned`  | 
275 |  | -//! * `InstructionFault`  | 
276 |  | -//! * `IllegalInstruction`  | 
277 |  | -//! * `Breakpoint`  | 
278 |  | -//! * `LoadMisaligned`  | 
279 |  | -//! * `LoadFault`  | 
280 |  | -//! * `StoreMisaligned`  | 
281 |  | -//! * `StoreFault`  | 
282 |  | -//! * `UserEnvCall`  | 
283 |  | -//! * `SupervisorEnvCall`  | 
284 |  | -//! * `MachineEnvCall`  | 
285 |  | -//! * `InstructionPageFault`  | 
286 |  | -//! * `LoadPageFault`  | 
287 |  | -//! * `StorePageFault`  | 
 | 273 | +//! You can define an exception handler with the [`exception`] attribute.  | 
 | 274 | +//! The attribute expects the path to the exception source as an argument.  | 
 | 275 | +//!  | 
 | 276 | +//! The [`exception`] attribute ensures at compile time that there is a valid  | 
 | 277 | +//! exception source for the given handler.  | 
288 | 278 | //!  | 
289 | 279 | //! For example:  | 
290 | 280 | //! ``` no_run  | 
291 |  | -//! #[export_name = "MachineEnvCall"]  | 
292 |  | -//! fn custom_menv_call_handler(trap_frame: &riscv_rt::TrapFrame) {  | 
293 |  | -//!     // ...  | 
 | 281 | +//! use riscv::interrupt::Exception; // or a target-specific exception enum  | 
 | 282 | +//!  | 
 | 283 | +//! #[riscv_rt::exception(Exception::MachineEnvCall)]  | 
 | 284 | +//! fn custom_menv_call_handler(trap_frame: &mut riscv_rt::TrapFrame) {  | 
 | 285 | +//!     todo!()  | 
294 | 286 | //! }  | 
295 |  | -//! ```  | 
296 |  | -//! or  | 
297 |  | -//! ``` no_run  | 
298 |  | -//! #[no_mangle]  | 
299 |  | -//! fn MachineEnvCall(trap_frame: &riscv_rt::TrapFrame) -> ! {  | 
300 |  | -//!     // ...  | 
 | 287 | +//!  | 
 | 288 | +//! #[riscv_rt::exception(Exception::LoadFault)]  | 
 | 289 | +//! fn custom_load_fault_handler() -> ! {  | 
 | 290 | +//!     loop {}  | 
301 | 291 | //! }  | 
302 | 292 | //! ```  | 
303 | 293 | //!  | 
 | 
320 | 310 | //! or  | 
321 | 311 | //! ``` no_run  | 
322 | 312 | //! #[no_mangle]  | 
323 |  | -//! fn ExceptionHandler(trap_frame: &riscv_rt::TrapFrame) -> ! {  | 
 | 313 | +//! fn ExceptionHandler(trap_frame: &mut riscv_rt::TrapFrame) {  | 
324 | 314 | //!     // ...  | 
325 | 315 | //! }  | 
326 | 316 | //! ```  | 
327 | 317 | //!  | 
328 | 318 | //! Default implementation of this function stucks in a busy-loop.  | 
329 | 319 | //!  | 
330 |  | -//!  | 
331 | 320 | //! ### Core interrupt handlers  | 
332 | 321 | //!  | 
333 | 322 | //! This functions are called when corresponding interrupt is occured.  | 
334 |  | -//! You can define an interrupt handler with one of the following names:  | 
335 |  | -//! * `SupervisorSoft`  | 
336 |  | -//! * `MachineSoft`  | 
337 |  | -//! * `SupervisorTimer`  | 
338 |  | -//! * `MachineTimer`  | 
339 |  | -//! * `SupervisorExternal`  | 
340 |  | -//! * `MachineExternal`  | 
 | 323 | +//! You can define a core interrupt handler with the [`core_interrupt`] attribute.  | 
 | 324 | +//! The attribute expects the path to the interrupt source as an argument.  | 
 | 325 | +//!  | 
 | 326 | +//! The [`core_interrupt`] attribute ensures at compile time that there is a valid  | 
 | 327 | +//! core interrupt source for the given handler.  | 
341 | 328 | //!  | 
342 | 329 | //! For example:  | 
343 | 330 | //! ``` no_run  | 
344 |  | -//! #[export_name = "MachineTimer"]  | 
345 |  | -//! fn custom_timer_handler() {  | 
346 |  | -//!     // ...  | 
 | 331 | +//! use riscv::interrupt::Interrupt; // or a target-specific core interrupt enum  | 
 | 332 | +//!  | 
 | 333 | +//! #[riscv_rt::core_interrupt(Interrupt::MachineSoft)]  | 
 | 334 | +//! unsafe fn custom_machine_soft_handler() {  | 
 | 335 | +//!     todo!()  | 
347 | 336 | //! }  | 
348 |  | -//! ```  | 
349 |  | -//! or  | 
350 |  | -//! ``` no_run  | 
351 |  | -//! #[no_mangle]  | 
352 |  | -//! fn MachineTimer() {  | 
353 |  | -//!     // ...  | 
 | 337 | +//!  | 
 | 338 | +//! #[riscv_rt::core_interrupt(Interrupt::MachineTimer)]  | 
 | 339 | +//! fn custom_machine_timer_handler() -> ! {  | 
 | 340 | +//!     loop {}  | 
354 | 341 | //! }  | 
355 | 342 | //! ```  | 
356 | 343 | //!  | 
357 |  | -//! You can also use the `#[interrupt]` macro to define interrupt handlers:  | 
 | 344 | +//! In vectored mode, this macro will also generate a proper trap handler for the interrupt.  | 
358 | 345 | //!  | 
359 |  | -//! ``` no_run  | 
360 |  | -//! #[riscv_rt::interrupt]  | 
361 |  | -//! fn MachineTimer() {  | 
362 |  | -//!    // ...  | 
363 |  | -//! }  | 
364 |  | -//! ```  | 
 | 346 | +//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.  | 
 | 347 | +//!  | 
 | 348 | +//! ### External interrupt handlers  | 
 | 349 | +//!  | 
 | 350 | +//! This functions are called when corresponding interrupt is occured.  | 
 | 351 | +//! You can define an external interrupt handler with the [`external_interrupt`] attribute.  | 
 | 352 | +//! The attribute expects the path to the interrupt source as an argument.  | 
365 | 353 | //!  | 
366 |  | -//! In direct mode, this macro is equivalent to defining a function with the same name.  | 
367 |  | -//! However, in vectored mode, this macro will generate a proper trap handler for the interrupt.  | 
 | 354 | +//! The [`external_interrupt`] attribute ensures at compile time that there is a valid  | 
 | 355 | +//! external interrupt source for the given handler.  | 
 | 356 | +//! Note that external interrupts are target-specific and may not be available on all platforms.  | 
368 | 357 | //!  | 
369 | 358 | //! If interrupt handler is not explicitly defined, `DefaultHandler` is called.  | 
370 | 359 | //!  | 
371 | 360 | //! ### `DefaultHandler`  | 
372 | 361 | //!  | 
373 | 362 | //! This function is called when interrupt without defined interrupt handler is occured.  | 
374 | 363 | //! The interrupt reason can be decoded from the `mcause`/`scause` register.  | 
 | 364 | +//! If it is an external interrupt, the interrupt reason can be decoded from a  | 
 | 365 | +//! target-specific peripheral interrupt controller.  | 
375 | 366 | //!  | 
376 | 367 | //! This function can be redefined in the following way:  | 
377 | 368 | //!  | 
378 | 369 | //! ``` no_run  | 
379 | 370 | //! #[export_name = "DefaultHandler"]  | 
380 |  | -//! fn custom_interrupt_handler() {  | 
 | 371 | +//! unsafe fn custom_interrupt_handler() {  | 
381 | 372 | //!     // ...  | 
382 | 373 | //! }  | 
383 | 374 | //! ```  | 
384 | 375 | //! or  | 
385 | 376 | //! ``` no_run  | 
386 | 377 | //! #[no_mangle]  | 
387 |  | -//! fn DefaultHandler() {  | 
388 |  | -//!     // ...  | 
 | 378 | +//! fn DefaultHandler() -> ! {  | 
 | 379 | +//!     loop {}  | 
389 | 380 | //! }  | 
390 | 381 | //! ```  | 
391 | 382 | //!  | 
 | 
436 | 427 | //! riscv-rt = {features=["v-trap"]}  | 
437 | 428 | //! ```  | 
438 | 429 | //! When the vectored trap feature is enabled, the trap vector is set to `_vector_table` in vectored mode.  | 
439 |  | -//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the interrupt.  | 
440 |  | -//!  | 
441 |  | -//! ### Defining interrupt handlers in vectored mode  | 
442 |  | -//!  | 
443 |  | -//! In vectored mode, each interrupt must also have a corresponding trap handler.  | 
444 |  | -//! Therefore, using `export_name` or `no_mangle` is not enough to define an interrupt handler.  | 
445 |  | -//! The [`interrupt`] macro will generate the trap handler for the interrupt:  | 
446 |  | -//!  | 
447 |  | -//! ``` no_run  | 
448 |  | -//! #[riscv_rt::interrupt]  | 
449 |  | -//! fn MachineTimer() {  | 
450 |  | -//!    // ...  | 
451 |  | -//! }  | 
452 |  | -//! ```  | 
453 |  | -//!  | 
454 |  | -//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`.  | 
 | 430 | +//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the core interrupt.  | 
455 | 431 | 
  | 
456 | 432 | // NOTE: Adapted from cortex-m/src/lib.rs  | 
457 | 433 | #![no_std]  | 
 | 
0 commit comments