xref: /Kernel-v10.6.2/portable/WizC/PIC18/port.c (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1 /*
2  * FreeRTOS Kernel V10.6.2
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 /*
30 Changes from V3.2.1
31     + CallReturn Depth increased from 8 to 10 levels to accomodate wizC/fedC V12.
32 
33 Changes from V3.2.0
34     + TBLPTRU is now initialised to zero during the initial stack creation of a new task. This solves
35     an error on devices with more than 64kB ROM.
36 
37 Changes from V3.0.0
38     + ucCriticalNesting is now initialised to 0x7F to prevent interrupts from being
39           handled before the scheduler is started.
40 
41 Changes from V3.0.1
42 */
43 
44 /* Scheduler include files. */
45 #include <FreeRTOS.h>
46 #include <task.h>
47 
48 #include <malloc.h>
49 
50 /*---------------------------------------------------------------------------
51  * Implementation of functions defined in portable.h for the WizC PIC18 port.
52  *---------------------------------------------------------------------------*/
53 
54 /*
55  * We require the address of the pxCurrentTCB variable, but don't want to
56  * know any details of its type.
57  */
58 typedef void TCB_t;
59 extern volatile TCB_t * volatile pxCurrentTCB;
60 
61 /*
62  * Define minimal-stack constants
63  * -----
64  * FSR's:
65  *      STATUS, WREG, BSR, PRODH, PRODL, FSR0H, FSR0L,
66  *      FSR1H, FSR1L,TABLAT, (TBLPTRU), TBLPTRH, TBLPTRL,
67  *      (PCLATU), PCLATH
68  *      sfr's within parenthesis only on devices > 64kB
69  * -----
70  * Call/Return stack:
71  *       2 bytes per entry on devices <= 64kB
72  *       3 bytes per entry on devices >  64kB
73  * -----
74  * Other bytes:
75  *       2 bytes: FunctionParameter for initial taskcode
76  *       1 byte : Number of entries on call/return stack
77  *       1 byte : ucCriticalNesting
78  *      16 bytes: Free space on stack
79  */
80 #if _ROMSIZE > 0x8000
81     #define portSTACK_FSR_BYTES             ( 15 )
82     #define portSTACK_CALLRETURN_ENTRY_SIZE (  3 )
83 #else
84     #define portSTACK_FSR_BYTES             ( 13 )
85     #define portSTACK_CALLRETURN_ENTRY_SIZE (  2 )
86 #endif
87 
88 #define portSTACK_MINIMAL_CALLRETURN_DEPTH  ( 10 )
89 #define portSTACK_OTHER_BYTES               ( 20 )
90 
91 uint16_t usCalcMinStackSize     = 0;
92 
93 /*-----------------------------------------------------------*/
94 
95 /*
96  * We initialise ucCriticalNesting to the middle value an
97  * uint8_t can contain. This way portENTER_CRITICAL()
98  * and portEXIT_CRITICAL() can be called without interrupts
99  * being enabled before the scheduler starts.
100  */
101 register uint8_t ucCriticalNesting = 0x7F;
102 
103 /*-----------------------------------------------------------*/
104 
105 /*
106  * Initialise the stack of a new task.
107  * See portSAVE_CONTEXT macro for description.
108  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)109 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
110 {
111 uint8_t ucScratch;
112     /*
113      * Get the size of the RAMarea in page 0 used by the compiler
114      * We do this here already to avoid W-register conflicts.
115      */
116     _Pragma("asm")
117         movlw   OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE
118         movwf   PRODL,ACCESS        ; PRODL is used as temp register
119     _Pragma("asmend")
120     ucScratch = PRODL;
121 
122     /*
123      * Place a few bytes of known values on the bottom of the stack.
124      * This is just useful for debugging.
125      */
126 //  *pxTopOfStack-- = 0x11;
127 //  *pxTopOfStack-- = 0x22;
128 //  *pxTopOfStack-- = 0x33;
129 
130     /*
131      * Simulate how the stack would look after a call to vPortYield()
132      * generated by the compiler.
133      */
134 
135     /*
136      * First store the function parameters.  This is where the task expects
137      * to find them when it starts running.
138      */
139     *pxTopOfStack-- = ( StackType_t ) ( (( uint16_t ) pvParameters >> 8) & 0x00ff );
140     *pxTopOfStack-- = ( StackType_t ) (  ( uint16_t ) pvParameters       & 0x00ff );
141 
142     /*
143      * Next are all the registers that form part of the task context.
144      */
145     *pxTopOfStack-- = ( StackType_t ) 0x11; /* STATUS. */
146     *pxTopOfStack-- = ( StackType_t ) 0x22; /* WREG. */
147     *pxTopOfStack-- = ( StackType_t ) 0x33; /* BSR. */
148     *pxTopOfStack-- = ( StackType_t ) 0x44; /* PRODH. */
149     *pxTopOfStack-- = ( StackType_t ) 0x55; /* PRODL. */
150     *pxTopOfStack-- = ( StackType_t ) 0x66; /* FSR0H. */
151     *pxTopOfStack-- = ( StackType_t ) 0x77; /* FSR0L. */
152     *pxTopOfStack-- = ( StackType_t ) 0x88; /* FSR1H. */
153     *pxTopOfStack-- = ( StackType_t ) 0x99; /* FSR1L. */
154     *pxTopOfStack-- = ( StackType_t ) 0xAA; /* TABLAT. */
155 #if _ROMSIZE > 0x8000
156     *pxTopOfStack-- = ( StackType_t ) 0x00; /* TBLPTRU. */
157 #endif
158     *pxTopOfStack-- = ( StackType_t ) 0xCC; /* TBLPTRH. */
159     *pxTopOfStack-- = ( StackType_t ) 0xDD; /* TBLPTRL. */
160 #if _ROMSIZE > 0x8000
161     *pxTopOfStack-- = ( StackType_t ) 0xEE; /* PCLATU. */
162 #endif
163     *pxTopOfStack-- = ( StackType_t ) 0xFF; /* PCLATH. */
164 
165     /*
166      * Next the compiler's scratchspace.
167      */
168     while(ucScratch-- > 0)
169     {
170         *pxTopOfStack-- = ( StackType_t ) 0;
171     }
172 
173     /*
174      * The only function return address so far is the address of the task entry.
175      * The order is TOSU/TOSH/TOSL. For devices > 64kB, TOSU is put on the
176      * stack, too. TOSU is always written as zero here because wizC does not allow
177      * functionpointers to point above 64kB in ROM.
178      */
179 #if _ROMSIZE > 0x8000
180     *pxTopOfStack-- = ( StackType_t ) 0;
181 #endif
182     *pxTopOfStack-- = ( StackType_t ) ( ( ( uint16_t ) pxCode >> 8 ) & 0x00ff );
183     *pxTopOfStack-- = ( StackType_t ) ( (   uint16_t ) pxCode        & 0x00ff );
184 
185     /*
186      * Store the number of return addresses on the hardware stack.
187      * So far only the address of the task entry point.
188      */
189     *pxTopOfStack-- = ( StackType_t ) 1;
190 
191     /*
192      * The code generated by wizC does not maintain separate
193      * stack and frame pointers. Therefore the portENTER_CRITICAL macro cannot
194      * use the stack as per other ports.  Instead a variable is used to keep
195      * track of the critical section nesting.  This variable has to be stored
196      * as part of the task context and is initially set to zero.
197      */
198     *pxTopOfStack-- = ( StackType_t ) portNO_CRITICAL_SECTION_NESTING;
199 
200     return pxTopOfStack;
201 }
202 /*-----------------------------------------------------------*/
203 
usPortCALCULATE_MINIMAL_STACK_SIZE(void)204 uint16_t usPortCALCULATE_MINIMAL_STACK_SIZE( void )
205 {
206     /*
207      * Fetch the size of compiler's scratchspace.
208      */
209     _Pragma("asm")
210         movlw   OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE
211         movlb   usCalcMinStackSize>>8
212         movwf   usCalcMinStackSize,BANKED
213     _Pragma("asmend")
214 
215     /*
216      * Add minimum needed stackspace
217      */
218     usCalcMinStackSize  +=  ( portSTACK_FSR_BYTES )
219         +   ( portSTACK_MINIMAL_CALLRETURN_DEPTH * portSTACK_CALLRETURN_ENTRY_SIZE )
220         +   ( portSTACK_OTHER_BYTES );
221 
222     return(usCalcMinStackSize);
223 }
224 
225 /*-----------------------------------------------------------*/
226 
xPortStartScheduler(void)227 BaseType_t xPortStartScheduler( void )
228 {
229     extern void portSetupTick( void );
230 
231     /*
232      * Setup a timer for the tick ISR for the preemptive scheduler.
233      */
234     portSetupTick();
235 
236     /*
237      * Restore the context of the first task to run.
238      */
239     portRESTORE_CONTEXT();
240 
241     /*
242      * This point should never be reached during execution.
243      */
244     return pdTRUE;
245 }
246 
247 /*-----------------------------------------------------------*/
248 
vPortEndScheduler(void)249 void vPortEndScheduler( void )
250 {
251     /*
252      * It is unlikely that the scheduler for the PIC port will get stopped
253      * once running. When called a reset is done which is probably the
254      * most valid action.
255      */
256     _Pragma(asmline reset);
257 }
258 
259 /*-----------------------------------------------------------*/
260 
261 /*
262  * Manual context switch.  This is similar to the tick context switch,
263  * but does not increment the tick count.  It must be identical to the
264  * tick context switch in how it stores the stack of a task.
265  */
vPortYield(void)266 void vPortYield( void )
267 {
268     /*
269      * Save the context of the current task.
270      */
271     portSAVE_CONTEXT( portINTERRUPTS_UNCHANGED );
272 
273     /*
274      * Switch to the highest priority task that is ready to run.
275      */
276     vTaskSwitchContext();
277 
278     /*
279      * Start executing the task we have just switched to.
280      */
281     portRESTORE_CONTEXT();
282 }
283 /*-----------------------------------------------------------*/
284 
285 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
286 
pvPortMalloc(uint16_t usWantedSize)287     void *pvPortMalloc( uint16_t usWantedSize )
288     {
289     void *pvReturn;
290 
291         vTaskSuspendAll();
292         {
293             pvReturn = malloc( ( malloc_t ) usWantedSize );
294         }
295         xTaskResumeAll();
296 
297         return pvReturn;
298     }
299 
300 #endif /* configSUPPORT_STATIC_ALLOCATION */
301 
302 /*-----------------------------------------------------------*/
303 
304 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
305 
vPortFree(void * pv)306     void vPortFree( void *pv )
307     {
308         if( pv )
309         {
310             vTaskSuspendAll();
311             {
312                 free( pv );
313             }
314             xTaskResumeAll();
315         }
316     }
317 
318 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
319