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