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