]> begriffs open source - freertos/blob - portable/Softune/MB96340/port.c
FreeRTOS MPU: Remove MPU region number check (#1261)
[freertos] / portable / Softune / MB96340 / port.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 #include "FreeRTOS.h"
30 #include "task.h"
31
32 /*-----------------------------------------------------------
33  * Implementation of functions defined in portable.h for the 16FX port.
34  *----------------------------------------------------------*/
35
36 /*
37  * Get current value of DPR and ADB registers
38  */
39 StackType_t xGet_DPR_ADB_bank( void );
40
41 /*
42  * Get current value of DTB and PCB registers
43  */
44 StackType_t xGet_DTB_PCB_bank( void );
45
46 /*
47  * Sets up the periodic ISR used for the RTOS tick.  This uses RLT0, but
48  * can be done using any given RLT.
49  */
50 static void prvSetupRLT0Interrupt( void );
51
52 /*-----------------------------------------------------------*/
53
54 /*
55  * We require the address of the pxCurrentTCB variable, but don't want to know
56  * any details of its type.
57  */
58 typedef void TCB_t;
59 extern volatile TCB_t * volatile pxCurrentTCB;
60
61 /*-----------------------------------------------------------*/
62
63 /*
64  * Macro to save a task context to the task stack. This macro  copies the
65  * saved context (AH:AL, DPR:ADB, DTB:PCB , PC and PS) from  the   system
66  * stack to task stack pointed by user stack pointer ( USP  for SMALL and
67  * MEDIUM memory model amd USB:USP for COMPACT  and LARGE memory model ),
68  * then  it pushes the general purpose registers RW0-RW7  on  to the task
69  * stack. Finally the  resultant  stack  pointer  value is saved into the
70  * task  control  block  so  it  can  be retrieved the next time the task
71  * executes.
72  */
73 #if( ( configMEMMODEL == portSMALL ) || ( configMEMMODEL == portMEDIUM ) )
74
75     #define portSAVE_CONTEXT()                                          \
76             {   __asm(" POPW  A ");                                     \
77                 __asm(" AND  CCR,#H'DF ");                              \
78                 __asm(" PUSHW  A ");                                    \
79                 __asm(" OR   CCR,#H'20 ");                              \
80                 __asm(" POPW  A ");                                     \
81                 __asm(" AND  CCR,#H'DF ");                              \
82                 __asm(" PUSHW  A ");                                    \
83                 __asm(" OR   CCR,#H'20 ");                              \
84                 __asm(" POPW  A ");                                     \
85                 __asm(" AND  CCR,#H'DF ");                              \
86                 __asm(" PUSHW  A ");                                    \
87                 __asm(" OR   CCR,#H'20 ");                              \
88                 __asm(" POPW  A ");                                     \
89                 __asm(" AND  CCR,#H'DF ");                              \
90                 __asm(" PUSHW  A ");                                    \
91                 __asm(" OR   CCR,#H'20 ");                              \
92                 __asm(" POPW  A ");                                     \
93                 __asm(" AND  CCR,#H'DF ");                              \
94                 __asm(" PUSHW  A ");                                    \
95                 __asm(" OR   CCR,#H'20 ");                              \
96                 __asm(" POPW  A ");                                     \
97                 __asm(" AND  CCR,#H'DF ");                              \
98                 __asm(" PUSHW  A ");                                    \
99                 __asm(" PUSHW (RW0,RW1,RW2,RW3,RW4,RW5,RW6,RW7) ");     \
100                 __asm(" MOVW A, _pxCurrentTCB ");                       \
101                 __asm(" MOVW A, SP ");                                  \
102                 __asm(" SWAPW ");                                       \
103                 __asm(" MOVW @AL, AH ");                                \
104                 __asm(" OR   CCR,#H'20 ");                              \
105             }
106
107 /*
108  * Macro to restore a task context from the task stack. This is
109  * effectively the reverse of SAVE_CONTEXT(). First the stack pointer
110  * value (USP for SMALL and MEDIUM memory model amd USB:USP for COMPACT
111  * and LARGE memory model ) is loaded from the task  control block. Next
112  * the value of all the general purpose registers RW0-RW7 is retrieved.
113  * Finally it copies of the context ( AH:AL, DPR:ADB, DTB:PCB, PC and PS)
114  * of the task to be executed upon RETI from user stack to system stack.
115  */
116
117     #define portRESTORE_CONTEXT()                                       \
118             {   __asm(" MOVW A, _pxCurrentTCB ");                       \
119                 __asm(" MOVW A, @A ");                                  \
120                 __asm(" AND  CCR,#H'DF ");                              \
121                 __asm(" MOVW SP, A ");                                  \
122                 __asm(" POPW (RW0,RW1,RW2,RW3,RW4,RW5,RW6,RW7) ");      \
123                 __asm(" POPW  A ");                                     \
124                 __asm(" OR   CCR,#H'20 ");                              \
125                 __asm(" PUSHW  A ");                                    \
126                 __asm(" AND  CCR,#H'DF ");                              \
127                 __asm(" POPW  A ");                                     \
128                 __asm(" OR   CCR,#H'20 ");                              \
129                 __asm(" PUSHW  A ");                                    \
130                 __asm(" AND  CCR,#H'DF ");                              \
131                 __asm(" POPW  A ");                                     \
132                 __asm(" OR   CCR,#H'20 ");                              \
133                 __asm(" PUSHW  A ");                                    \
134                 __asm(" AND  CCR,#H'DF ");                              \
135                 __asm(" POPW  A ");                                     \
136                 __asm(" OR   CCR,#H'20 ");                              \
137                 __asm(" PUSHW  A ");                                    \
138                 __asm(" AND  CCR,#H'DF ");                              \
139                 __asm(" POPW  A ");                                     \
140                 __asm(" OR   CCR,#H'20 ");                              \
141                 __asm(" PUSHW  A ");                                    \
142                 __asm(" AND  CCR,#H'DF ");                              \
143                 __asm(" POPW  A ");                                     \
144                 __asm(" OR   CCR,#H'20 ");                              \
145                 __asm(" PUSHW  A ");                                    \
146             }
147
148 #elif( ( configMEMMODEL == portCOMPACT ) || ( configMEMMODEL == portLARGE ) )
149
150     #define portSAVE_CONTEXT()                                          \
151             {   __asm(" POPW  A ");                                     \
152                 __asm(" AND  CCR,#H'DF ");                              \
153                 __asm(" PUSHW  A ");                                    \
154                 __asm(" OR   CCR,#H'20 ");                              \
155                 __asm(" POPW  A ");                                     \
156                 __asm(" AND  CCR,#H'DF ");                              \
157                 __asm(" PUSHW  A ");                                    \
158                 __asm(" OR   CCR,#H'20 ");                              \
159                 __asm(" POPW  A ");                                     \
160                 __asm(" AND  CCR,#H'DF ");                              \
161                 __asm(" PUSHW  A ");                                    \
162                 __asm(" OR   CCR,#H'20 ");                              \
163                 __asm(" POPW  A ");                                     \
164                 __asm(" AND  CCR,#H'DF ");                              \
165                 __asm(" PUSHW  A ");                                    \
166                 __asm(" OR   CCR,#H'20 ");                              \
167                 __asm(" POPW  A ");                                     \
168                 __asm(" AND  CCR,#H'DF ");                              \
169                 __asm(" PUSHW  A ");                                    \
170                 __asm(" OR   CCR,#H'20 ");                              \
171                 __asm(" POPW  A ");                                     \
172                 __asm(" AND  CCR,#H'DF ");                              \
173                 __asm(" PUSHW  A ");                                    \
174                 __asm(" PUSHW (RW0,RW1,RW2,RW3,RW4,RW5,RW6,RW7) ");     \
175                 __asm(" MOVL A, _pxCurrentTCB ");                       \
176                 __asm(" MOVL RL2, A ");                                 \
177                 __asm(" MOVW A, SP ");                                  \
178                 __asm(" MOVW @RL2+0, A ");                              \
179                 __asm(" MOV A, USB ");                                  \
180                 __asm(" MOV @RL2+2, A ");                               \
181             }
182
183     #define portRESTORE_CONTEXT()                                       \
184             {   __asm(" MOVL A, _pxCurrentTCB ");                       \
185                 __asm(" MOVL RL2, A ");                                 \
186                 __asm(" MOVW A, @RL2+0 ");                              \
187                 __asm(" AND  CCR,#H'DF ");                              \
188                 __asm(" MOVW SP, A ");                                  \
189                 __asm(" MOV A, @RL2+2 ");                               \
190                 __asm(" MOV USB, A ");                                  \
191                 __asm(" POPW (RW0,RW1,RW2,RW3,RW4,RW5,RW6,RW7) ");      \
192                 __asm(" POPW  A ");                                     \
193                 __asm(" OR   CCR,#H'20 ");                              \
194                 __asm(" PUSHW  A ");                                    \
195                 __asm(" AND  CCR,#H'DF ");                              \
196                 __asm(" POPW  A ");                                     \
197                 __asm(" OR   CCR,#H'20 ");                              \
198                 __asm(" PUSHW  A ");                                    \
199                 __asm(" AND  CCR,#H'DF ");                              \
200                 __asm(" POPW  A ");                                     \
201                 __asm(" OR   CCR,#H'20 ");                              \
202                 __asm(" PUSHW  A ");                                    \
203                 __asm(" AND  CCR,#H'DF ");                              \
204                 __asm(" POPW  A ");                                     \
205                 __asm(" OR   CCR,#H'20 ");                              \
206                 __asm(" PUSHW  A ");                                    \
207                 __asm(" AND  CCR,#H'DF ");                              \
208                 __asm(" POPW  A ");                                     \
209                 __asm(" OR   CCR,#H'20 ");                              \
210                 __asm(" PUSHW  A ");                                    \
211                 __asm(" AND  CCR,#H'DF ");                              \
212                 __asm(" POPW  A ");                                     \
213                 __asm(" OR   CCR,#H'20 ");                              \
214                 __asm(" PUSHW  A ");                                    \
215             }
216 #endif
217
218 /*-----------------------------------------------------------*/
219
220 /*
221  * Functions for obtaining the current value  of  DPR:ADB, DTB:PCB bank registers
222  */
223
224 #pragma asm
225
226         .GLOBAL    _xGet_DPR_ADB_bank
227         .GLOBAL    _xGet_DTB_PCB_bank
228         .SECTION   CODE, CODE, ALIGN=1
229
230 _xGet_DPR_ADB_bank:
231
232     MOV A, DPR
233     SWAP
234     MOV A, ADB
235     ORW A
236     #if configMEMMODEL == portMEDIUM || configMEMMODEL == portLARGE
237         RETP
238     #elif configMEMMODEL == portSMALL || configMEMMODEL == portCOMPACT
239         RET
240     #endif
241
242
243 _xGet_DTB_PCB_bank:
244
245     MOV A, DTB
246     SWAP
247     MOV A, PCB
248     ORW A
249     #if configMEMMODEL == portMEDIUM || configMEMMODEL == portLARGE
250         RETP
251     #elif configMEMMODEL == portSMALL || configMEMMODEL == portCOMPACT
252         RET
253     #endif
254
255 #pragma endasm
256 /*-----------------------------------------------------------*/
257
258 /*
259  * Initialise the stack of a task to look exactly as if a call to
260  * portSAVE_CONTEXT had been called.
261  *
262  * See the header file portable.h.
263  */
264 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
265 {
266     /* Place a few bytes of known values on the bottom of the stack.
267     This is just useful for debugging. */
268     *pxTopOfStack = 0x1111;
269     pxTopOfStack--;
270     *pxTopOfStack = 0x2222;
271     pxTopOfStack--;
272     *pxTopOfStack = 0x3333;
273     pxTopOfStack--;
274
275     /* Once the task is called the task  would  push  the  pointer to the
276     parameter onto the stack. Hence here the pointer would be copied to the stack
277     first.  When using the COMPACT or LARGE memory model the pointer would be 24
278     bits, and when using the SMALL or MEDIUM memory model the pointer would be 16
279     bits. */
280     #if( ( configMEMMODEL == portCOMPACT ) || ( configMEMMODEL == portLARGE ) )
281     {
282         *pxTopOfStack = ( StackType_t ) ( ( uint32_t ) ( pvParameters ) >> 16 );
283         pxTopOfStack--;
284     }
285     #endif
286
287     *pxTopOfStack = ( StackType_t ) ( pvParameters );
288     pxTopOfStack--;
289
290     /* This is redundant push to the stack. This is required in order to introduce
291     an offset so that the task accesses a parameter correctly that is passed on to
292     the task stack. */
293     #if( ( configMEMMODEL == portMEDIUM ) || ( configMEMMODEL == portLARGE ) )
294     {
295         *pxTopOfStack = ( xGet_DTB_PCB_bank() & 0xff00 ) | ( ( ( int32_t ) ( pxCode ) >> 16 ) & 0xff );
296         pxTopOfStack--;
297     }
298     #endif
299
300     /* This is redundant push to the stack. This is required in order to introduce
301     an offset so the task correctly accesses the parameter passed on the task stack. */
302     *pxTopOfStack = ( StackType_t ) ( pxCode );
303     pxTopOfStack--;
304
305     /* PS - User Mode, ILM=7, RB=0, Interrupts enabled,USP */
306     *pxTopOfStack = 0xE0C0;
307     pxTopOfStack--;
308
309     /* PC */
310     *pxTopOfStack = ( StackType_t ) ( pxCode );
311     pxTopOfStack--;
312
313     /* DTB | PCB */
314     #if configMEMMODEL == portSMALL || configMEMMODEL == portCOMPACT
315     {
316         *pxTopOfStack = xGet_DTB_PCB_bank();
317         pxTopOfStack--;
318     }
319     #endif
320
321     /* DTB | PCB, in case of MEDIUM and LARGE memory models, PCB would be used
322     along with PC to indicate the start address of the function. */
323     #if( ( configMEMMODEL == portMEDIUM ) || ( configMEMMODEL == portLARGE ) )
324     {
325         *pxTopOfStack = ( xGet_DTB_PCB_bank() & 0xff00 ) | ( ( ( int32_t ) ( pxCode ) >> 16 ) & 0xff );
326         pxTopOfStack--;
327     }
328     #endif
329
330     /* DPR | ADB  */
331     *pxTopOfStack = xGet_DPR_ADB_bank();
332     pxTopOfStack--;
333
334     /* AL */
335     *pxTopOfStack = ( StackType_t ) 0x9999;
336     pxTopOfStack--;
337
338     /* AH */
339     *pxTopOfStack = ( StackType_t ) 0xAAAA;
340     pxTopOfStack--;
341
342     /* Next the general purpose registers. */
343     *pxTopOfStack = ( StackType_t ) 0x7777; /* RW7 */
344     pxTopOfStack--;
345     *pxTopOfStack = ( StackType_t ) 0x6666; /* RW6 */
346     pxTopOfStack--;
347     *pxTopOfStack = ( StackType_t ) 0x5555; /* RW5 */
348     pxTopOfStack--;
349     *pxTopOfStack = ( StackType_t ) 0x4444; /* RW4 */
350     pxTopOfStack--;
351     *pxTopOfStack = ( StackType_t ) 0x3333; /* RW3 */
352     pxTopOfStack--;
353     *pxTopOfStack = ( StackType_t ) 0x2222; /* RW2 */
354     pxTopOfStack--;
355     *pxTopOfStack = ( StackType_t ) 0x1111; /* RW1 */
356     pxTopOfStack--;
357     *pxTopOfStack = ( StackType_t ) 0x8888; /* RW0 */
358
359     return pxTopOfStack;
360 }
361 /*-----------------------------------------------------------*/
362
363 static void prvSetupRLT0Interrupt( void )
364 {
365 /* The peripheral clock divided by 16 is used by the timer. */
366 const uint16_t usReloadValue = ( uint16_t ) ( ( ( configCLKP1_CLOCK_HZ / configTICK_RATE_HZ ) / 16UL ) - 1UL );
367
368     /* set reload value = 34999+1, TICK Interrupt after 10 ms @ 56MHz of CLKP1 */
369     TMRLR0 = usReloadValue;
370
371     /* prescaler 1:16, reload, interrupt enable, count enable, trigger */
372     TMCSR0 = 0x041B;
373 }
374 /*-----------------------------------------------------------*/
375
376 BaseType_t xPortStartScheduler( void )
377 {
378     /* Setup the hardware to generate the tick. */
379     prvSetupRLT0Interrupt();
380
381     /* Restore the context of the first task that is going to run. */
382     portRESTORE_CONTEXT();
383
384     /* Simulate a function call end as generated by the compiler.  We will now
385     jump to the start of the task the context of which we have just restored. */
386     __asm(" reti ");
387
388
389     /* Should not get here. */
390     return pdTRUE;
391 }
392 /*-----------------------------------------------------------*/
393
394 void vPortEndScheduler( void )
395 {
396     /* Not implemented - unlikely to ever be required as there is nothing to
397     return to. */
398 }
399
400 /*-----------------------------------------------------------*/
401
402 /*
403  * The interrupt service routine used depends on whether the pre-emptive
404  * scheduler is being used or not.
405  */
406
407 #if configUSE_PREEMPTION == 1
408
409     /*
410      * Tick ISR for preemptive scheduler.  We can use a __nosavereg attribute
411      * as the context is to be saved by the portSAVE_CONTEXT() macro, not the
412      * compiler generated code.  The tick count is incremented after the context
413      * is saved.
414      */
415     __nosavereg __interrupt void prvRLT0_TICKISR( void )
416     {
417         /* Disable interrupts so that portSAVE_CONTEXT() is not interrupted */
418         __DI();
419
420         /* Save the context of the interrupted task. */
421         portSAVE_CONTEXT();
422
423         /* Enable interrupts */
424         __EI();
425
426         /* Clear RLT0 interrupt flag */
427         TMCSR0_UF = 0;
428
429         /* Increment the tick count then switch to the highest priority task
430         that is ready to run. */
431         if( xTaskIncrementTick() != pdFALSE )
432         {
433             vTaskSwitchContext();
434         }
435
436         /* Disable interrupts so that portRESTORE_CONTEXT() is not interrupted */
437         __DI();
438
439         /* Restore the context of the new task. */
440         portRESTORE_CONTEXT();
441
442         /* Enable interrupts */
443         __EI();
444     }
445
446 #else
447
448     /*
449      * Tick ISR for the cooperative scheduler.  All this does is increment the
450      * tick count.  We don't need to switch context, this can only be done by
451      * manual calls to taskYIELD();
452      */
453     __interrupt void prvRLT0_TICKISR( void )
454     {
455         /* Clear RLT0 interrupt flag */
456         TMCSR0_UF = 0;
457
458         xTaskIncrementTick();
459     }
460
461 #endif
462
463 /*-----------------------------------------------------------*/
464
465 /*
466  * Manual context switch. We can use a __nosavereg attribute  as the context
467  * is to be saved by the portSAVE_CONTEXT() macro, not the compiler generated
468  * code.
469  */
470 __nosavereg __interrupt void vPortYield( void )
471 {
472     /* Save the context of the interrupted task. */
473     portSAVE_CONTEXT();
474
475     /* Switch to the highest priority task that is ready to run. */
476     vTaskSwitchContext();
477
478     /* Restore the context of the new task. */
479     portRESTORE_CONTEXT();
480 }
481 /*-----------------------------------------------------------*/
482
483 __nosavereg __interrupt void vPortYieldDelayed( void )
484 {
485     /* Disable interrupts so that portSAVE_CONTEXT() is not interrupted */
486     __DI();
487
488     /* Save the context of the interrupted task. */
489     portSAVE_CONTEXT();
490
491     /* Enable interrupts */
492     __EI();
493
494     /* Clear delayed interrupt flag */
495     __asm (" CLRB  03A4H:0 ");
496
497     /* Switch to the highest priority task that is ready to run. */
498     vTaskSwitchContext();
499
500     /* Disable interrupts so that portSAVE_CONTEXT() is not interrupted */
501     __DI();
502
503     /* Restore the context of the new task. */
504     portRESTORE_CONTEXT();
505
506     /* Enable interrupts */
507     __EI();
508 }
509 /*-----------------------------------------------------------*/