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