|
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