]> begriffs open source - freertos/blob - portable/oWatcom/16BitDOS/Flsh186/port.c
Style: uncrusitfy
[freertos] / portable / oWatcom / 16BitDOS / Flsh186 / 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  * Changes from V1.00:\r
29  *\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
33  +\r
34  + Changes from V1.2.0:\r
35  +\r
36  + portRESET_PIC() is now called last thing before the end of the preemptive\r
37  +    tick routine.\r
38  +\r
39  + Changes from V2.6.1\r
40  +\r
41  + Replaced the sUsingPreemption variable with the configUSE_PREEMPTION\r
42  +    macro to be consistent with the later ports.\r
43  */\r
44 \r
45 /*-----------------------------------------------------------\r
46 * Implementation of functions defined in portable.h for the Flashlite 186\r
47 * port.\r
48 *----------------------------------------------------------*/\r
49 \r
50 #include <stdlib.h>\r
51 #include <i86.h>\r
52 #include <dos.h>\r
53 #include <setjmp.h>\r
54 \r
55 #include "FreeRTOS.h"\r
56 #include "task.h"\r
57 #include "portasm.h"\r
58 \r
59 /*lint -e950 Non ANSI reserved words okay in this file only. */\r
60 \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
64 \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
68 \r
69 /* Setup the hardware to generate the required tick frequency. */\r
70 static void prvSetTickFrequency( uint32_t ulTickRateHz );\r
71 \r
72 /* Set the hardware back to the state as per before the scheduler started. */\r
73 static void prvExitFunction( void );\r
74 \r
75 #if configUSE_PREEMPTION == 1\r
76 \r
77 /* Tick service routine used by the scheduler when preemptive scheduling is\r
78  * being used. */\r
79     static void __interrupt __far prvPreemptiveTick( void );\r
80 #else\r
81 \r
82 /* Tick service routine used by the scheduler when cooperative scheduling is\r
83  * being used. */\r
84     static void __interrupt __far prvNonPreemptiveTick( void );\r
85 #endif\r
86 \r
87 /* Trap routine used by taskYIELD() to manually cause a context switch. */\r
88 static void __interrupt __far prvYieldProcessor( void );\r
89 \r
90 /*lint -e956 File scopes necessary here. */\r
91 \r
92 /* Set true when the vectors are set so the scheduler will service the tick. */\r
93 static int16_t sSchedulerRunning = pdFALSE;\r
94 \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
97 \r
98 /* Used to restore the original DOS context when the scheduler is ended. */\r
99 static jmp_buf xJumpBuf;\r
100 \r
101 /*lint +e956 */\r
102 \r
103 /*-----------------------------------------------------------*/\r
104 BaseType_t xPortStartScheduler( void )\r
105 {\r
106     /* This is called with interrupts already disabled. */\r
107 \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
111 \r
112     /* Put our manual switch (yield) function on a known\r
113      * vector. */\r
114     _dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor );\r
115 \r
116     #if configUSE_PREEMPTION == 1\r
117         {\r
118             /* Put our tick switch function on the timer interrupt. */\r
119             _dos_setvect( portTIMER_INT_NUMBER, prvPreemptiveTick );\r
120         }\r
121     #else\r
122         {\r
123             /* We want the timer interrupt to just increment the tick count. */\r
124             _dos_setvect( portTIMER_INT_NUMBER, prvNonPreemptiveTick );\r
125         }\r
126     #endif\r
127 \r
128     prvSetTickFrequency( configTICK_RATE_HZ );\r
129 \r
130     /* Clean up function if we want to return to DOS. */\r
131     if( setjmp( xJumpBuf ) != 0 )\r
132     {\r
133         prvExitFunction();\r
134         sSchedulerRunning = pdFALSE;\r
135     }\r
136     else\r
137     {\r
138         sSchedulerRunning = pdTRUE;\r
139 \r
140         /* Kick off the scheduler by setting up the context of the first task. */\r
141         portFIRST_CONTEXT();\r
142     }\r
143 \r
144     return sSchedulerRunning;\r
145 }\r
146 /*-----------------------------------------------------------*/\r
147 \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
152     {\r
153         /* Get the scheduler to update the task states following the tick. */\r
154         if( xTaskIncrementTick() != pdFALSE )\r
155         {\r
156             /* Switch in the context of the next task to be run. */\r
157             portSWITCH_CONTEXT();\r
158         }\r
159 \r
160         /* Reset the PIC ready for the next time. */\r
161         portRESET_PIC();\r
162     }\r
163 #else  /* if configUSE_PREEMPTION == 1 */\r
164     static void __interrupt __far prvNonPreemptiveTick( void )\r
165     {\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
169         portRESET_PIC();\r
170     }\r
171 #endif /* if configUSE_PREEMPTION == 1 */\r
172 /*-----------------------------------------------------------*/\r
173 \r
174 static void __interrupt __far prvYieldProcessor( void )\r
175 {\r
176     /* Switch in the context of the next task to be run. */\r
177     portSWITCH_CONTEXT();\r
178 }\r
179 /*-----------------------------------------------------------*/\r
180 \r
181 void vPortEndScheduler( void )\r
182 {\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
187 }\r
188 /*-----------------------------------------------------------*/\r
189 \r
190 static void prvExitFunction( void )\r
191 {\r
192     const uint16_t usTimerDisable = 0x0000;\r
193     uint16_t       usTimer0Control;\r
194 \r
195     /* Interrupts should be disabled here anyway - but no\r
196      * harm in making sure. */\r
197     portDISABLE_INTERRUPTS();\r
198 \r
199     if( sSchedulerRunning == pdTRUE )\r
200     {\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
204     }\r
205 \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
210 \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
215 \r
216 \r
217     portENABLE_INTERRUPTS();\r
218 }\r
219 /*-----------------------------------------------------------*/\r
220 \r
221 static void prvSetTickFrequency( uint32_t ulTickRateHz )\r
222 {\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
229 \r
230 /* ( CPU frequency / 4 ) / clock 2 max count [inpw( 0xff62 ) = 7] */\r
231 \r
232     const uint32_t ulClockFrequency        = 0x7f31a0;\r
233 \r
234     uint32_t       ulTimerCount            = ulClockFrequency / ulTickRateHz;\r
235 \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
239 \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
244 }\r
245 \r
246 \r
247 /*lint +e950 */\r