]> begriffs open source - cmsis-freertos/blob - Demo/PPC440_Xilinx_Virtex5_GCC/RTOSDemo/flop/flop-reg-test.c
Updated to FreeRTOS V10.0.1
[cmsis-freertos] / Demo / PPC440_Xilinx_Virtex5_GCC / RTOSDemo / flop / flop-reg-test.c
1 /*
2  * FreeRTOS Kernel V10.0.1
3  * Copyright (C) 2017 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  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*
29  * Tests the floating point context save and restore mechanism.
30  *
31  * Two tasks are created - each of which is allocated a buffer of 
32  * portNO_FLOP_REGISTERS_TO_SAVE 32bit variables into which the flop context
33  * of the task is saved when the task is switched out, and from which the
34  * flop context of the task is restored when the task is switch in.  Prior to 
35  * the tasks being created each position in the two buffers is filled with a 
36  * unique value - this way the flop context of each task is different.
37  *
38  * The two test tasks never block so are always in either the Running or
39  * Ready state.  They execute at the lowest priority so will get pre-empted
40  * regularly, although the yield frequently so will not get much execution
41  * time.  The lack of execution time is not a problem as its only the 
42  * switching in and out that is being tested.
43  *
44  * Whenever a task is moved from the Ready to the Running state its flop 
45  * context will be loaded from the buffer, but while the task is in the
46  * Running state the buffer is not used and can contain any value - in this
47  * case and for test purposes the task itself clears the buffer to zero.  
48  * The next time the task is moved out of the Running state into the
49  * Ready state the flop context will once more get saved to the buffer - 
50  * overwriting the zeros.
51  *
52  * Therefore whenever the task is not in the Running state its buffer contains
53  * the most recent values of its floating point registers - the zeroing out
54  * of the buffer while the task was executing being used to ensure the values 
55  * the buffer contains are not stale.
56  *
57  * When neither test task is in the Running state the buffers should contain
58  * the unique values allocated before the tasks were created.  If so then
59  * the floating point context has been maintained.  This check is performed
60  * by the 'check' task (defined in main.c) by calling 
61  * xAreFlopRegisterTestsStillRunning().
62  *
63  * The test tasks also increment a value each time they execute.
64  * xAreFlopRegisterTestsStillRunning() also checks that this value has changed
65  * since it last ran to ensure the test tasks are still getting processing time.
66  */
67
68 /* Standard includes files. */
69 #include <string.h>
70
71 /* Scheduler include files. */
72 #include "FreeRTOS.h"
73 #include "task.h"
74
75 /*-----------------------------------------------------------*/
76
77 #define flopNUMBER_OF_TASKS             2
78 #define flopSTART_VALUE ( 0x1 )
79
80 /*-----------------------------------------------------------*/
81
82 /* The two test tasks as described at the top of this file. */
83 static void vFlopTest1( void *pvParameters );
84 static void vFlopTest2( void *pvParameters );
85
86 /*-----------------------------------------------------------*/
87
88 /* Buffers into which the flop registers will be saved.  There is a buffer for 
89 both tasks. */
90 static volatile unsigned long ulFlopRegisters[ flopNUMBER_OF_TASKS ][ portNO_FLOP_REGISTERS_TO_SAVE ];
91
92 /* Variables that are incremented by the tasks to indicate that they are still
93 running. */
94 static volatile unsigned long ulFlop1CycleCount = 0, ulFlop2CycleCount = 0;
95
96 /*-----------------------------------------------------------*/
97
98 void vStartFlopRegTests( void )
99 {
100 TaskHandle_t xTaskJustCreated;
101 unsigned portBASE_TYPE x, y, z = flopSTART_VALUE;
102
103         /* Fill the arrays into which the flop registers are to be saved with 
104         known values.  These are the values that will be written to the flop
105         registers when the tasks start, and as the tasks do not perform any
106         flop operations the values should never change.  Each position in the
107         buffer contains a different value so the flop context of each task
108         will be different. */
109         for( x = 0; x < flopNUMBER_OF_TASKS; x++ )
110         {
111                 for( y = 0; y < ( portNO_FLOP_REGISTERS_TO_SAVE - 1); y++ )
112                 {
113                         ulFlopRegisters[ x ][ y ] = z;
114                         z++;
115                 }
116         }
117
118
119         /* Create the first task. */
120         xTaskCreate( vFlopTest1, "flop1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskJustCreated );
121
122         /* The task     tag value is a value that can be associated with a task, but 
123         is not used by the scheduler itself.  Its use is down to the application so
124         it makes a convenient place in this case to store the pointer to the buffer
125         into which the flop context of the task will be stored.  The first created
126         task uses ulFlopRegisters[ 0 ], the second ulFlopRegisters[ 1 ]. */
127         vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 0 ][ 0 ] ) );
128
129         /* Do the same for the second task. */
130         xTaskCreate( vFlopTest2, "flop2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskJustCreated );
131         vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 1 ][ 0 ] ) );
132 }
133 /*-----------------------------------------------------------*/
134
135 static void vFlopTest1( void *pvParameters )
136 {
137         /* Just to remove compiler warning. */
138         ( void ) pvParameters;
139
140         for( ;; )
141         {
142                 /* The values from the buffer should have now been written to the flop
143                 registers.  Clear the buffer to ensure the same values then get written
144                 back the next time the task runs.  Being preempted during this memset
145                 could cause the test to fail, hence the critical section. */
146                 portENTER_CRITICAL();
147                         memset( ( void * ) ulFlopRegisters[ 0 ], 0x00, ( portNO_FLOP_REGISTERS_TO_SAVE * sizeof( unsigned portBASE_TYPE ) ) );
148                 portEXIT_CRITICAL();
149
150                 /* We don't have to do anything other than indicate that we are 
151                 still running. */
152                 ulFlop1CycleCount++;
153                 taskYIELD();
154         }
155 }
156 /*-----------------------------------------------------------*/
157
158 static void vFlopTest2( void *pvParameters )
159 {
160         /* Just to remove compiler warning. */
161         ( void ) pvParameters;
162
163         for( ;; )
164         {
165                 /* The values from the buffer should have now been written to the flop
166                 registers.  Clear the buffer to ensure the same values then get written
167                 back the next time the task runs. */
168                 portENTER_CRITICAL();
169                         memset( ( void * ) ulFlopRegisters[ 1 ], 0x00, ( portNO_FLOP_REGISTERS_TO_SAVE * sizeof( unsigned portBASE_TYPE ) ) );
170                 portEXIT_CRITICAL();
171
172                 /* We don't have to do anything other than indicate that we are 
173                 still running. */
174                 ulFlop2CycleCount++;
175                 taskYIELD();
176         }
177 }
178 /*-----------------------------------------------------------*/
179
180 portBASE_TYPE xAreFlopRegisterTestsStillRunning( void )
181 {
182 portBASE_TYPE xReturn = pdPASS;
183 unsigned portBASE_TYPE x, y, z = flopSTART_VALUE;
184 static unsigned long ulLastFlop1CycleCount = 0, ulLastFlop2CycleCount = 0;
185
186         /* Called from the 'check' task.
187         
188         The flop tasks cannot be currently running, check their saved registers
189         are as expected.  The tests tasks do not perform any flop operations so
190         their registers should be as per their initial setting. */
191         for( x = 0; x < flopNUMBER_OF_TASKS; x++ )
192         {
193                 for( y = 0; y < ( portNO_FLOP_REGISTERS_TO_SAVE - 1 ); y++ )
194                 {
195                         if( ulFlopRegisters[ x ][ y ] != z )
196                         {
197                                 xReturn = pdFAIL;
198                                 break;
199                         }
200
201                         z++;
202                 }
203         }
204
205         /* Check both tasks have actually been swapped in and out since this function
206         last executed. */
207         if( ulFlop1CycleCount == ulLastFlop1CycleCount )
208         {
209                 xReturn = pdFAIL;
210         }
211
212         if( ulFlop2CycleCount == ulLastFlop2CycleCount )
213         {
214                 xReturn = pdFAIL;
215         }
216
217         ulLastFlop1CycleCount = ulFlop1CycleCount;
218         ulLastFlop2CycleCount = ulFlop2CycleCount;
219
220         return xReturn;
221 }
222