interrupt.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #ifndef _AGM_INTERRUPT_H
  2. #define _AGM_INTERRUPT_H
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. #include "util.h"
  7. #define MCAUSE_INT_MASK (0x80000000)
  8. static inline void INT_SetISR(void *isr) { write_csr(mtvec, isr); }
  9. static inline void INT_EnableIntGlobal(void) { set_csr (mstatus, MSTATUS_MIE); }
  10. static inline void INT_DisableIntGlobal(void) { clear_csr(mstatus, MSTATUS_MIE); }
  11. static inline void INT_EnableIntExternal(void) { set_csr (mie, MIP_MEIP); }
  12. static inline void INT_DisableIntExternal(void) { clear_csr(mie, MIP_MEIP); }
  13. static inline void INT_EnableIntSoftware(void) { set_csr (mie, MIP_MSIP); }
  14. static inline void INT_DisableIntSoftware(void) { clear_csr(mie, MIP_MSIP); }
  15. static inline void INT_EnableIntTimer(void) { set_csr (mie, MIP_MTIP); }
  16. static inline void INT_DisableIntTimer(void) { clear_csr(mie, MIP_MTIP); }
  17. static inline void INT_EnableIntLocal (uint32_t irq) { set_csr (mie, (1 << irq)); } // irq must be one of LOCAL_INTx_IRQn
  18. static inline void INT_DisableIntLocal(uint32_t irq) { clear_csr(mie, (1 << irq)); }
  19. static inline void INT_EnablePLIC(void) { INT_EnableIntExternal(); INT_EnableIntGlobal(); }
  20. // Each interrupt has an enable bit, a pending bit, and a priority. The pending bits are set regardless of the enable
  21. // bits. Reading the claim_complete register will return the highest priority pending interrupt number and clear the
  22. // corresponding pending bit (only for enabled interrupts with above threshold priority). Since Interrupts are numbered
  23. // starting from 1, a read value of 0 means no active interrupt. A write to the claim_complete register will complete
  24. // the interrupt.
  25. typedef struct
  26. {
  27. __IO uint32_t PRIORITY[0x400]; // 0x0000-
  28. __IO uint32_t PENDING[0x400]; // 0x1000-
  29. __IO uint32_t ENABLE[0x7f800]; // 0x2000-
  30. __IO uint32_t THRESHOLD; // 0x200000
  31. __IO uint32_t CLAIM_COMPLETE; // 0x200004
  32. } PLIC_TypeDef;
  33. #define PLIC_BASE (0xc000000)
  34. #define PLIC ((PLIC_TypeDef *) PLIC_BASE)
  35. #define PLIC_MIN_PRIORITY 1
  36. // The IRQ number can be greater than word size (XLEN_BITS)
  37. #define IRQ_BIT_OFFSET(__irq) (__irq % XLEN_BITS)
  38. #define IRQ_WORD_OFFSET(__irq) (__irq / XLEN_BITS)
  39. // PLIC functions. INT_ClaimIRQ and INT_CompleteIRQ should be called only within an ISR!
  40. static inline uint32_t INT_GetIRQThreshold(void) { return PLIC->THRESHOLD; }
  41. static inline uint32_t INT_GetIRQPriorify(uint32_t irq) { return PLIC->PRIORITY[irq]; }
  42. static inline uint32_t INT_ClaimIRQ(void) { return PLIC->CLAIM_COMPLETE; }
  43. static inline void INT_SetIRQThreshold(uint32_t threshold) { PLIC->THRESHOLD = threshold; }
  44. static inline void INT_SetIRQPriority(uint32_t irq, uint32_t priority) { PLIC->PRIORITY[irq] = priority; }
  45. static inline void INT_CompleteIRQ(uint32_t irq) { PLIC->CLAIM_COMPLETE = irq; }
  46. void INT_EnableIRQ(uint32_t irq, uint32_t priority);
  47. void INT_DisableIRQ(uint32_t irq);
  48. bool INT_IsIRQPending(uint32_t irq);
  49. typedef struct
  50. {
  51. __IO uint32_t MSIP; // 0x0000, Machine software interrupt pending
  52. uint32_t RESERVED0[0x0fff];
  53. __IO uint32_t MTIMECMP_LO; // 0x4000, Machine timer compare
  54. __IO uint32_t MTIMECMP_HI;
  55. uint32_t RESERVED1[0x1ffc];
  56. __IO uint32_t MTIME_LO; // 0xbff8, Machine timer
  57. __IO uint32_t MTIME_HI;
  58. } CLINT_TypeDef;
  59. #undef CLINT_BASE
  60. #define CLINT_BASE (0x2000000)
  61. #define CLINT ((CLINT_TypeDef *) CLINT_BASE)
  62. // CLINT functions
  63. static inline uint64_t INT_GetMtime(void) { return ((uint64_t)CLINT->MTIME_HI) << 32 | CLINT->MTIME_LO; }
  64. static inline uint64_t INT_GetMtimeCmp(void) { return ((uint64_t)CLINT->MTIMECMP_HI) << 32 | CLINT->MTIMECMP_LO; }
  65. static inline void INT_SetMtimeLo(uint32_t mtime) { CLINT->MTIME_LO = mtime; }
  66. static inline void INT_SetMtimeHi(uint32_t mtime) { CLINT->MTIME_HI = mtime; }
  67. static inline void INT_SetMtime(uint64_t mtime)
  68. {
  69. CLINT->MTIME_LO = 0; // So that MTIME_HI will not inadvertently increase
  70. CLINT->MTIME_HI = mtime >> 32;
  71. CLINT->MTIME_LO = mtime;
  72. }
  73. static inline void INT_SetMtimeCmp(uint64_t mtime)
  74. {
  75. CLINT->MTIMECMP_LO = -1; // So that interrupt is not triggered by an intermediate mtimecmp value
  76. CLINT->MTIMECMP_HI = mtime >> 32;
  77. CLINT->MTIMECMP_LO = mtime;
  78. }
  79. static inline void INT_TriggerSoftwareInt(void) { CLINT->MSIP = 1; }
  80. static inline void INT_ClearSoftwareInt(void) { CLINT->MSIP = 0; }
  81. // ISR functions
  82. extern void handle_trap_nonest(uintptr_t mcause, uintptr_t mepc, uintptr_t *sp);
  83. extern void handle_trap_nested(uintptr_t mcause, uintptr_t mepc, uintptr_t *sp);
  84. extern void (**plic_isr)(void);
  85. extern void (**clint_isr)(void);
  86. extern void exception_handler(void);
  87. void INT_Init(void);
  88. #ifdef __cplusplus
  89. }
  90. #endif
  91. #endif