]> begriffs open source - freertos/blob - portable/Paradigm/Tern_EE/large_untested/port.c
Style: uncrustify
[freertos] / portable / Paradigm / Tern_EE / large_untested / port.c
1 /*\r
2  * FreeRTOS Kernel V10.3.1\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  */\r
26 \r
27 \r
28 /*-----------------------------------------------------------\r
29 * Implementation of functions defined in portable.h for the Tern EE 186\r
30 * port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Library includes. */\r
34 #include <embedded.h>\r
35 #include <ae.h>\r
36 \r
37 /* Scheduler includes. */\r
38 #include "FreeRTOS.h"\r
39 #include "task.h"\r
40 #include "portasm.h"\r
41 \r
42 /* The timer increments every four clocks, hence the divide by 4. */\r
43 #define portTIMER_COMPARE                 ( uint16_t ) ( ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) / ( uint32_t ) 4 )\r
44 \r
45 /* From the RDC data sheet. */\r
46 #define portENABLE_TIMER_AND_INTERRUPT    ( uint16_t ) 0xe001\r
47 \r
48 /* Interrupt control. */\r
49 #define portEIO_REGISTER                  0xff22\r
50 #define portCLEAR_INTERRUPT               0x0008\r
51 \r
52 /* Setup the hardware to generate the required tick frequency. */\r
53 static void prvSetupTimerInterrupt( void );\r
54 \r
55 /* The ISR used depends on whether the preemptive or cooperative scheduler\r
56  * is being used. */\r
57 #if ( configUSE_PREEMPTION == 1 )\r
58 \r
59 /* Tick service routine used by the scheduler when preemptive scheduling is\r
60  * being used. */\r
61     static void __interrupt __far prvPreemptiveTick( void );\r
62 #else\r
63 \r
64 /* Tick service routine used by the scheduler when cooperative scheduling is\r
65  * being used. */\r
66     static void __interrupt __far prvNonPreemptiveTick( void );\r
67 #endif\r
68 \r
69 /* Trap routine used by taskYIELD() to manually cause a context switch. */\r
70 static void __interrupt __far prvYieldProcessor( void );\r
71 \r
72 /* The timer initialisation functions leave interrupts enabled,\r
73  * which is not what we want.  This ISR is installed temporarily in case\r
74  * the timer fires before we get a change to disable interrupts again. */\r
75 static void __interrupt __far prvDummyISR( void );\r
76 \r
77 /*-----------------------------------------------------------*/\r
78 /* See header file for description. */\r
79 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
80                                      TaskFunction_t pxCode,\r
81                                      void * pvParameters )\r
82 {\r
83     StackType_t DS_Reg = 0;\r
84 \r
85     /* Place a few bytes of known values on the bottom of the stack.\r
86      * This is just useful for debugging. */\r
87 \r
88     *pxTopOfStack = 0x1111;\r
89     pxTopOfStack--;\r
90     *pxTopOfStack = 0x2222;\r
91     pxTopOfStack--;\r
92     *pxTopOfStack = 0x3333;\r
93     pxTopOfStack--;\r
94 \r
95     /* We are going to start the scheduler using a return from interrupt\r
96      * instruction to load the program counter, so first there would be the\r
97      * function call with parameters preamble. */\r
98 \r
99     *pxTopOfStack = FP_SEG( pvParameters );\r
100     pxTopOfStack--;\r
101     *pxTopOfStack = FP_OFF( pvParameters );\r
102     pxTopOfStack--;\r
103     *pxTopOfStack = FP_SEG( pxCode );\r
104     pxTopOfStack--;\r
105     *pxTopOfStack = FP_OFF( pxCode );\r
106     pxTopOfStack--;\r
107 \r
108     /* Next the status register and interrupt return address. */\r
109     *pxTopOfStack = portINITIAL_SW;\r
110     pxTopOfStack--;\r
111     *pxTopOfStack = FP_SEG( pxCode );\r
112     pxTopOfStack--;\r
113     *pxTopOfStack = FP_OFF( pxCode );\r
114     pxTopOfStack--;\r
115 \r
116     /* The remaining registers would be pushed on the stack by our context\r
117      * switch function.  These are loaded with values simply to make debugging\r
118      * easier. */\r
119     *pxTopOfStack = ( StackType_t ) 0xAAAA; /* AX */\r
120     pxTopOfStack--;\r
121     *pxTopOfStack = ( StackType_t ) 0xBBBB; /* BX */\r
122     pxTopOfStack--;\r
123     *pxTopOfStack = ( StackType_t ) 0xCCCC; /* CX */\r
124     pxTopOfStack--;\r
125     *pxTopOfStack = ( StackType_t ) 0xDDDD; /* DX */\r
126     pxTopOfStack--;\r
127     *pxTopOfStack = ( StackType_t ) 0xEEEE; /* ES */\r
128     pxTopOfStack--;\r
129 \r
130     /* We need the true data segment. */\r
131     __asm {\r
132         MOV DS_Reg, DS\r
133     };\r
134 \r
135     *pxTopOfStack = DS_Reg;                 /* DS */\r
136     pxTopOfStack--;\r
137     *pxTopOfStack = ( StackType_t ) 0x0123; /* SI */\r
138     pxTopOfStack--;\r
139     *pxTopOfStack = ( StackType_t ) 0xDDDD; /* DI */\r
140     pxTopOfStack--;\r
141     *pxTopOfStack = ( StackType_t ) 0xBBBB; /* BP */\r
142 \r
143     return pxTopOfStack;\r
144 }\r
145 /*-----------------------------------------------------------*/\r
146 \r
147 BaseType_t xPortStartScheduler( void )\r
148 {\r
149     /* This is called with interrupts already disabled. */\r
150 \r
151     /* Put our manual switch (yield) function on a known\r
152      * vector. */\r
153     setvect( portSWITCH_INT_NUMBER, prvYieldProcessor );\r
154 \r
155     /* Setup the tick interrupt. */\r
156     prvSetupTimerInterrupt();\r
157 \r
158     /* Kick off the scheduler by setting up the context of the first task. */\r
159     portFIRST_CONTEXT();\r
160 \r
161     /* Should not get here! */\r
162     return pdFALSE;\r
163 }\r
164 /*-----------------------------------------------------------*/\r
165 \r
166 static void __interrupt __far prvDummyISR( void )\r
167 {\r
168     /* The timer initialisation functions leave interrupts enabled,\r
169      * which is not what we want.  This ISR is installed temporarily in case\r
170      * the timer fires before we get a change to disable interrupts again. */\r
171     outport( portEIO_REGISTER, portCLEAR_INTERRUPT );\r
172 }\r
173 /*-----------------------------------------------------------*/\r
174 \r
175 /* The ISR used depends on whether the preemptive or cooperative scheduler\r
176  * is being used. */\r
177 #if ( configUSE_PREEMPTION == 1 )\r
178     static void __interrupt __far prvPreemptiveTick( void )\r
179     {\r
180         /* Get the scheduler to update the task states following the tick. */\r
181         if( xTaskIncrementTick() != pdFALSE )\r
182         {\r
183             /* Switch in the context of the next task to be run. */\r
184             portSWITCH_CONTEXT();\r
185         }\r
186 \r
187         /* Reset interrupt. */\r
188         outport( portEIO_REGISTER, portCLEAR_INTERRUPT );\r
189     }\r
190 #else /* if ( configUSE_PREEMPTION == 1 ) */\r
191     static void __interrupt __far prvNonPreemptiveTick( void )\r
192     {\r
193         /* Same as preemptive tick, but the cooperative scheduler is being used\r
194          * so we don't have to switch in the context of the next task. */\r
195         xTaskIncrementTick();\r
196 \r
197         /* Reset interrupt. */\r
198         outport( portEIO_REGISTER, portCLEAR_INTERRUPT );\r
199     }\r
200 #endif /* if ( configUSE_PREEMPTION == 1 ) */\r
201 /*-----------------------------------------------------------*/\r
202 \r
203 static void __interrupt __far prvYieldProcessor( void )\r
204 {\r
205     /* Switch in the context of the next task to be run. */\r
206     portSWITCH_CONTEXT();\r
207 }\r
208 /*-----------------------------------------------------------*/\r
209 \r
210 void vPortEndScheduler( void )\r
211 {\r
212     /* Not implemented. */\r
213 }\r
214 /*-----------------------------------------------------------*/\r
215 \r
216 static void prvSetupTimerInterrupt( void )\r
217 {\r
218     const uint16_t usTimerACompare = portTIMER_COMPARE, usTimerAMode = portENABLE_TIMER_AND_INTERRUPT;\r
219     const uint16_t usT2_IRQ = 0x13;\r
220 \r
221     /* Configure the timer, the dummy handler is used here as the init\r
222      * function leaves interrupts enabled. */\r
223     t2_init( usTimerAMode, usTimerACompare, prvDummyISR );\r
224 \r
225     /* Disable interrupts again before installing the real handlers. */\r
226     portDISABLE_INTERRUPTS();\r
227 \r
228     #if ( configUSE_PREEMPTION == 1 )\r
229 \r
230         /* Tick service routine used by the scheduler when preemptive scheduling is\r
231          * being used. */\r
232         setvect( usT2_IRQ, prvPreemptiveTick );\r
233     #else\r
234 \r
235         /* Tick service routine used by the scheduler when cooperative scheduling is\r
236          * being used. */\r
237         setvect( usT2_IRQ, prvNonPreemptiveTick );\r
238     #endif\r
239 }\r