2 * FreeRTOS Kernel V10.3.1
\r
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
28 * Changes from V1.00:
\r
30 + Call to taskYIELD() from within tick ISR has been replaced by the more
\r
31 + efficient portSWITCH_CONTEXT().
\r
32 + ISR function definitions renamed to include the prv prefix.
\r
34 + Changes from V1.2.0:
\r
36 + portRESET_PIC() is now called last thing before the end of the preemptive
\r
39 + Changes from V2.6.1
\r
41 + Replaced the sUsingPreemption variable with the configUSE_PREEMPTION
\r
42 + macro to be consistent with the later ports.
\r
45 /*-----------------------------------------------------------
\r
46 * Implementation of functions defined in portable.h for the Flashlite 186
\r
48 *----------------------------------------------------------*/
\r
55 #include "FreeRTOS.h"
\r
57 #include "portasm.h"
\r
59 /*lint -e950 Non ANSI reserved words okay in this file only. */
\r
61 #define portTIMER_EOI_TYPE ( 8 )
\r
62 #define portRESET_PIC() portOUTPUT_WORD( ( uint16_t ) 0xff22, portTIMER_EOI_TYPE )
\r
63 #define portTIMER_INT_NUMBER 0x12
\r
65 #define portTIMER_1_CONTROL_REGISTER ( ( uint16_t ) 0xff5e )
\r
66 #define portTIMER_0_CONTROL_REGISTER ( ( uint16_t ) 0xff56 )
\r
67 #define portTIMER_INTERRUPT_ENABLE ( ( uint16_t ) 0x2000 )
\r
69 /* Setup the hardware to generate the required tick frequency. */
\r
70 static void prvSetTickFrequency( uint32_t ulTickRateHz );
\r
72 /* Set the hardware back to the state as per before the scheduler started. */
\r
73 static void prvExitFunction( void );
\r
75 #if configUSE_PREEMPTION == 1
\r
77 /* Tick service routine used by the scheduler when preemptive scheduling is
\r
79 static void __interrupt __far prvPreemptiveTick( void );
\r
82 /* Tick service routine used by the scheduler when cooperative scheduling is
\r
84 static void __interrupt __far prvNonPreemptiveTick( void );
\r
87 /* Trap routine used by taskYIELD() to manually cause a context switch. */
\r
88 static void __interrupt __far prvYieldProcessor( void );
\r
90 /*lint -e956 File scopes necessary here. */
\r
92 /* Set true when the vectors are set so the scheduler will service the tick. */
\r
93 static int16_t sSchedulerRunning = pdFALSE;
\r
95 /* Points to the original routine installed on the vector we use for manual context switches. This is then used to restore the original routine during prvExitFunction(). */
\r
96 static void( __interrupt __far * pxOldSwitchISR )();
\r
98 /* Used to restore the original DOS context when the scheduler is ended. */
\r
99 static jmp_buf xJumpBuf;
\r
103 /*-----------------------------------------------------------*/
\r
104 BaseType_t xPortStartScheduler( void )
\r
106 /* This is called with interrupts already disabled. */
\r
108 /* Remember what was on the interrupts we are going to use
\r
109 * so we can put them back later if required. */
\r
110 pxOldSwitchISR = _dos_getvect( portSWITCH_INT_NUMBER );
\r
112 /* Put our manual switch (yield) function on a known
\r
114 _dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor );
\r
116 #if configUSE_PREEMPTION == 1
\r
118 /* Put our tick switch function on the timer interrupt. */
\r
119 _dos_setvect( portTIMER_INT_NUMBER, prvPreemptiveTick );
\r
123 /* We want the timer interrupt to just increment the tick count. */
\r
124 _dos_setvect( portTIMER_INT_NUMBER, prvNonPreemptiveTick );
\r
128 prvSetTickFrequency( configTICK_RATE_HZ );
\r
130 /* Clean up function if we want to return to DOS. */
\r
131 if( setjmp( xJumpBuf ) != 0 )
\r
134 sSchedulerRunning = pdFALSE;
\r
138 sSchedulerRunning = pdTRUE;
\r
140 /* Kick off the scheduler by setting up the context of the first task. */
\r
141 portFIRST_CONTEXT();
\r
144 return sSchedulerRunning;
\r
146 /*-----------------------------------------------------------*/
\r
148 /* The tick ISR used depend on whether or not the preemptive or cooperative
\r
149 * kernel is being used. */
\r
150 #if configUSE_PREEMPTION == 1
\r
151 static void __interrupt __far prvPreemptiveTick( void )
\r
153 /* Get the scheduler to update the task states following the tick. */
\r
154 if( xTaskIncrementTick() != pdFALSE )
\r
156 /* Switch in the context of the next task to be run. */
\r
157 portSWITCH_CONTEXT();
\r
160 /* Reset the PIC ready for the next time. */
\r
163 #else /* if configUSE_PREEMPTION == 1 */
\r
164 static void __interrupt __far prvNonPreemptiveTick( void )
\r
166 /* Same as preemptive tick, but the cooperative scheduler is being used
\r
167 * so we don't have to switch in the context of the next task. */
\r
168 xTaskIncrementTick();
\r
171 #endif /* if configUSE_PREEMPTION == 1 */
\r
172 /*-----------------------------------------------------------*/
\r
174 static void __interrupt __far prvYieldProcessor( void )
\r
176 /* Switch in the context of the next task to be run. */
\r
177 portSWITCH_CONTEXT();
\r
179 /*-----------------------------------------------------------*/
\r
181 void vPortEndScheduler( void )
\r
183 /* Jump back to the processor state prior to starting the
\r
184 * scheduler. This means we are not going to be using a
\r
185 * task stack frame so the task can be deleted. */
\r
186 longjmp( xJumpBuf, 1 );
\r
188 /*-----------------------------------------------------------*/
\r
190 static void prvExitFunction( void )
\r
192 const uint16_t usTimerDisable = 0x0000;
\r
193 uint16_t usTimer0Control;
\r
195 /* Interrupts should be disabled here anyway - but no
\r
196 * harm in making sure. */
\r
197 portDISABLE_INTERRUPTS();
\r
199 if( sSchedulerRunning == pdTRUE )
\r
201 /* Put back the switch interrupt routines that was in place
\r
202 * before the scheduler started. */
\r
203 _dos_setvect( portSWITCH_INT_NUMBER, pxOldSwitchISR );
\r
206 /* Disable the timer used for the tick to ensure the scheduler is
\r
207 * not called before restoring interrupts. There was previously nothing
\r
208 * on this timer so there is no old ISR to restore. */
\r
209 portOUTPUT_WORD( portTIMER_1_CONTROL_REGISTER, usTimerDisable );
\r
211 /* Restart the DOS tick. */
\r
212 usTimer0Control = portINPUT_WORD( portTIMER_0_CONTROL_REGISTER );
\r
213 usTimer0Control |= portTIMER_INTERRUPT_ENABLE;
\r
214 portOUTPUT_WORD( portTIMER_0_CONTROL_REGISTER, usTimer0Control );
\r
217 portENABLE_INTERRUPTS();
\r
219 /*-----------------------------------------------------------*/
\r
221 static void prvSetTickFrequency( uint32_t ulTickRateHz )
\r
223 const uint16_t usMaxCountRegister = 0xff5a;
\r
224 const uint16_t usTimerPriorityRegister = 0xff32;
\r
225 const uint16_t usTimerEnable = 0xC000;
\r
226 const uint16_t usRetrigger = 0x0001;
\r
227 const uint16_t usTimerHighPriority = 0x0000;
\r
228 uint16_t usTimer0Control;
\r
230 /* ( CPU frequency / 4 ) / clock 2 max count [inpw( 0xff62 ) = 7] */
\r
232 const uint32_t ulClockFrequency = 0x7f31a0;
\r
234 uint32_t ulTimerCount = ulClockFrequency / ulTickRateHz;
\r
236 portOUTPUT_WORD( portTIMER_1_CONTROL_REGISTER, usTimerEnable | portTIMER_INTERRUPT_ENABLE | usRetrigger );
\r
237 portOUTPUT_WORD( usMaxCountRegister, ( uint16_t ) ulTimerCount );
\r
238 portOUTPUT_WORD( usTimerPriorityRegister, usTimerHighPriority );
\r
240 /* Stop the DOS tick - don't do this if you want to maintain a TOD clock. */
\r
241 usTimer0Control = portINPUT_WORD( portTIMER_0_CONTROL_REGISTER );
\r
242 usTimer0Control &= ~portTIMER_INTERRUPT_ENABLE;
\r
243 portOUTPUT_WORD( portTIMER_0_CONTROL_REGISTER, usTimer0Control );
\r