1 /*
2  * FreeRTOS Kernel V11.1.0
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.0.0
31 
32 Changes from V3.0.1
33 */
34 #ifndef PORTMACRO_H
35 #define PORTMACRO_H
36 
37 #if !defined(_SERIES) || _SERIES != 18
38     #error "WizC supports FreeRTOS on the Microchip PIC18-series only"
39 #endif
40 
41 #if !defined(QUICKCALL) || QUICKCALL != 1
42     #error "QuickCall must be enabled (see ProjectOptions/Optimisations)"
43 #endif
44 
45 #include <stddef.h>
46 #include <pic.h>
47 
48 #define portCHAR        char
49 #define portFLOAT       float
50 #define portDOUBLE      portFLOAT
51 #define portLONG        long
52 #define portSHORT       short
53 #define portSTACK_TYPE  uint8_t
54 #define portBASE_TYPE   char
55 
56 typedef portSTACK_TYPE StackType_t;
57 typedef signed char BaseType_t;
58 typedef unsigned char UBaseType_t;
59 
60 
61 #if( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
62     typedef uint16_t TickType_t;
63     #define portMAX_DELAY ( TickType_t )    ( 0xFFFF )
64 #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
65     typedef uint32_t TickType_t;
66     #define portMAX_DELAY ( TickType_t )    ( 0xFFFFFFFFUL )
67 #else
68     #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
69 #endif
70 
71 #define portBYTE_ALIGNMENT          1
72 
73 /*-----------------------------------------------------------*/
74 
75 /*
76  * Constant used for context switch macro when we require the interrupt
77  * enable state to be forced when the interrupted task is switched back in.
78  */
79 #define portINTERRUPTS_FORCED               (0x01)
80 
81 /*
82  * Constant used for context switch macro when we require the interrupt
83  * enable state to be unchanged when the interrupted task is switched back in.
84  */
85 #define portINTERRUPTS_UNCHANGED            (0x00)
86 
87 /* Initial interrupt enable state for newly created tasks.  This value is
88  * used when a task switches in for the first time.
89  */
90 #define portINTERRUPTS_INITIAL_STATE        (portINTERRUPTS_FORCED)
91 
92 /*
93  * Macros to modify the global interrupt enable bit in INTCON.
94  */
95 #define portDISABLE_INTERRUPTS()    \
96     do                              \
97     {                               \
98         bGIE=0;                     \
99     } while(bGIE)   // MicroChip recommends this check!
100 
101 #define portENABLE_INTERRUPTS()     \
102     do                              \
103     {                               \
104         bGIE=1;                     \
105     } while(0)
106 
107 /*-----------------------------------------------------------*/
108 
109 /*
110  * Critical section macros.
111  */
112 extern uint8_t ucCriticalNesting;
113 
114 #define portNO_CRITICAL_SECTION_NESTING     ( ( uint8_t ) 0 )
115 
116 #define portENTER_CRITICAL()                                        \
117     do                                                              \
118     {                                                               \
119         portDISABLE_INTERRUPTS();                                   \
120                                                                     \
121         /*                                                          \
122          * Now interrupts are disabled ucCriticalNesting            \
123          * can be accessed directly. Increment                      \
124          * ucCriticalNesting to keep a count of how                 \
125          * many times portENTER_CRITICAL() has been called.         \
126          */                                                         \
127         ucCriticalNesting++;                                        \
128     } while(0)
129 
130 #define portEXIT_CRITICAL()                                         \
131     do                                                              \
132     {                                                               \
133         if(ucCriticalNesting > portNO_CRITICAL_SECTION_NESTING)     \
134         {                                                           \
135             /*                                                      \
136              * Decrement the nesting count as we are leaving a      \
137              * critical section.                                    \
138              */                                                     \
139             ucCriticalNesting--;                                    \
140         }                                                           \
141                                                                     \
142         /*                                                          \
143          * If the nesting level has reached zero then               \
144          * interrupts should be re-enabled.                         \
145          */                                                         \
146         if( ucCriticalNesting == portNO_CRITICAL_SECTION_NESTING )  \
147         {                                                           \
148             portENABLE_INTERRUPTS();                                \
149         }                                                           \
150     } while(0)
151 
152 /*-----------------------------------------------------------*/
153 
154 /*
155  * The minimal stacksize is calculated on the first reference of
156  * portMINIMAL_STACK_SIZE. Some input to this calculation is
157  * compiletime determined, other input is port-defined (see port.c)
158  */
159 extern uint16_t usPortCALCULATE_MINIMAL_STACK_SIZE( void );
160 extern uint16_t usCalcMinStackSize;
161 
162 #define portMINIMAL_STACK_SIZE                  \
163     ((usCalcMinStackSize == 0)                  \
164         ? usPortCALCULATE_MINIMAL_STACK_SIZE()  \
165         : usCalcMinStackSize )
166 
167 /*
168  * WizC uses a downgrowing stack
169  */
170 #define portSTACK_GROWTH            ( -1 )
171 
172 /*-----------------------------------------------------------*/
173 
174 /*
175  * Macro's that pushes all the registers that make up the context of a task onto
176  * the stack, then saves the new top of stack into the TCB. TOSU and TBLPTRU
177  * are only saved/restored on devices with more than 64kB (32k Words) ROM.
178  *
179  * The stackpointer is held by WizC in FSR2 and points to the first free byte.
180  * WizC uses a "downgrowing" stack. There is no framepointer.
181  *
182  * We keep track of the interruptstatus using ucCriticalNesting. When this
183  * value equals zero, interrupts have to be enabled upon exit from the
184  * portRESTORE_CONTEXT macro.
185  *
186  * If this is called from an ISR then the interrupt enable bits must have been
187  * set for the ISR to ever get called.  Therefore we want to save
188  * ucCriticalNesting with value zero. This means the interrupts will again be
189  * re-enabled when the interrupted task is switched back in.
190  *
191  * If this is called from a manual context switch (i.e. from a call to yield),
192  * then we want to keep the current value of ucCriticalNesting so it is restored
193  * with its current value. This allows a yield from within a critical section.
194  *
195  * The compiler uses some locations at the bottom of RAM for temporary
196  * storage. The compiler may also have been instructed to optimize
197  * function-parameters and local variables to global storage. The compiler
198  * uses an area called LocOpt for this wizC feature.
199  * The total overheadstorage has to be saved in it's entirety as part of
200  * a task context. These macro's store/restore from data address 0x0000 to
201  * (OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE - 1).
202  * OVERHEADPAGE0, LOCOPTSIZE and MAXLOCOPTSIZE are compiler-generated
203  * assembler definitions.
204  */
205 
206 #define portSAVE_CONTEXT( ucInterruptForced )                       \
207     do                                                              \
208     {                                                               \
209         portDISABLE_INTERRUPTS();                                   \
210                                                                     \
211         _Pragma("asm")                                              \
212             ;                                                       \
213             ; Push the relevant SFR's onto the task's stack         \
214             ;                                                       \
215             movff   STATUS,POSTDEC2                                 \
216             movff   WREG,POSTDEC2                                   \
217             movff   BSR,POSTDEC2                                    \
218             movff   PRODH,POSTDEC2                                  \
219             movff   PRODL,POSTDEC2                                  \
220             movff   FSR0H,POSTDEC2                                  \
221             movff   FSR0L,POSTDEC2                                  \
222             movff   FSR1H,POSTDEC2                                  \
223             movff   FSR1L,POSTDEC2                                  \
224             movff   TABLAT,POSTDEC2                                 \
225             if __ROMSIZE > 0x8000                                   \
226                 movff   TBLPTRU,POSTDEC2                            \
227             endif                                                   \
228             movff   TBLPTRH,POSTDEC2                                \
229             movff   TBLPTRL,POSTDEC2                                \
230             if __ROMSIZE > 0x8000                                   \
231                 movff   PCLATU,POSTDEC2                             \
232             endif                                                   \
233             movff   PCLATH,POSTDEC2                                 \
234             ;                                                       \
235             ; Store the compiler-scratch-area as described above.   \
236             ;                                                       \
237             movlw   OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE          \
238             clrf    FSR0L,ACCESS                                    \
239             clrf    FSR0H,ACCESS                                    \
240         _rtos_S1:                                                   \
241             movff   POSTINC0,POSTDEC2                               \
242             decfsz  WREG,W,ACCESS                                   \
243             SMARTJUMP _rtos_S1                                      \
244             ;                                                       \
245             ; Save the pic call/return-stack belonging to the       \
246             ; current task by copying it to the task's software-    \
247             ; stack. We save the hardware stack pointer (which      \
248             ; is the number of addresses on the stack) in the       \
249             ; W-register first because we need it later and it      \
250             ; is modified in the save-loop by executing pop's.      \
251             ; After the loop the W-register is stored on the        \
252             ; stack, too.                                           \
253             ;                                                       \
254             movf    STKPTR,W,ACCESS                                 \
255             bz      _rtos_s3                                        \
256         _rtos_S2:                                                   \
257             if __ROMSIZE > 0x8000                                   \
258                 movff   TOSU,POSTDEC2                               \
259             endif                                                   \
260             movff   TOSH,POSTDEC2                                   \
261             movff   TOSL,POSTDEC2                                   \
262             pop                                                     \
263             tstfsz  STKPTR,ACCESS                                   \
264             SMARTJUMP _rtos_S2                                      \
265         _rtos_s3:                                                   \
266             movwf   POSTDEC2,ACCESS                                 \
267             ;                                                       \
268             ; Next the value for ucCriticalNesting used by the      \
269             ; task is stored on the stack. When                     \
270             ; (ucInterruptForced == portINTERRUPTS_FORCED), we save \
271             ; it as 0 (portNO_CRITICAL_SECTION_NESTING).            \
272             ;                                                       \
273             if ucInterruptForced == portINTERRUPTS_FORCED           \
274                 clrf POSTDEC2,ACCESS                                \
275             else                                                    \
276                 movff   ucCriticalNesting,POSTDEC2                  \
277             endif                                                   \
278             ;                                                       \
279             ; Save the new top of the software stack in the TCB.    \
280             ;                                                       \
281             movff   pxCurrentTCB,FSR0L                              \
282             movff   pxCurrentTCB+1,FSR0H                            \
283             movff   FSR2L,POSTINC0                                  \
284             movff   FSR2H,POSTINC0                                  \
285         _Pragma("asmend")                                           \
286     } while(0)
287 
288 /************************************************************/
289 
290 /*
291  * This is the reverse of portSAVE_CONTEXT.
292  */
293 #define portRESTORE_CONTEXT()                                       \
294     do                                                              \
295     {                                                               \
296         _Pragma("asm")                                              \
297             ;                                                       \
298             ; Set FSR0 to point to pxCurrentTCB->pxTopOfStack.      \
299             ;                                                       \
300             movff   pxCurrentTCB,FSR0L                              \
301             movff   pxCurrentTCB+1,FSR0H                            \
302             ;                                                       \
303             ; De-reference FSR0 to set the address it holds into    \
304             ; FSR2 (i.e. *( pxCurrentTCB->pxTopOfStack ) ). FSR2    \
305             ; is used by wizC as stackpointer.                      \
306             ;                                                       \
307             movff   POSTINC0,FSR2L                                  \
308             movff   POSTINC0,FSR2H                                  \
309             ;                                                       \
310             ; Next, the value for ucCriticalNesting used by the     \
311             ; task is retrieved from the stack.                     \
312             ;                                                       \
313             movff   PREINC2,ucCriticalNesting                       \
314             ;                                                       \
315             ; Rebuild the pic call/return-stack. The number of      \
316             ; return addresses is the next item on the task stack.  \
317             ; Save this number in PRODL. Then fetch the addresses   \
318             ; and store them on the hardwarestack.                  \
319             ; The datasheets say we can't use movff here...         \
320             ;                                                       \
321             movff   PREINC2,PRODL   // Use PRODL as tempregister    \
322             clrf    STKPTR,ACCESS                                   \
323         _rtos_R1:                                                   \
324             push                                                    \
325             movf    PREINC2,W,ACCESS                                \
326             movwf   TOSL,ACCESS                                     \
327             movf    PREINC2,W,ACCESS                                \
328             movwf   TOSH,ACCESS                                     \
329             if __ROMSIZE > 0x8000                                   \
330                 movf    PREINC2,W,ACCESS                            \
331                 movwf   TOSU,ACCESS                                 \
332             else                                                    \
333                 clrf    TOSU,ACCESS                                 \
334             endif                                                   \
335             decfsz  PRODL,F,ACCESS                                  \
336             SMARTJUMP _rtos_R1                                      \
337             ;                                                       \
338             ; Restore the compiler's working storage area to page 0 \
339             ;                                                       \
340             movlw   OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE          \
341             movwf   FSR0L,ACCESS                                    \
342             clrf    FSR0H,ACCESS                                    \
343         _rtos_R2:                                                   \
344             decf    FSR0L,F,ACCESS                                  \
345             movff   PREINC2,INDF0                                   \
346             tstfsz  FSR0L,ACCESS                                    \
347             SMARTJUMP _rtos_R2                                      \
348             ;                                                       \
349             ; Restore the sfr's forming the tasks context.          \
350             ; We cannot yet restore bsr, w and status because       \
351             ; we need these registers for a final test.             \
352             ;                                                       \
353             movff   PREINC2,PCLATH                                  \
354             if __ROMSIZE > 0x8000                                   \
355                 movff   PREINC2,PCLATU                              \
356             else                                                    \
357                 clrf    PCLATU,ACCESS                               \
358             endif                                                   \
359             movff   PREINC2,TBLPTRL                                 \
360             movff   PREINC2,TBLPTRH                                 \
361             if __ROMSIZE > 0x8000                                   \
362                 movff   PREINC2,TBLPTRU                             \
363             else                                                    \
364                 clrf    TBLPTRU,ACCESS                              \
365             endif                                                   \
366             movff   PREINC2,TABLAT                                  \
367             movff   PREINC2,FSR1L                                   \
368             movff   PREINC2,FSR1H                                   \
369             movff   PREINC2,FSR0L                                   \
370             movff   PREINC2,FSR0H                                   \
371             movff   PREINC2,PRODL                                   \
372             movff   PREINC2,PRODH                                   \
373             ;                                                       \
374             ; The return from portRESTORE_CONTEXT() depends on      \
375             ; the value of ucCriticalNesting. When it is zero,      \
376             ; interrupts need to be enabled. This is done via a     \
377             ; retfie instruction because we need the                \
378             ; interrupt-enabling and the return to the restored     \
379             ; task to be uninterruptible.                           \
380             ; Because bsr, status and W are affected by the test    \
381             ; they are restored after the test.                     \
382             ;                                                       \
383             movlb   ucCriticalNesting>>8                            \
384             tstfsz  ucCriticalNesting,BANKED                        \
385             SMARTJUMP _rtos_R4                                      \
386         _rtos_R3:                                                   \
387             movff   PREINC2,BSR                                     \
388             movff   PREINC2,WREG                                    \
389             movff   PREINC2,STATUS                                  \
390             retfie  0       ; Return enabling interrupts            \
391         _rtos_R4:                                                   \
392             movff   PREINC2,BSR                                     \
393             movff   PREINC2,WREG                                    \
394             movff   PREINC2,STATUS                                  \
395             return  0       ; Return without affecting interrupts   \
396         _Pragma("asmend")                                           \
397     } while(0)
398 
399 /*-----------------------------------------------------------*/
400 
401 #define portTICK_PERIOD_MS  ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
402 
403 /*-----------------------------------------------------------*/
404 
405 extern void vPortYield( void );
406 #define portYIELD()             vPortYield()
407 
408 #define portNOP()   _Pragma("asm")                                  \
409                         nop                                         \
410                     _Pragma("asmend")
411 
412 /*-----------------------------------------------------------*/
413 
414 #define portTASK_FUNCTION( xFunction, pvParameters )        \
415     void pointed xFunction( void *pvParameters )        \
416     _Pragma(asmfunc xFunction)
417 
418 #define portTASK_FUNCTION_PROTO     portTASK_FUNCTION
419 /*-----------------------------------------------------------*/
420 
421 
422 #define volatile
423 #define register
424 
425 #endif /* PORTMACRO_H */
426