1 /******************************************************************************
2 * Filename: cpu.c
3 *
4 * Description: Instruction wrappers for special CPU instructions needed by
5 * the drivers.
6 *
7 * Copyright (c) 2015 - 2022, Texas Instruments Incorporated
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1) Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2) Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
21 * be used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 ******************************************************************************/
37
38 #include "cpu.h"
39
40 //*****************************************************************************
41 //
42 // Handle support for DriverLib in ROM:
43 // This section will undo prototype renaming made in the header file
44 //
45 //*****************************************************************************
46 #if !defined(DOXYGEN)
47 #undef CPUcpsid
48 #define CPUcpsid NOROM_CPUcpsid
49 #undef CPUprimask
50 #define CPUprimask NOROM_CPUprimask
51 #undef CPUcpsie
52 #define CPUcpsie NOROM_CPUcpsie
53 #undef CPUbasepriGet
54 #define CPUbasepriGet NOROM_CPUbasepriGet
55 #undef CPUdelay
56 #define CPUdelay NOROM_CPUdelay
57 #endif
58
59 //*****************************************************************************
60 //
61 // Disable all external interrupts
62 //
63 //*****************************************************************************
64 #if defined(DOXYGEN)
65 uint32_t
CPUcpsid(void)66 CPUcpsid(void)
67 {
68 // This function is written in assembly. See cpu.c for compiler specific implementation.
69 }
70 #elif defined(__IAR_SYSTEMS_ICC__)
71 uint32_t
CPUcpsid(void)72 CPUcpsid(void)
73 {
74 // Read PRIMASK and disable interrupts.
75 __asm(" mrs r0, PRIMASK\n"
76 " cpsid i\n");
77
78 // "Warning[Pe940]: missing return statement at end of non-void function"
79 // is suppressed here to avoid putting a "bx lr" in the inline assembly
80 // above and a superfluous return statement here.
81 #pragma diag_suppress=Pe940
82 }
83 #pragma diag_default=Pe940
84 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
85 __asm uint32_t
CPUcpsid(void)86 CPUcpsid(void)
87 {
88 // Read PRIMASK and disable interrupts.
89 mrs r0, PRIMASK;
90 cpsid i;
91 bx lr
92 }
93 #elif (defined(__TI_COMPILER_VERSION__) || defined(__clang__))
94 uint32_t
CPUcpsid(void)95 CPUcpsid(void)
96 {
97 // Read PRIMASK and disable interrupts.
98 __asm(" mrs r0, PRIMASK\n"
99 " cpsid i\n"
100 " bx lr\n");
101
102 // The following keeps the compiler happy, because it wants to see a
103 // return value from this function. It will generate code to return
104 // a zero. However, the real return is the "bx lr" above, so the
105 // return(0) is never executed and the function returns with the value
106 // you expect in R0.
107 return(0);
108 }
109 #else
110 uint32_t __attribute__((naked))
CPUcpsid(void)111 CPUcpsid(void)
112 {
113 uint32_t ui32Ret;
114
115 // Read PRIMASK and disable interrupts
116 __asm volatile (" mrs %0, PRIMASK\n"
117 " cpsid i\n"
118 " bx lr\n"
119 : "=r"(ui32Ret)
120 );
121
122 // The return is handled in the inline assembly, but the compiler will
123 // still complain if there is not an explicit return here (despite the fact
124 // that this does not result in any code being produced because of the
125 // naked attribute).
126 return(ui32Ret);
127 }
128 #endif
129
130 //*****************************************************************************
131 //
132 // Get the current interrupt state
133 //
134 //*****************************************************************************
135 #if defined(DOXYGEN)
136 uint32_t
CPUprimask(void)137 CPUprimask(void)
138 {
139 // This function is written in assembly. See cpu.c for compiler specific implementation.
140 }
141 #elif defined(__IAR_SYSTEMS_ICC__)
142 uint32_t
CPUprimask(void)143 CPUprimask(void)
144 {
145 // Read PRIMASK.
146 __asm(" mrs r0, PRIMASK\n");
147
148 // "Warning[Pe940]: missing return statement at end of non-void function"
149 // is suppressed here to avoid putting a "bx lr" in the inline assembly
150 // above and a superfluous return statement here.
151 #pragma diag_suppress=Pe940
152 }
153 #pragma diag_default=Pe940
154 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
155 __asm uint32_t
CPUprimask(void)156 CPUprimask(void)
157 {
158 // Read PRIMASK.
159 mrs r0, PRIMASK;
160 bx lr
161 }
162 #elif (defined(__TI_COMPILER_VERSION__) || defined(__clang__))
163 uint32_t
CPUprimask(void)164 CPUprimask(void)
165 {
166 // Read PRIMASK.
167 __asm(" mrs r0, PRIMASK\n"
168 " bx lr\n");
169
170 // The following keeps the compiler happy, because it wants to see a
171 // return value from this function. It will generate code to return
172 // a zero. However, the real return is the "bx lr" above, so the
173 // return(0) is never executed and the function returns with the value
174 // you expect in R0.
175 return(0);
176 }
177 #else
178 uint32_t __attribute__((naked))
CPUprimask(void)179 CPUprimask(void)
180 {
181 uint32_t ui32Ret;
182
183 // Read PRIMASK
184 __asm volatile (" mrs %0, PRIMASK\n"
185 " bx lr\n"
186 : "=r"(ui32Ret)
187 );
188
189 // The return is handled in the inline assembly, but the compiler will
190 // still complain if there is not an explicit return here (despite the fact
191 // that this does not result in any code being produced because of the
192 // naked attribute).
193 return(ui32Ret);
194 }
195 #endif
196
197 //*****************************************************************************
198 //
199 // Enable all external interrupts
200 //
201 //*****************************************************************************
202 #if defined(DOXYGEN)
203 uint32_t
CPUcpsie(void)204 CPUcpsie(void)
205 {
206 // This function is written in assembly. See cpu.c for compiler specific implementation.
207 }
208 #elif defined(__IAR_SYSTEMS_ICC__)
209 uint32_t
CPUcpsie(void)210 CPUcpsie(void)
211 {
212 // Read PRIMASK and enable interrupts.
213 __asm(" mrs r0, PRIMASK\n"
214 " cpsie i\n");
215
216 // "Warning[Pe940]: missing return statement at end of non-void function"
217 // is suppressed here to avoid putting a "bx lr" in the inline assembly
218 // above and a superfluous return statement here.
219 #pragma diag_suppress=Pe940
220 }
221 #pragma diag_default=Pe940
222 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
223 __asm uint32_t
CPUcpsie(void)224 CPUcpsie(void)
225 {
226 // Read PRIMASK and enable interrupts.
227 mrs r0, PRIMASK;
228 cpsie i;
229 bx lr
230 }
231 #elif (defined(__TI_COMPILER_VERSION__) || defined(__clang__))
232 uint32_t
CPUcpsie(void)233 CPUcpsie(void)
234 {
235 // Read PRIMASK and enable interrupts.
236 __asm(" mrs r0, PRIMASK\n"
237 " cpsie i\n"
238 " bx lr\n");
239
240 // The following keeps the compiler happy, because it wants to see a
241 // return value from this function. It will generate code to return
242 // a zero. However, the real return is the "bx lr" above, so the
243 // return(0) is never executed and the function returns with the value
244 // you expect in R0.
245 return(0);
246 }
247 #else
248 uint32_t __attribute__((naked))
CPUcpsie(void)249 CPUcpsie(void)
250 {
251 uint32_t ui32Ret;
252
253 // Read PRIMASK and enable interrupts.
254 __asm volatile (" mrs %0, PRIMASK\n"
255 " cpsie i\n"
256 " bx lr\n"
257 : "=r"(ui32Ret)
258 );
259
260 // The return is handled in the inline assembly, but the compiler will
261 // still complain if there is not an explicit return here (despite the fact
262 // that this does not result in any code being produced because of the
263 // naked attribute).
264 return(ui32Ret);
265 }
266 #endif
267
268 //*****************************************************************************
269 //
270 // Get the interrupt priority disable level
271 //
272 //*****************************************************************************
273 #if defined(DOXYGEN)
274 uint32_t
CPUbasepriGet(void)275 CPUbasepriGet(void)
276 {
277 // This function is written in assembly. See cpu.c for compiler specific implementation.
278 }
279 #elif defined(__IAR_SYSTEMS_ICC__)
280 uint32_t
CPUbasepriGet(void)281 CPUbasepriGet(void)
282 {
283 // Read BASEPRI.
284 __asm(" mrs r0, BASEPRI\n");
285
286 // "Warning[Pe940]: missing return statement at end of non-void function"
287 // is suppressed here to avoid putting a "bx lr" in the inline assembly
288 // above and a superfluous return statement here.
289 #pragma diag_suppress=Pe940
290 }
291 #pragma diag_default=Pe940
292 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
293 __asm uint32_t
CPUbasepriGet(void)294 CPUbasepriGet(void)
295 {
296 // Read BASEPRI.
297 mrs r0, BASEPRI;
298 bx lr
299 }
300 #elif (defined(__TI_COMPILER_VERSION__) || defined(__clang__))
301 uint32_t
CPUbasepriGet(void)302 CPUbasepriGet(void)
303 {
304 // Read BASEPRI.
305 __asm(" mrs r0, BASEPRI\n"
306 " bx lr\n");
307
308 // The following keeps the compiler happy, because it wants to see a
309 // return value from this function. It will generate code to return
310 // a zero. However, the real return is the "bx lr" above, so the
311 // return(0) is never executed and the function returns with the value
312 // you expect in R0.
313 return(0);
314 }
315 #else
316 uint32_t __attribute__((naked))
CPUbasepriGet(void)317 CPUbasepriGet(void)
318 {
319 uint32_t ui32Ret;
320
321 // Read BASEPRI.
322 __asm volatile (" mrs %0, BASEPRI\n"
323 " bx lr\n"
324 : "=r"(ui32Ret)
325 );
326
327 // The return is handled in the inline assembly, but the compiler will
328 // still complain if there is not an explicit return here (despite the fact
329 // that this does not result in any code being produced because of the
330 // naked attribute).
331 return(ui32Ret);
332 }
333 #endif
334
335 //*****************************************************************************
336 //
337 // Provide a small delay
338 //
339 //*****************************************************************************
340 #if defined(DOXYGEN)
341 void
CPUdelay(uint32_t ui32Count)342 CPUdelay(uint32_t ui32Count)
343 {
344 // This function is written in assembly. See cpu.c for compiler specific implementation.
345 }
346 #elif defined(__IAR_SYSTEMS_ICC__)
347 void
CPUdelay(uint32_t ui32Count)348 CPUdelay(uint32_t ui32Count)
349 {
350 // Loop the specified number of times
351 __asm("CPUdelay:\n"
352 " subs r0, #1\n"
353 " bne.n CPUdelay\n"
354 " bx lr");
355 #pragma diag_suppress=Pe940
356 }
357 #pragma diag_default=Pe940
358 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
359 __asm void
CPUdelay(uint32_t ui32Count)360 CPUdelay(uint32_t ui32Count)
361 {
362 // Delay the specified number of times (3 cycles pr. loop)
363 CPUdel
364 subs r0, #1;
365 bne CPUdel;
366 bx lr;
367 }
368 #elif defined(__TI_COMPILER_VERSION__)
369 // For CCS implement this function in pure assembly. This prevents the TI
370 // compiler from doing funny things with the optimizer.
371
372 // Loop the specified number of times
373 __asm(" .sect \".text:NOROM_CPUdelay\"\n"
374 " .clink\n"
375 " .thumbfunc NOROM_CPUdelay\n"
376 " .thumb\n"
377 " .global NOROM_CPUdelay\n"
378 "NOROM_CPUdelay:\n"
379 " subs r0, #1\n"
380 " bne.n NOROM_CPUdelay\n"
381 " bx lr\n");
382 #elif defined(__clang__)
383 void
CPUdelay(uint32_t ui32Count)384 CPUdelay(uint32_t ui32Count)
385 {
386 // Loop the specified number of times
387 __asm("CPUdel:\n"
388 " subs r0, #1\n"
389 " bne.n CPUdel\n"
390 " bx lr");
391 }
392 #else
393 // GCC
394 void __attribute__((naked))
CPUdelay(uint32_t ui32Count)395 CPUdelay(uint32_t ui32Count)
396 {
397 // Loop the specified number of times
398 __asm volatile ("%=: subs %0, #1\n"
399 " bne %=b\n"
400 " bx lr\n"
401 : /* No output */
402 : "r" (ui32Count)
403 );
404 }
405 #endif
406