]> begriffs open source - freertos/blob - portable/IAR/RX700v3_DPFPU/port.c
[AUTO][RELEASE]: Bump file header version to "10.4.3"
[freertos] / portable / IAR / RX700v3_DPFPU / port.c
1 /*
2  * FreeRTOS Kernel V10.4.3
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*-----------------------------------------------------------
29 * Implementation of functions defined in portable.h for the RXv3 DPFPU port.
30 *----------------------------------------------------------*/
31
32 #warning Testing for DFPU support in this port is not yet complete
33
34 /* Scheduler includes. */
35 #include "FreeRTOS.h"
36 #include "task.h"
37
38 /* Library includes. */
39 #include "string.h"
40
41 /* Hardware specifics. */
42 #if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 )
43
44     #include "platform.h"
45
46 #else /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */
47
48     #include "iodefine.h"
49
50 #endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */
51
52 /*-----------------------------------------------------------*/
53
54 /* Tasks should start with interrupts enabled and in Supervisor mode, therefore
55  * PSW is set with U and I set, and PM and IPL clear. */
56 #define portINITIAL_PSW     ( ( StackType_t ) 0x00030000 )
57 #define portINITIAL_FPSW    ( ( StackType_t ) 0x00000100 )
58 #define portINITIAL_DPSW    ( ( StackType_t ) 0x00000100 )
59 #define portINITIAL_DCMR    ( ( StackType_t ) 0x00000000 )
60 #define portINITIAL_DECNT   ( ( StackType_t ) 0x00000001 )
61
62 /* Tasks are not created with a DPFPU context, but can be given a DPFPU context
63  * after they have been created.  A variable is stored as part of the tasks context
64  * that holds portNO_DPFPU_CONTEXT if the task does not have a DPFPU context, or
65  * any other value if the task does have a DPFPU context. */
66 #define portNO_DPFPU_CONTEXT    ( ( StackType_t ) 0 )
67 #define portHAS_DPFPU_CONTEXT   ( ( StackType_t ) 1 )
68
69 /* The space on the stack required to hold the DPFPU data registers.  This is 16
70  * 64-bit registers. */
71 #define portDPFPU_DATA_REGISTER_WORDS   ( 16 * 2 )
72
73 /*-----------------------------------------------------------*/
74
75 /*
76  * Function to start the first task executing - written in asm code as direct
77  * access to registers is required.
78  */
79 static void prvStartFirstTask( void );
80
81 /*
82  * Software interrupt handler.  Performs the actual context switch (saving and
83  * restoring of registers).  Written in asm code as direct register access is
84  * required.
85  */
86 __interrupt void vSoftwareInterruptISR( void );
87
88 /*
89  * The tick ISR handler.  The peripheral used is configured by the application
90  * via a hook/callback function.
91  */
92 __interrupt void vTickISR( void );
93
94 /*-----------------------------------------------------------*/
95
96 /* Saved as part of the task context.  If ulPortTaskHasDPFPUContext is non-zero
97  * then a DPFPU context must be saved and restored for the task. */
98 #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
99
100     StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT;
101
102 #endif /* configUSE_TASK_DPFPU_SUPPORT */
103
104 /* This is accessed by the inline assembler functions so is file scope for
105  * convenience. */
106 extern void * pxCurrentTCB;
107 extern void vTaskSwitchContext( void );
108
109 /*-----------------------------------------------------------*/
110
111 /*
112  * See header file for description.
113  */
114 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
115                                      TaskFunction_t pxCode,
116                                      void * pvParameters )
117 {
118     /* R0 is not included as it is the stack pointer. */
119
120     *pxTopOfStack = 0x00;
121     pxTopOfStack--;
122     *pxTopOfStack = portINITIAL_PSW;
123     pxTopOfStack--;
124     *pxTopOfStack = ( StackType_t ) pxCode;
125
126     /* When debugging it can be useful if every register is set to a known
127      * value.  Otherwise code space can be saved by just setting the registers
128      * that need to be set. */
129     #ifdef USE_FULL_REGISTER_INITIALISATION
130         {
131             pxTopOfStack--;
132             *pxTopOfStack = 0xffffffff; /* r15. */
133             pxTopOfStack--;
134             *pxTopOfStack = 0xeeeeeeee;
135             pxTopOfStack--;
136             *pxTopOfStack = 0xdddddddd;
137             pxTopOfStack--;
138             *pxTopOfStack = 0xcccccccc;
139             pxTopOfStack--;
140             *pxTopOfStack = 0xbbbbbbbb;
141             pxTopOfStack--;
142             *pxTopOfStack = 0xaaaaaaaa;
143             pxTopOfStack--;
144             *pxTopOfStack = 0x99999999;
145             pxTopOfStack--;
146             *pxTopOfStack = 0x88888888;
147             pxTopOfStack--;
148             *pxTopOfStack = 0x77777777;
149             pxTopOfStack--;
150             *pxTopOfStack = 0x66666666;
151             pxTopOfStack--;
152             *pxTopOfStack = 0x55555555;
153             pxTopOfStack--;
154             *pxTopOfStack = 0x44444444;
155             pxTopOfStack--;
156             *pxTopOfStack = 0x33333333;
157             pxTopOfStack--;
158             *pxTopOfStack = 0x22222222;
159             pxTopOfStack--;
160         }
161     #else /* ifdef USE_FULL_REGISTER_INITIALISATION */
162         {
163             pxTopOfStack -= 15;
164         }
165     #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */
166
167     *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */
168     pxTopOfStack--;
169     *pxTopOfStack = portINITIAL_FPSW;
170     pxTopOfStack--;
171     *pxTopOfStack = 0x11111111; /* Accumulator 1. */
172     pxTopOfStack--;
173     *pxTopOfStack = 0x22222222; /* Accumulator 1. */
174     pxTopOfStack--;
175     *pxTopOfStack = 0x33333333; /* Accumulator 1. */
176     pxTopOfStack--;
177     *pxTopOfStack = 0x44444444; /* Accumulator 0. */
178     pxTopOfStack--;
179     *pxTopOfStack = 0x55555555; /* Accumulator 0. */
180     pxTopOfStack--;
181     *pxTopOfStack = 0x66666666; /* Accumulator 0. */
182
183     #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
184         {
185             /* The task will start without a DPFPU context.  A task that
186              * uses the DPFPU hardware must call vPortTaskUsesDPFPU() before
187              * executing any floating point instructions. */
188             pxTopOfStack--;
189             *pxTopOfStack = portNO_DPFPU_CONTEXT;
190         }
191     #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 )
192         {
193             /* The task will start with a DPFPU context.  Leave enough
194              * space for the registers - and ensure they are initialised if desired. */
195             #ifdef USE_FULL_REGISTER_INITIALISATION
196                 {
197                     pxTopOfStack -= 2;
198                     *(double *)pxTopOfStack = 1515.1515; /* DR15. */
199                     pxTopOfStack -= 2;
200                     *(double *)pxTopOfStack = 1414.1414; /* DR14. */
201                     pxTopOfStack -= 2;
202                     *(double *)pxTopOfStack = 1313.1313; /* DR13. */
203                     pxTopOfStack -= 2;
204                     *(double *)pxTopOfStack = 1212.1212; /* DR12. */
205                     pxTopOfStack -= 2;
206                     *(double *)pxTopOfStack = 1111.1111; /* DR11. */
207                     pxTopOfStack -= 2;
208                     *(double *)pxTopOfStack = 1010.1010; /* DR10. */
209                     pxTopOfStack -= 2;
210                     *(double *)pxTopOfStack =  909.0909; /* DR9. */
211                     pxTopOfStack -= 2;
212                     *(double *)pxTopOfStack =  808.0808; /* DR8. */
213                     pxTopOfStack -= 2;
214                     *(double *)pxTopOfStack =  707.0707; /* DR7. */
215                     pxTopOfStack -= 2;
216                     *(double *)pxTopOfStack =  606.0606; /* DR6. */
217                     pxTopOfStack -= 2;
218                     *(double *)pxTopOfStack =  505.0505; /* DR5. */
219                     pxTopOfStack -= 2;
220                     *(double *)pxTopOfStack =  404.0404; /* DR4. */
221                     pxTopOfStack -= 2;
222                     *(double *)pxTopOfStack =  303.0303; /* DR3. */
223                     pxTopOfStack -= 2;
224                     *(double *)pxTopOfStack =  202.0202; /* DR2. */
225                     pxTopOfStack -= 2;
226                     *(double *)pxTopOfStack =  101.0101; /* DR1. */
227                     pxTopOfStack -= 2;
228                     *(double *)pxTopOfStack = 9876.54321;/* DR0. */
229                 }
230             #else /* ifdef USE_FULL_REGISTER_INITIALISATION */
231                 {
232                     pxTopOfStack -= portDPFPU_DATA_REGISTER_WORDS;
233                     memset( pxTopOfStack, 0x00, portDPFPU_DATA_REGISTER_WORDS * sizeof( StackType_t ) );
234                 }
235             #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */
236             pxTopOfStack--;
237             *pxTopOfStack = portINITIAL_DECNT; /* DECNT. */
238             pxTopOfStack--;
239             *pxTopOfStack = portINITIAL_DCMR;  /* DCMR. */
240             pxTopOfStack--;
241             *pxTopOfStack = portINITIAL_DPSW;  /* DPSW. */
242         }
243     #elif ( configUSE_TASK_DPFPU_SUPPORT == 0 )
244         {
245             /* Omit DPFPU support. */
246         }
247     #else /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */
248         {
249             #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined.
250         }
251     #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */
252
253     return pxTopOfStack;
254 }
255 /*-----------------------------------------------------------*/
256
257 #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
258
259     void vPortTaskUsesDPFPU( void )
260     {
261         /* A task is registering the fact that it needs a DPFPU context.  Set the
262          * DPFPU flag (which is saved as part of the task context). */
263         ulPortTaskHasDPFPUContext = portHAS_DPFPU_CONTEXT;
264     }
265
266 #endif /* configUSE_TASK_DPFPU_SUPPORT */
267 /*-----------------------------------------------------------*/
268
269 BaseType_t xPortStartScheduler( void )
270 {
271     extern void vApplicationSetupTimerInterrupt( void );
272
273     /* Use pxCurrentTCB just so it does not get optimised away. */
274     if( pxCurrentTCB != NULL )
275     {
276         /* Call an application function to set up the timer that will generate the
277          * tick interrupt.  This way the application can decide which peripheral to
278          * use.  A demo application is provided to show a suitable example. */
279         vApplicationSetupTimerInterrupt();
280
281         /* Enable the software interrupt. */
282         _IEN( _ICU_SWINT ) = 1;
283
284         /* Ensure the software interrupt is clear. */
285         _IR( _ICU_SWINT ) = 0;
286
287         /* Ensure the software interrupt is set to the kernel priority. */
288         _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY;
289
290         /* Start the first task. */
291         prvStartFirstTask();
292     }
293
294     /* Should not get here. */
295     return pdFAIL;
296 }
297 /*-----------------------------------------------------------*/
298
299 void vPortEndScheduler( void )
300 {
301     /* Not implemented in ports where there is nothing to return to.
302      * Artificially force an assert. */
303     configASSERT( pxCurrentTCB == NULL );
304
305     /* The following line is just to prevent the symbol getting optimised away. */
306     ( void ) vTaskSwitchContext();
307 }
308 /*-----------------------------------------------------------*/
309
310 static void prvStartFirstTask( void )
311 {
312     __asm volatile
313     (
314
315         /* When starting the scheduler there is nothing that needs moving to the
316          * interrupt stack because the function is not called from an interrupt.
317          * Just ensure the current stack is the user stack. */
318         "SETPSW         U                                               \n"\
319
320
321         /* Obtain the location of the stack associated with which ever task
322          * pxCurrentTCB is currently pointing to. */
323         "MOV.L          #_pxCurrentTCB, R15             \n"\
324         "MOV.L          [R15], R15                              \n"\
325         "MOV.L          [R15], R0                               \n"\
326
327
328         /* Restore the registers from the stack of the task pointed to by
329          * pxCurrentTCB. */
330
331         #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
332
333             /* The restored ulPortTaskHasDPFPUContext is to be zero here.
334              * So, it is never necessary to restore the DPFPU context here. */
335             "POP                R15                                                                     \n"\
336             "MOV.L              #_ulPortTaskHasDPFPUContext, R14        \n"\
337             "MOV.L              R15, [R14]                                                      \n"\
338
339         #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 )
340
341             /* Restore the DPFPU context. */
342             "DPOPM.L    DPSW-DECNT                              \n"\
343             "DPOPM.D    DR0-DR15                                \n"\
344
345         #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */
346
347         "POP            R15                                             \n"\
348
349         /* Accumulator low 32 bits. */
350         "MVTACLO        R15, A0                                 \n"\
351         "POP            R15                                             \n"\
352
353         /* Accumulator high 32 bits. */
354         "MVTACHI        R15, A0                                 \n"\
355         "POP            R15                                             \n"\
356
357         /* Accumulator guard. */
358         "MVTACGU        R15, A0                                 \n"\
359         "POP            R15                                             \n"\
360
361         /* Accumulator low 32 bits. */
362         "MVTACLO        R15, A1                                 \n"\
363         "POP            R15                                             \n"\
364
365         /* Accumulator high 32 bits. */
366         "MVTACHI        R15, A1                                 \n"\
367         "POP            R15                                             \n"\
368
369         /* Accumulator guard. */
370         "MVTACGU        R15, A1                                 \n"\
371         "POP            R15                                             \n"\
372
373         /* Floating point status word. */
374         "MVTC           R15, FPSW                               \n"\
375
376         /* R1 to R15 - R0 is not included as it is the SP. */
377         "POPM           R1-R15                                  \n"\
378
379         /* This pops the remaining registers. */
380         "RTE                                                            \n"\
381         "NOP                                                            \n"\
382         "NOP                                                            \n"
383     );
384 }
385 /*-----------------------------------------------------------*/
386
387 #pragma vector = VECT( ICU, SWINT )
388 __interrupt void vSoftwareInterruptISR( void )
389 {
390     __asm volatile
391     (
392         /* Re-enable interrupts. */
393         "SETPSW         I                                                       \n"\
394
395
396         /* Move the data that was automatically pushed onto the interrupt stack when
397          * the interrupt occurred from the interrupt stack to the user stack.
398          *
399          * R15 is saved before it is clobbered. */
400         "PUSH.L         R15                                                     \n"\
401
402         /* Read the user stack pointer. */
403         "MVFC           USP, R15                                        \n"\
404
405         /* Move the address down to the data being moved. */
406         "SUB            #12, R15                                        \n"\
407         "MVTC           R15, USP                                        \n"\
408
409         /* Copy the data across, R15, then PC, then PSW. */
410         "MOV.L          [ R0 ], [ R15 ]                         \n"\
411         "MOV.L          4[ R0 ], 4[ R15 ]                       \n"\
412         "MOV.L          8[ R0 ], 8[ R15 ]                       \n"\
413
414         /* Move the interrupt stack pointer to its new correct position. */
415         "ADD            #12, R0                                         \n"\
416
417         /* All the rest of the registers are saved directly to the user stack. */
418         "SETPSW         U                                                       \n"\
419
420         /* Save the rest of the general registers (R15 has been saved already). */
421         "PUSHM          R1-R14                                          \n"\
422
423         /* Save the FPSW and accumulators. */
424         "MVFC           FPSW, R15                                       \n"\
425         "PUSH.L         R15                                                     \n"\
426         "MVFACGU        #0, A1, R15                                     \n"\
427         "PUSH.L         R15                                                     \n"\
428         "MVFACHI        #0, A1, R15                                     \n"\
429         "PUSH.L         R15                                                     \n"\
430         "MVFACLO        #0, A1, R15                                     \n" /* Low order word. */ \
431         "PUSH.L         R15                                                     \n"\
432         "MVFACGU        #0, A0, R15                                     \n"\
433         "PUSH.L         R15                                                     \n"\
434         "MVFACHI        #0, A0, R15                                     \n"\
435         "PUSH.L         R15                                                     \n"\
436         "MVFACLO        #0, A0, R15                                     \n" /* Low order word. */ \
437         "PUSH.L         R15                                                     \n"\
438
439         #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
440
441             /* Does the task have a DPFPU context that needs saving?  If
442              * ulPortTaskHasDPFPUContext is 0 then no. */
443             "MOV.L              #_ulPortTaskHasDPFPUContext, R15        \n"\
444             "MOV.L              [R15], R15                                                      \n"\
445             "CMP                #0, R15                                                         \n"\
446
447             /* Save the DPFPU context, if any. */
448             "BEQ.B              __lab1                                          \n"\
449             "DPUSHM.D   DR0-DR15                                        \n"\
450             "DPUSHM.L   DPSW-DECNT                                      \n"\
451             "__lab1:                                                            \n"\
452
453             /* Save ulPortTaskHasDPFPUContext itself. */
454             "PUSH.L             R15                                                     \n"\
455
456         #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 )
457
458             /* Save the DPFPU context, always. */
459             "DPUSHM.D   DR0-DR15                                        \n"\
460             "DPUSHM.L   DPSW-DECNT                                      \n"\
461
462         #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */
463
464
465         /* Save the stack pointer to the TCB. */
466         "MOV.L          #_pxCurrentTCB, R15                     \n"\
467         "MOV.L          [ R15 ], R15                            \n"\
468         "MOV.L          R0, [ R15 ]                                     \n"\
469
470
471         /* Ensure the interrupt mask is set to the syscall priority while the kernel
472          * structures are being accessed. */
473         "MVTIPL         %0                                                      \n"\
474
475         /* Select the next task to run. */
476         "BSR.A          _vTaskSwitchContext                     \n"\
477
478         /* Reset the interrupt mask as no more data structure access is required. */
479         "MVTIPL         %1                                                      \n"\
480
481
482         /* Load the stack pointer of the task that is now selected as the Running
483          * state task from its TCB. */
484         "MOV.L          #_pxCurrentTCB,R15                      \n"\
485         "MOV.L          [ R15 ], R15                            \n"\
486         "MOV.L          [ R15 ], R0                                     \n"\
487
488
489         /* Restore the context of the new task.  The PSW (Program Status Word) and
490          * PC will be popped by the RTE instruction. */
491
492         #if ( configUSE_TASK_DPFPU_SUPPORT == 1 )
493
494             /* Is there a DPFPU context to restore?  If the restored
495              * ulPortTaskHasDPFPUContext is zero then no. */
496             "POP                R15                                                                     \n"\
497             "MOV.L              #_ulPortTaskHasDPFPUContext, R14        \n"\
498             "MOV.L              R15, [R14]                                                      \n"\
499             "CMP                #0, R15                                                         \n"\
500
501             /* Restore the DPFPU context, if any. */
502             "BEQ.B              __lab2                                          \n"\
503             "DPOPM.L    DPSW-DECNT                                      \n"\
504             "DPOPM.D    DR0-DR15                                        \n"\
505             "__lab2:                                                            \n"\
506
507         #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 )
508
509             /* Restore the DPFPU context, always. */
510             "DPOPM.L    DPSW-DECNT                                      \n"\
511             "DPOPM.D    DR0-DR15                                        \n"\
512
513         #endif /* if( configUSE_TASK_DPFPU_SUPPORT == 1 ) */
514
515         "POP            R15                                                     \n"\
516
517         /* Accumulator low 32 bits. */
518         "MVTACLO        R15, A0                                         \n"\
519         "POP            R15                                                     \n"\
520
521         /* Accumulator high 32 bits. */
522         "MVTACHI        R15, A0                                         \n"\
523         "POP            R15                                                     \n"\
524
525         /* Accumulator guard. */
526         "MVTACGU        R15, A0                                         \n"\
527         "POP            R15                                                     \n"\
528
529         /* Accumulator low 32 bits. */
530         "MVTACLO        R15, A1                                         \n"\
531         "POP            R15                                                     \n"\
532
533         /* Accumulator high 32 bits. */
534         "MVTACHI        R15, A1                                         \n"\
535         "POP            R15                                                     \n"\
536
537         /* Accumulator guard. */
538         "MVTACGU        R15, A1                                         \n"\
539         "POP            R15                                                     \n"\
540         "MVTC           R15, FPSW                                       \n"\
541         "POPM           R1-R15                                          \n"\
542         "RTE                                                                    \n"\
543         "NOP                                                                    \n"\
544         "NOP                                                                      "
545         portCDT_NO_PARSE( :: ) "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configKERNEL_INTERRUPT_PRIORITY )
546     );
547 }
548 /*-----------------------------------------------------------*/
549
550 #pragma vector = _VECT( configTICK_VECTOR )
551 __interrupt void vTickISR( void )
552 {
553     /* Re-enable interrupts. */
554     __enable_interrupt();
555
556     /* Increment the tick, and perform any processing the new tick value
557      * necessitates.  Ensure IPL is at the max syscall value first. */
558     __set_interrupt_level( configMAX_SYSCALL_INTERRUPT_PRIORITY );
559     {
560         if( xTaskIncrementTick() != pdFALSE )
561         {
562             taskYIELD();
563         }
564     }
565     __set_interrupt_level( configKERNEL_INTERRUPT_PRIORITY );
566 }
567 /*-----------------------------------------------------------*/