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