macros.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. //! Utility macros for generating standard peripherals-related code in RISC-V PACs.
  2. /// Macro to create interfaces to CLINT peripherals in PACs.
  3. /// The resulting struct will be named `CLINT`, and will provide safe access to the CLINT registers.
  4. ///
  5. /// This macro expects 4 different argument types:
  6. ///
  7. /// - Base address (**MANDATORY**): base address of the CLINT peripheral of the target.
  8. /// - Frequency (**OPTIONAL**): clock frequency (in Hz) of the `MTIME` register. It enables the `delay` method of the `CLINT` struct.
  9. /// - Per-HART mtimecmp registers (**OPTIONAL**): a list of `mtimecmp` registers for easing access to per-HART mtimecmp regs.
  10. /// - Per-HART msip registers (**OPTIONAL**): a list of `msip` registers for easing access to per-HART msip regs.
  11. ///
  12. /// Check the examples below for more details about the usage and syntax of this macro.
  13. ///
  14. /// # Example
  15. ///
  16. /// ## Base address only
  17. ///
  18. /// ```
  19. /// use riscv_peripheral::clint_codegen;
  20. ///
  21. /// clint_codegen!(base 0x0200_0000, freq 32_768,); // do not forget the ending comma!
  22. ///
  23. /// let mswi = CLINT::mswi(); // MSWI peripheral
  24. /// let mtimer = CLINT::mtimer(); // MTIMER peripheral
  25. /// let delay = CLINT::delay(); // For the `embedded_hal::delay::DelayNs` trait
  26. /// ```
  27. ///
  28. /// ## Base address and per-HART mtimecmp registers
  29. ///
  30. /// ```
  31. /// use riscv_peripheral::clint_codegen;
  32. ///
  33. /// /// HART IDs for the target CLINT peripheral
  34. /// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  35. /// #[repr(u16)]
  36. /// pub enum HartId { H0 = 0, H1 = 1, H2 = 2 }
  37. ///
  38. /// // Implement `HartIdNumber` for `HartId`
  39. /// unsafe impl riscv_peripheral::aclint::HartIdNumber for HartId {
  40. /// const MAX_HART_ID_NUMBER: u16 = 2;
  41. /// fn number(self) -> u16 { self as _ }
  42. /// fn from_number(number: u16) -> Result<Self, u16> {
  43. /// if number > Self::MAX_HART_ID_NUMBER {
  44. /// Err(number)
  45. /// } else {
  46. /// // SAFETY: valid context number
  47. /// Ok(unsafe { core::mem::transmute(number) })
  48. /// }
  49. /// }
  50. /// }
  51. ///
  52. /// clint_codegen!(
  53. /// base 0x0200_0000,
  54. /// mtimecmps [mtimecmp0 = (HartId::H0, "`H0`"), mtimecmp1 = (HartId::H1, "`H1`"), mtimecmp2 = (HartId::H2, "`H2`")],
  55. /// msips [msip0=(HartId::H0,"`H0`"), msip1=(HartId::H1,"`H1`"), msip2=(HartId::H2,"`H2`")], // do not forget the ending comma!
  56. /// );
  57. ///
  58. /// let mswi = CLINT::mswi(); // MSWI peripheral
  59. /// let mtimer = CLINT::mtimer(); // MTIMER peripheral
  60. ///
  61. /// let mtimecmp0 = CLINT::mtimecmp0(); // mtimecmp register for HART 0
  62. /// let mtimecmp1 = CLINT::mtimecmp1(); // mtimecmp register for HART 1
  63. /// let mtimecmp2 = CLINT::mtimecmp2(); // mtimecmp register for HART 2
  64. ///
  65. /// let msip0 = CLINT::msip0(); // msip register for HART 0
  66. /// let msip1 = CLINT::msip1(); // msip register for HART 1
  67. /// let msip2 = CLINT::msip2(); // msip register for HART 2
  68. /// ```
  69. #[macro_export]
  70. macro_rules! clint_codegen {
  71. () => {
  72. #[allow(unused_imports)]
  73. use CLINT as _; // assert that the CLINT struct is defined
  74. };
  75. (base $addr:literal, $($tail:tt)*) => {
  76. /// CLINT peripheral
  77. #[allow(clippy::upper_case_acronyms)]
  78. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  79. pub struct CLINT;
  80. unsafe impl $crate::aclint::Clint for CLINT {
  81. const BASE: usize = $addr;
  82. }
  83. impl CLINT {
  84. /// Returns `true` if a machine timer **OR** software interrupt is pending.
  85. #[inline]
  86. pub fn is_interrupting() -> bool {
  87. Self::mswi_is_interrupting() || Self::mtimer_is_interrupting()
  88. }
  89. /// Returns `true` if machine timer **OR** software interrupts are enabled.
  90. pub fn is_enabled() -> bool {
  91. Self::mswi_is_enabled() || Self::mtimer_is_enabled()
  92. }
  93. /// Enables machine timer **AND** software interrupts to allow the CLINT to trigger interrupts.
  94. ///
  95. /// # Safety
  96. ///
  97. /// Enabling the `CLINT` may break mask-based critical sections.
  98. #[inline]
  99. pub unsafe fn enable() {
  100. Self::mswi_enable();
  101. Self::mtimer_enable();
  102. }
  103. /// Disables machine timer **AND** software interrupts to prevent the CLINT from triggering interrupts.
  104. #[inline]
  105. pub fn disable() {
  106. Self::mswi_disable();
  107. Self::mtimer_disable();
  108. }
  109. /// Returns `true` if a machine software interrupt is pending.
  110. #[inline]
  111. pub fn mswi_is_interrupting() -> bool {
  112. $crate::riscv::register::mip::read().msoft()
  113. }
  114. /// Returns `true` if Machine Software Interrupts are enabled.
  115. #[inline]
  116. pub fn mswi_is_enabled() -> bool {
  117. $crate::riscv::register::mie::read().msoft()
  118. }
  119. /// Enables the `MSWI` peripheral.
  120. ///
  121. /// # Safety
  122. ///
  123. /// Enabling the `MSWI` may break mask-based critical sections.
  124. #[inline]
  125. pub unsafe fn mswi_enable() {
  126. $crate::riscv::register::mie::set_msoft();
  127. }
  128. /// Disables the `MSWI` peripheral.
  129. #[inline]
  130. pub fn mswi_disable() {
  131. // SAFETY: it is safe to disable interrupts
  132. unsafe { $crate::riscv::register::mie::clear_msoft() };
  133. }
  134. /// Returns the `MSWI` peripheral.
  135. #[inline]
  136. pub const fn mswi() -> $crate::aclint::mswi::MSWI {
  137. $crate::aclint::CLINT::<CLINT>::mswi()
  138. }
  139. /// Returns `true` if a machine timer interrupt is pending.
  140. #[inline]
  141. pub fn mtimer_is_interrupting() -> bool {
  142. $crate::riscv::register::mip::read().mtimer()
  143. }
  144. /// Returns `true` if Machine Timer Interrupts are enabled.
  145. #[inline]
  146. pub fn mtimer_is_enabled() -> bool {
  147. $crate::riscv::register::mie::read().mtimer()
  148. }
  149. /// Sets the Machine Timer Interrupt bit of the `mie` CSR.
  150. /// This bit must be set for the `MTIMER` to trigger machine timer interrupts.
  151. ///
  152. /// # Safety
  153. ///
  154. /// Enabling the `MTIMER` may break mask-based critical sections.
  155. #[inline]
  156. pub unsafe fn mtimer_enable() {
  157. $crate::riscv::register::mie::set_mtimer();
  158. }
  159. /// Clears the Machine Timer Interrupt bit of the `mie` CSR.
  160. /// When cleared, the `MTIMER` cannot trigger machine timer interrupts.
  161. #[inline]
  162. pub fn mtimer_disable() {
  163. // SAFETY: it is safe to disable interrupts
  164. unsafe { $crate::riscv::register::mie::clear_mtimer() };
  165. }
  166. /// Returns the `MTIMER` peripheral.
  167. #[inline]
  168. pub const fn mtimer() -> $crate::aclint::mtimer::MTIMER {
  169. $crate::aclint::CLINT::<CLINT>::mtimer()
  170. }
  171. /// Returns the `MTIME` register of the `MTIMER` peripheral.
  172. #[inline]
  173. pub const fn mtime() -> $crate::aclint::mtimer::MTIME {
  174. Self::mtimer().mtime
  175. }
  176. }
  177. $crate::clint_codegen!($($tail)*);
  178. };
  179. (freq $freq:literal, $($tail:tt)*) => {
  180. impl CLINT {
  181. /// Returns the frequency of the `MTIME` register.
  182. #[inline]
  183. pub const fn freq() -> usize {
  184. $freq
  185. }
  186. /// Delay implementation for CLINT peripherals.
  187. ///
  188. /// # Note
  189. ///
  190. /// You must export the `riscv_peripheral::hal::delay::DelayNs` trait in order to use delay methods.
  191. #[inline]
  192. pub const fn delay() -> $crate::hal::aclint::Delay {
  193. $crate::hal::aclint::Delay::new(Self::mtime(), Self::freq())
  194. }
  195. }
  196. $crate::clint_codegen!($($tail)*);
  197. };
  198. (async_delay, $($tail:tt)*) => {
  199. impl CLINT {
  200. /// Asynchronous delay implementation for CLINT peripherals.
  201. ///
  202. /// # Note
  203. ///
  204. /// You must export the `riscv_peripheral::hal_async::delay::DelayNs` trait in order to use delay methods.
  205. ///
  206. /// This implementation relies on the machine-level timer interrupts to wake futures.
  207. /// Therefore, it needs to schedule the machine-level timer interrupts via the `MTIMECMP` register assigned to the current HART.
  208. /// Thus, the `Delay` instance must be created on the same HART that is used to call the asynchronous delay methods.
  209. /// Additionally, the rest of the application must not modify the `MTIMER` register assigned to the current HART.
  210. #[inline]
  211. pub fn async_delay() -> $crate::hal_async::aclint::Delay {
  212. $crate::hal_async::aclint::Delay::new(Self::freq())
  213. }
  214. }
  215. $crate::clint_codegen!($($tail)*);
  216. };
  217. (msips [$($fn:ident = ($hart:expr , $shart:expr)),+], $($tail:tt)*) => {
  218. impl CLINT {
  219. $(
  220. #[doc = "Returns the `msip` register for HART "]
  221. #[doc = $shart]
  222. #[doc = "."]
  223. #[inline]
  224. pub fn $fn() -> $crate::aclint::mswi::MSIP {
  225. Self::mswi().msip($hart)
  226. }
  227. )*
  228. }
  229. $crate::clint_codegen!($($tail)*);
  230. };
  231. (mtimecmps [$($fn:ident = ($hart:expr , $shart:expr)),+], $($tail:tt)*) => {
  232. impl CLINT {
  233. $(
  234. #[doc = "Returns the `mtimecmp` register for HART "]
  235. #[doc = $shart]
  236. #[doc = "."]
  237. #[inline]
  238. pub fn $fn() -> $crate::aclint::mtimer::MTIMECMP {
  239. Self::mtimer().mtimecmp($hart)
  240. }
  241. )*
  242. }
  243. $crate::clint_codegen!($($tail)*);
  244. };
  245. }
  246. /// Macro to create interfaces to PLIC peripherals in PACs.
  247. #[macro_export]
  248. macro_rules! plic_codegen {
  249. () => {
  250. #[allow(unused_imports)]
  251. use PLIC as _; // assert that the PLIC struct is defined
  252. };
  253. (base $addr:literal, $($tail:tt)*) => {
  254. /// PLIC peripheral
  255. #[allow(clippy::upper_case_acronyms)]
  256. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  257. pub struct PLIC;
  258. unsafe impl $crate::plic::Plic for PLIC {
  259. const BASE: usize = $addr;
  260. }
  261. impl PLIC {
  262. /// Returns `true` if a machine external interrupt is pending.
  263. #[inline]
  264. pub fn is_interrupting() -> bool {
  265. $crate::riscv::register::mip::read().mext()
  266. }
  267. /// Returns true if Machine External Interrupts are enabled.
  268. #[inline]
  269. pub fn is_enabled() -> bool {
  270. $crate::riscv::register::mie::read().mext()
  271. }
  272. /// Enables machine external interrupts to allow the PLIC to trigger interrupts.
  273. ///
  274. /// # Safety
  275. ///
  276. /// Enabling the `PLIC` may break mask-based critical sections.
  277. #[inline]
  278. pub unsafe fn enable() {
  279. $crate::riscv::register::mie::set_mext();
  280. }
  281. /// Disables machine external interrupts to prevent the PLIC from triggering interrupts.
  282. #[inline]
  283. pub fn disable() {
  284. // SAFETY: it is safe to disable interrupts
  285. unsafe { $crate::riscv::register::mie::clear_mext() };
  286. }
  287. /// Returns the priorities register of the PLIC.
  288. #[inline]
  289. pub fn priorities() -> $crate::plic::priorities::PRIORITIES {
  290. $crate::plic::PLIC::<PLIC>::priorities()
  291. }
  292. /// Returns the pendings register of the PLIC.
  293. #[inline]
  294. pub fn pendings() -> $crate::plic::pendings::PENDINGS {
  295. $crate::plic::PLIC::<PLIC>::pendings()
  296. }
  297. /// Returns the context proxy of a given PLIC HART context.
  298. #[inline]
  299. pub fn ctx<H: $crate::plic::HartIdNumber>(hart_id: H) -> $crate::plic::CTX<Self> {
  300. $crate::plic::PLIC::<PLIC>::ctx(hart_id)
  301. }
  302. /// Returns the PLIC HART context for the current HART.
  303. ///
  304. /// # Note
  305. ///
  306. /// This function determines the current HART ID by reading the [`riscv::register::mhartid`] CSR.
  307. /// Thus, it can only be used in M-mode. For S-mode, use [`PLIC::ctx`] instead.
  308. #[inline]
  309. pub fn ctx_mhartid(&self) -> $crate::plic::CTX<Self> {
  310. $crate::plic::PLIC::<PLIC>::ctx_mhartid()
  311. }
  312. }
  313. $crate::plic_codegen!($($tail)*);
  314. };
  315. (ctxs [$($fn:ident = ($ctx:expr , $sctx:expr)),+], $($tail:tt)*) => {
  316. impl PLIC {
  317. $(
  318. #[doc = "Returns a PLIC context proxy for context of HART "]
  319. #[doc = $sctx]
  320. #[doc = "."]
  321. #[inline]
  322. pub fn $fn() -> $crate::plic::CTX<Self> {
  323. Self::ctx($ctx)
  324. }
  325. )*
  326. }
  327. $crate::plic_codegen!($($tail)*);
  328. };
  329. }