am_reg_macros.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. //*****************************************************************************
  2. //
  3. //! @file am_reg_macros.h
  4. //!
  5. //! @brief Helper macros for using hardware registers.
  6. //
  7. //*****************************************************************************
  8. //*****************************************************************************
  9. //
  10. // Copyright (c) 2017, Ambiq Micro
  11. // All rights reserved.
  12. //
  13. // Redistribution and use in source and binary forms, with or without
  14. // modification, are permitted provided that the following conditions are met:
  15. //
  16. // 1. Redistributions of source code must retain the above copyright notice,
  17. // this list of conditions and the following disclaimer.
  18. //
  19. // 2. Redistributions in binary form must reproduce the above copyright
  20. // notice, this list of conditions and the following disclaimer in the
  21. // documentation and/or other materials provided with the distribution.
  22. //
  23. // 3. Neither the name of the copyright holder nor the names of its
  24. // contributors may be used to endorse or promote products derived from this
  25. // software without specific prior written permission.
  26. //
  27. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  31. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. // POSSIBILITY OF SUCH DAMAGE.
  38. //
  39. // This is part of revision 1.2.9 of the AmbiqSuite Development Package.
  40. //
  41. //*****************************************************************************
  42. #ifndef AM_REG_MACROS_H
  43. #define AM_REG_MACROS_H
  44. #ifdef __cplusplus
  45. extern "C"
  46. {
  47. #endif
  48. //*****************************************************************************
  49. //
  50. // Include the inline assembly macros.
  51. //
  52. //*****************************************************************************
  53. #include "am_reg_macros_asm.h"
  54. //*****************************************************************************
  55. //
  56. // High-level Helper Macros.
  57. //
  58. // Usage:
  59. //
  60. // For direct 32-bit access to a register, use AM_REGVAL:
  61. // AM_REGVAL(REG_VCOMP_BASEADDR + AM_VCOMP_VCMPCFG_O) |= 0xDEADBEEF;
  62. //
  63. // The AM_REG macro can also be used as a shorthand version of AM_REGVAL:
  64. // AM_REG(VCOMP, VCMPCFG) |= 0xDEADBEEF;
  65. //
  66. // The AM_REGn macro is used for accessing registers of peripherals with
  67. // multiple instances, such as IOMSTR.
  68. // AM_REGn(IOMSTR, 1, CLKCFG) |= 0xDEADBEEF;
  69. //
  70. // To write to a specific bitfield within a register, use AM_BFW or AM_BFWn:
  71. // AM_BFW(CTIMER, 0, CTCTRL0, TMRB0FN, 0x3);
  72. //
  73. // To read a field, use AM_BFR or AM_BFRn:
  74. // ui32Timer0Fn = AM_BFR((CTIMER, 0, CTCTRL0, TMRB0FN);
  75. //
  76. // Note:
  77. //
  78. // AM_REGn, AM_BFW and AM_BFR are concatenation-based, which means that
  79. // standalone macro definitions should not be used for the 'module', 'reg', and
  80. // 'field' arguments.All macro names in the various peripheral header files are
  81. // written in one of the following forms:
  82. // - AM_REG_##module_reg_O
  83. // - AM_REG_##module_reg_field_S
  84. // - AM_REG_##module_reg_field_M
  85. //
  86. // The "module", "reg" and "field" fragments may be used as valid arguments to
  87. // the AM_REGn, AM_BFW, and AM_BFR macros, all of which are able to perform the
  88. // necessary concatenation operations to reconstruct the full macros and look
  89. // up the appropriate base address for the instance number given. For
  90. // peripherals with only one instance, use instance number 0.
  91. //
  92. // The AM_REGVAL macro does not perform any concatenation operations, so the
  93. // complete macro name (including any suffix) must be specified.
  94. //
  95. //*****************************************************************************
  96. #define AM_REGVAL(x) (*((volatile uint32_t *)(x)))
  97. #define AM_REGVAL_FLOAT(x) (*((volatile float *)(x)))
  98. //*****************************************************************************
  99. //
  100. // Register access macros for single-instance modules
  101. // AM_REG - Write a register of a module.
  102. // AM_BFW - Write a value to a bitfield of a register.
  103. // AM_BFWe - Use a defined enum value to write a value to a bitfield.
  104. // AM_BFR - Read a bitfield value from a register.
  105. // AM_BFM - Read and mask a bitfield, but leave the value in its bit position.
  106. // (Useful for comparing with enums.)
  107. //
  108. //*****************************************************************************
  109. #define AM_REG(module, reg) \
  110. AM_REGn(module, 0, reg)
  111. #define AM_BFW(module, reg, field, value) \
  112. AM_BFWn(module, 0, reg, field, value)
  113. #define AM_BFWe(module, reg, field, enumval) \
  114. AM_BFWen(module, 0, reg, field, enumval)
  115. #define AM_BFR(module, reg, field) \
  116. AM_BFRn(module, 0, reg, field)
  117. #define AM_BFM(module, reg, field) \
  118. AM_BFMn(module, 0, reg, field)
  119. #define AM_BFV(module, reg, field, value) \
  120. (((uint32_t)(value) << AM_REG_##module##_##reg##_##field##_S) & \
  121. AM_REG_##module##_##reg##_##field##_M)
  122. #define AM_BFX(module, reg, field, value) \
  123. (((uint32_t)(value) & AM_REG_##module##_##reg##_##field##_M) >> \
  124. AM_REG_##module##_##reg##_##field##_S)
  125. //*****************************************************************************
  126. //
  127. // Register access macros for multi-instance modules
  128. // AM_REGn - Write a register of a multiple instance module.
  129. // AM_BFWn - Write a value to a bitfield of a register in a multiple instance.
  130. // AM_BFWen - Use a defined enum value to write a value to a bitfield of a
  131. // register in a multiple instance.
  132. // AM_BFRn - Read a bitfield value from a register in a multiple instance.
  133. // AM_BFMn - Read a bitfield, but leave the value in its bitfield position.
  134. // AM_BFMn - Read and mask a bitfield, but leave the value in its bit position.
  135. // (Useful for comparing with enums.)
  136. //
  137. //*****************************************************************************
  138. #define AM_REGn(module, instance, reg) \
  139. AM_REGVAL(AM_REG_##module##n(instance) + AM_REG_##module##_##reg##_O)
  140. #define AM_BFWn(module, instance, reg, field, value) \
  141. AM_REGn(module, instance, reg) = \
  142. (AM_BFV(module, reg, field, value) | \
  143. (AM_REGn(module, instance, reg) & \
  144. (~AM_REG_##module##_##reg##_##field##_M)))
  145. #define AM_BFWen(module, instance, reg, field, enumval) \
  146. AM_REGn(module, instance, reg) = \
  147. (AM_REG_##module##_##reg##_##field##_##enumval | \
  148. (AM_REGn(module, instance, reg) & \
  149. (~AM_REG_##module##_##reg##_##field##_M)))
  150. #define AM_BFRn(module, instance, reg, field) \
  151. AM_BFX(module, reg, field, AM_REGn(module, instance, reg))
  152. #define AM_BFMn(module, instance, reg, field) \
  153. (AM_REGn(module, instance, reg) & AM_REG_##module##_##reg##_##field##_M)
  154. //*****************************************************************************
  155. //
  156. // "Atomic" register access macros - use when a read-modify-write is required.
  157. //
  158. // These macros will be slower than the normal macros, but they will also
  159. // guarantee threadsafe hardware access.
  160. //
  161. // These macros require a nesting-friendly critical section implementation. If
  162. // you are using the HAL, you can use the default definitions below. If not,
  163. // you will need to supply your own.
  164. //
  165. // Atomic register access macros usage:
  166. // AM_REGa - Write a register of a single instance module. Provide operator
  167. // (&,|,etc) to perform that operation on the reg using value, or
  168. // no operator to simply write the value atomically.
  169. // AM_REGa_SET - Set bits in a single instance module according to the mask.
  170. // AM_REGa_CLR - Clear bits in a single instance module according to the mask.
  171. // AM_REGna - Multiple module version of AM_REGa.
  172. // AM_REGna_SET - Multiple instance version of AM_REGa_SET.
  173. // AM_REGna_CLR - Multiple instance version of AM_REGa_CLR.
  174. // AM_BFWa - Write a value to a register bitfield.
  175. // AM_BFWae - Use a defined enum value to write a value to a bitfield.
  176. // AM_BFWan - Write a value to a bitfield of a register in a multiple instance.
  177. // AM_BFWaen - Use a defined enum value to write a value to a bitfield of a
  178. // register in a multiple instance.
  179. //
  180. //*****************************************************************************
  181. #ifndef AM_CRITICAL_BEGIN
  182. #define AM_CRITICAL_BEGIN uint32_t ui32Primask = am_hal_interrupt_master_disable()
  183. #define AM_CRITICAL_END am_hal_interrupt_master_set(ui32Primask)
  184. #endif
  185. #define AM_REGan(module, instance, reg, operator, value) \
  186. AM_CRITICAL_BEGIN_ASM \
  187. AM_REGn(module, instance, reg) operator##= (value); \
  188. AM_CRITICAL_END_ASM
  189. #define AM_REGan_SET(module, instance, reg, mask) \
  190. AM_CRITICAL_BEGIN_ASM \
  191. AM_REGn(module, instance, reg) |= (mask); \
  192. AM_CRITICAL_END_ASM
  193. #define AM_REGan_CLR(module, instance, reg, mask) \
  194. AM_CRITICAL_BEGIN_ASM \
  195. AM_REGn(module, instance, reg) &= (~mask); \
  196. AM_CRITICAL_END_ASM
  197. #define AM_REGa(module, reg, operator, value) \
  198. AM_REGan(module, 0, reg, operator, value)
  199. #define AM_REGa_CLR(module, reg, mask) \
  200. AM_REGan_CLR(module, 0, reg, mask)
  201. #define AM_REGa_SET(module, reg, mask) \
  202. AM_REGan_SET(module, 0, reg, mask)
  203. #define AM_BFWa(module, reg, field, value) \
  204. AM_CRITICAL_BEGIN_ASM \
  205. AM_BFW(module, reg, field, value); \
  206. AM_CRITICAL_END_ASM
  207. #define AM_BFWae(module, reg, field, enumval) \
  208. AM_CRITICAL_BEGIN_ASM \
  209. AM_BFWe(module, reg, field, enumval); \
  210. AM_CRITICAL_END_ASM
  211. #define AM_BFWan(module, instance, reg, field, value) \
  212. AM_CRITICAL_BEGIN_ASM \
  213. AM_BFWn(module, instance, reg, field, enumval); \
  214. AM_CRITICAL_END_ASM
  215. #define AM_BFWaen(module, instance, reg, field, enumval) \
  216. AM_CRITICAL_BEGIN_ASM \
  217. AM_BFWen(module, instance reg, field, enumval); \
  218. AM_CRITICAL_END_ASM
  219. //*****************************************************************************
  220. //
  221. // Other helper Macros.
  222. //
  223. // Note: These macros make use of macro concatenation, so the '_S' or '_M'
  224. // suffix on a register bitfield macro should not be supplied by the user.
  225. // The macro will apply each suffix as needed.
  226. //
  227. //*****************************************************************************
  228. //
  229. // AM_ENUMX extracts a register bitfield enumeration to the bit 0 position,
  230. // which makes it possible to use enums directly with existing macros such
  231. // as AM_BFR() or AM_BFW().
  232. // Brief overview: bitfield enumerations are pre-shifted such that the defined
  233. // value lines up with the bitfield. This is convenient for many operations,
  234. // but not so when using AM_BFR() to read the value of a register bitfield
  235. // as AM_BFR() shifts the bitfield value to the bit 0 position.
  236. // Note that this type of bitfield extraction is Cortex efficient via the
  237. // UBFX (unsigned bit field extract) instruction.
  238. //
  239. // Alternately, AM_BFM() can also be used. AM_BFM() reads a register and masks
  240. // the bitfield value (without shifting), thereby allowing direct comparison
  241. // with a defined enum.
  242. //
  243. // Examples:
  244. // if ( AM_BFR(CLKGEN, CCTRL, CORESEL) ==
  245. // AM_ENUMX(CLKGEN, CCTRL, CORESEL, HFRC) )
  246. //
  247. // or alternatively:
  248. // if ( AM_BFM(CLKGEN, CCTRL, CORESEL) == AM_REG_CLKGEN_CCTRL_CORESEL_HFRC )
  249. //
  250. #define AM_ENUMX(module, reg, field, enumname) \
  251. ((AM_REG_##module##_##reg##_##field##_##enumname) >> \
  252. (AM_REG_##module##_##reg##_##field##_S))
  253. //
  254. // AM_WRITE_SM performs a shift/mask operation to prepare the value 'x' to be
  255. // written to the register field 'field'.
  256. //
  257. // For example:
  258. // AM_REGVAL(ui32Base + AM_VCOMP_VCMP_CFG_O) |=
  259. // AM_WRITE_SM(AM_VCOMP_VCMP_CFG_LVLSEL, ui32Value);
  260. //
  261. #define AM_WRITE_SM(field, x) (((x) << field##_S) & field##_M)
  262. //
  263. // AM_READ_SM performs a shift/mask operation to make it easier to interpret
  264. // the value of a given bitfield. This is essentially the reverse of the
  265. // AM_WRITE_SM operation. In most cases, you will want to use the shorter
  266. // AM_BFR macro instead of this one.
  267. //
  268. // For example:
  269. // ui32Value = AM_READ_SM(AM_VCOMP_VCMP_CFG_NSEL,
  270. // AM_REGVAL(ui32Base + AM_VCOMP_VCMP_CFG_O));
  271. //
  272. #define AM_READ_SM(field, x) (((x) & field##_M) >> field##_S)
  273. #ifdef __cplusplus
  274. }
  275. #endif
  276. #endif // AM_REG_MACROS_H