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 AND BSD-3-Clause 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 /*This file has been prepared for Doxygen automatic documentation generation.*/ 30 31 /*! \file ********************************************************************* 32 * 33 * \brief FreeRTOS port source for AVR32 UC3. 34 * 35 * - Compiler: GNU GCC for AVR32 36 * - Supported devices: All AVR32 devices can be used. 37 * - AppNote: 38 * 39 * \author Atmel Corporation (Now Microchip): 40 * https://www.microchip.com \n 41 * Support and FAQ: https://www.microchip.com/support/ 42 * 43 *****************************************************************************/ 44 45 /* 46 * Copyright (c) 2007, Atmel Corporation All rights reserved. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions are met: 50 * 51 * 1. Redistributions of source code must retain the above copyright notice, 52 * this list of conditions and the following disclaimer. 53 * 54 * 2. Redistributions in binary form must reproduce the above copyright notice, 55 * this list of conditions and the following disclaimer in the documentation 56 * and/or other materials provided with the distribution. 57 * 58 * 3. The name of ATMEL may not be used to endorse or promote products derived 59 * from this software without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED 62 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 63 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 64 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 65 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 66 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 67 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 68 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 69 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 70 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 */ 72 73 #ifndef PORTMACRO_H 74 #define PORTMACRO_H 75 76 /*----------------------------------------------------------- 77 * Port specific definitions. 78 * 79 * The settings in this file configure FreeRTOS correctly for the 80 * given hardware and compiler. 81 * 82 * These settings should not be altered. 83 *----------------------------------------------------------- 84 */ 85 #include <avr32/io.h> 86 #include "intc.h" 87 #include "compiler.h" 88 89 /* *INDENT-OFF* */ 90 #ifdef __cplusplus 91 extern "C" { 92 #endif 93 /* *INDENT-ON* */ 94 95 96 /* Type definitions. */ 97 #define portCHAR char 98 #define portFLOAT float 99 #define portDOUBLE double 100 #define portLONG long 101 #define portSHORT short 102 #define portSTACK_TYPE uint32_t 103 #define portBASE_TYPE long 104 105 typedef portSTACK_TYPE StackType_t; 106 typedef long BaseType_t; 107 typedef unsigned long UBaseType_t; 108 109 #define TASK_DELAY_MS( x ) ( ( x ) / portTICK_PERIOD_MS ) 110 #define TASK_DELAY_S( x ) ( ( x ) * 1000 / portTICK_PERIOD_MS ) 111 #define TASK_DELAY_MIN( x ) ( ( x ) * 60 * 1000 / portTICK_PERIOD_MS ) 112 113 #define configTICK_TC_IRQ ATPASTE2( AVR32_TC_IRQ, configTICK_TC_CHANNEL ) 114 115 #if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) 116 typedef uint16_t TickType_t; 117 #define portMAX_DELAY ( TickType_t ) 0xffff 118 #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS ) 119 typedef uint32_t TickType_t; 120 #define portMAX_DELAY ( TickType_t ) ( 0xFFFFFFFFUL ) 121 #else 122 #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width. 123 #endif 124 /*-----------------------------------------------------------*/ 125 126 /* Architecture specifics. */ 127 #define portSTACK_GROWTH ( -1 ) 128 #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) 129 #define portBYTE_ALIGNMENT 4 130 #define portNOP() { __asm__ __volatile__ ( "nop" ); } 131 /*-----------------------------------------------------------*/ 132 133 134 /*-----------------------------------------------------------*/ 135 136 /* INTC-specific. */ 137 #define DISABLE_ALL_EXCEPTIONS() Disable_global_exception() 138 #define ENABLE_ALL_EXCEPTIONS() Enable_global_exception() 139 140 #define DISABLE_ALL_INTERRUPTS() Disable_global_interrupt() 141 #define ENABLE_ALL_INTERRUPTS() Enable_global_interrupt() 142 143 #define DISABLE_INT_LEVEL( int_lev ) Disable_interrupt_level( int_lev ) 144 #define ENABLE_INT_LEVEL( int_lev ) Enable_interrupt_level( int_lev ) 145 146 147 /* 148 * Debug trace. 149 * Activated if and only if configDBG is nonzero. 150 * Prints a formatted string to stdout. 151 * The current source file name and line number are output with a colon before 152 * the formatted string. 153 * A carriage return and a linefeed are appended to the output. 154 * stdout is redirected to the USART configured by configDBG_USART. 155 * The parameters are the same as for the standard printf function. 156 * There is no return value. 157 * SHALL NOT BE CALLED FROM WITHIN AN INTERRUPT as fputs and printf use malloc, 158 * which is interrupt-unsafe with the current __malloc_lock and __malloc_unlock. 159 */ 160 #if configDBG 161 #define portDBG_TRACE( ... ) \ 162 { \ 163 fputs( __FILE__ ":" ASTRINGZ( __LINE__ ) ": ", stdout ); \ 164 printf( __VA_ARGS__ ); \ 165 fputs( "\r\n", stdout ); \ 166 } 167 #else 168 #define portDBG_TRACE( ... ) 169 #endif 170 171 172 /* Critical section management. */ 173 #define portDISABLE_INTERRUPTS() DISABLE_ALL_INTERRUPTS() 174 #define portENABLE_INTERRUPTS() ENABLE_ALL_INTERRUPTS() 175 176 177 extern void vPortEnterCritical( void ); 178 extern void vPortExitCritical( void ); 179 180 #define portENTER_CRITICAL() vPortEnterCritical(); 181 #define portEXIT_CRITICAL() vPortExitCritical(); 182 183 184 /* Added as there is no such function in FreeRTOS. */ 185 extern void * pvPortRealloc( void * pv, 186 size_t xSize ); 187 /*-----------------------------------------------------------*/ 188 189 190 /*=============================================================================================*/ 191 192 /* 193 * Restore Context for cases other than INTi. 194 */ 195 #define portRESTORE_CONTEXT() \ 196 { \ 197 extern volatile uint32_t ulCriticalNesting; \ 198 extern volatile void * volatile pxCurrentTCB; \ 199 \ 200 __asm__ __volatile__ ( \ 201 /* Set SP to point to new stack */ \ 202 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 203 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 204 "ld.w r0, r8[0] \n\t" \ 205 "ld.w sp, r0[0] \n\t" \ 206 \ 207 /* Restore ulCriticalNesting variable */ \ 208 "ld.w r0, sp++ \n\t" \ 209 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 210 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 211 "st.w r8[0], r0 \n\t" \ 212 \ 213 /* Restore R0..R7 */ \ 214 "ldm sp++, r0-r7 \n\t" \ 215 /* R0-R7 should not be used below this line */ \ 216 /* Skip PC and SR (will do it at the end) */ \ 217 "sub sp, -2*4 \n\t" \ 218 /* Restore R8..R12 and LR */ \ 219 "ldm sp++, r8-r12, lr \n\t" \ 220 /* Restore SR */ \ 221 "ld.w r0, sp[-8*4]\n\t" /* R0 is modified, is restored later. */ \ 222 "mtsr %[SR], r0 \n\t" \ 223 /* Restore r0 */ \ 224 "ld.w r0, sp[-9*4] \n\t" \ 225 /* Restore PC */ \ 226 "ld.w pc, sp[-7*4]" /* Get PC from stack - PC is the 7th register saved */ \ 227 : \ 228 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ), \ 229 [ pxCurrentTCB ] "i" ( &pxCurrentTCB ), \ 230 [ SR ] "i" ( AVR32_SR ) \ 231 ); \ 232 } 233 234 235 /* 236 * portSAVE_CONTEXT_INT() and portRESTORE_CONTEXT_INT(): for INT0..3 exceptions. 237 * portSAVE_CONTEXT_SCALL() and portRESTORE_CONTEXT_SCALL(): for the scall exception. 238 * 239 * Had to make different versions because registers saved on the system stack 240 * are not the same between INT0..3 exceptions and the scall exception. 241 */ 242 243 /* Task context stack layout: */ 244 /* R8 (*) */ 245 /* R9 (*) */ 246 /* R10 (*) */ 247 /* R11 (*) */ 248 /* R12 (*) */ 249 /* R14/LR (*) */ 250 /* R15/PC (*) */ 251 /* SR (*) */ 252 /* R0 */ 253 /* R1 */ 254 /* R2 */ 255 /* R3 */ 256 /* R4 */ 257 /* R5 */ 258 /* R6 */ 259 /* R7 */ 260 /* ulCriticalNesting */ 261 /* (*) automatically done for INT0..INT3, but not for SCALL */ 262 263 /* 264 * The ISR used for the scheduler tick depends on whether the cooperative or 265 * the preemptive scheduler is being used. 266 */ 267 #if configUSE_PREEMPTION == 0 268 269 /* 270 * portSAVE_CONTEXT_OS_INT() for OS Tick exception. 271 */ 272 #define portSAVE_CONTEXT_OS_INT() \ 273 { \ 274 /* Save R0..R7 */ \ 275 __asm__ __volatile__ ( "stm --sp, r0-r7" ); \ 276 \ 277 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 278 /* there is also no context save. */ \ 279 } 280 281 /* 282 * portRESTORE_CONTEXT_OS_INT() for Tick exception. 283 */ 284 #define portRESTORE_CONTEXT_OS_INT() \ 285 { \ 286 __asm__ __volatile__ ( \ 287 /* Restore R0..R7 */ \ 288 "ldm sp++, r0-r7\n\t" \ 289 \ 290 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 291 /* there is also no context restore. */ \ 292 "rete" \ 293 ); \ 294 } 295 296 #else /* if configUSE_PREEMPTION == 0 */ 297 298 /* 299 * portSAVE_CONTEXT_OS_INT() for OS Tick exception. 300 */ 301 #define portSAVE_CONTEXT_OS_INT() \ 302 { \ 303 extern volatile uint32_t ulCriticalNesting; \ 304 extern volatile void * volatile pxCurrentTCB; \ 305 \ 306 /* When we come here */ \ 307 /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */ \ 308 \ 309 __asm__ __volatile__ ( \ 310 /* Save R0..R7 */ \ 311 "stm --sp, r0-r7 \n\t" \ 312 \ 313 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 314 "mov r8, LO(%[ulCriticalNesting])\n\t" \ 315 "orh r8, HI(%[ulCriticalNesting])\n\t" \ 316 "ld.w r0, r8[0] \n\t" \ 317 "st.w --sp, r0 \n\t" \ 318 \ 319 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 320 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 321 /* level and allow other lower interrupt level to occur). */ \ 322 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 323 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 324 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 325 /* will just be restoring the interrupt handler, no way!!! */ \ 326 /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */ \ 327 "ld.w r0, sp[9*4]\n\t" /* Read SR in stack */ \ 328 "bfextu r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */ \ 329 "cp.w r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 330 "brhi LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE] \n\t" \ 331 \ 332 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 333 /* NOTE: we don't enter a critical section here because all interrupt handlers */ \ 334 /* MUST perform a SAVE_CONTEXT/RESTORE_CONTEXT in the same way as */ \ 335 /* portSAVE_CONTEXT_OS_INT/port_RESTORE_CONTEXT_OS_INT if they call OS functions. */ \ 336 /* => all interrupt handlers must use portENTER_SWITCHING_ISR/portEXIT_SWITCHING_ISR. */ \ 337 "mov r8, LO(%[pxCurrentTCB])\n\t" \ 338 "orh r8, HI(%[pxCurrentTCB])\n\t" \ 339 "ld.w r0, r8[0]\n\t" \ 340 "st.w r0[0], sp\n" \ 341 \ 342 "LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE]:" \ 343 : \ 344 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ), \ 345 [ pxCurrentTCB ] "i" ( &pxCurrentTCB ), \ 346 [ LINE ] "i" ( __LINE__ ) \ 347 ); \ 348 } 349 350 /* 351 * portRESTORE_CONTEXT_OS_INT() for Tick exception. 352 */ 353 #define portRESTORE_CONTEXT_OS_INT() \ 354 { \ 355 extern volatile uint32_t ulCriticalNesting; \ 356 extern volatile void * volatile pxCurrentTCB; \ 357 \ 358 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 359 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 360 /* level and allow other lower interrupt level to occur). */ \ 361 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 362 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 363 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 364 /* will just be restoring the interrupt handler, no way!!! */ \ 365 __asm__ __volatile__ ( \ 366 "ld.w r0, sp[9*4]\n\t" /* Read SR in stack */ \ 367 "bfextu r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */ \ 368 "cp.w r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 369 "brhi LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]" \ 370 : \ 371 :[ LINE ] "i" ( __LINE__ ) \ 372 ); \ 373 \ 374 /* Else */ \ 375 /* because it is here safe, always call vTaskSwitchContext() since an OS tick occurred. */ \ 376 /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */ \ 377 portENTER_CRITICAL(); \ 378 vTaskSwitchContext(); \ 379 portEXIT_CRITICAL(); \ 380 \ 381 /* Restore all registers */ \ 382 \ 383 __asm__ __volatile__ ( \ 384 /* Set SP to point to new stack */ \ 385 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 386 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 387 "ld.w r0, r8[0] \n\t" \ 388 "ld.w sp, r0[0] \n" \ 389 \ 390 "LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]: \n\t" \ 391 \ 392 /* Restore ulCriticalNesting variable */ \ 393 "ld.w r0, sp++ \n\t" \ 394 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 395 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 396 "st.w r8[0], r0 \n\t" \ 397 \ 398 /* Restore R0..R7 */ \ 399 "ldm sp++, r0-r7 \n\t" \ 400 \ 401 /* Now, the stack should be R8..R12, LR, PC and SR */ \ 402 "rete" \ 403 : \ 404 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ), \ 405 [ pxCurrentTCB ] "i" ( &pxCurrentTCB ), \ 406 [ LINE ] "i" ( __LINE__ ) \ 407 ); \ 408 } 409 410 #endif /* if configUSE_PREEMPTION == 0 */ 411 412 413 /* 414 * portSAVE_CONTEXT_SCALL() for SupervisorCALL exception. 415 * 416 * NOTE: taskYIELD()(== SCALL) MUST NOT be called in a mode > supervisor mode. 417 * 418 */ 419 #define portSAVE_CONTEXT_SCALL() \ 420 { \ 421 extern volatile uint32_t ulCriticalNesting; \ 422 extern volatile void * volatile pxCurrentTCB; \ 423 \ 424 /* Warning: the stack layout after SCALL doesn't match the one after an interrupt. */ \ 425 /* If SR[M2:M0] == 001 */ \ 426 /* PC and SR are on the stack. */ \ 427 /* Else (other modes) */ \ 428 /* Nothing on the stack. */ \ 429 \ 430 /* WARNING NOTE: the else case cannot happen as it is strictly forbidden to call */ \ 431 /* vTaskDelay() and vTaskDelayUntil() OS functions (that result in a taskYield()) */ \ 432 /* in an interrupt|exception handler. */ \ 433 \ 434 __asm__ __volatile__ ( \ 435 /* in order to save R0-R7 */ \ 436 "sub sp, 6*4 \n\t" \ 437 /* Save R0..R7 */ \ 438 "stm --sp, r0-r7 \n\t" \ 439 \ 440 /* in order to save R8-R12 and LR */ \ 441 /* do not use SP if interrupts occurs, SP must be left at bottom of stack */ \ 442 "sub r7, sp,-16*4 \n\t" \ 443 /* Copy PC and SR in other places in the stack. */ \ 444 "ld.w r0, r7[-2*4] \n\t" /* Read SR */ \ 445 "st.w r7[-8*4], r0 \n\t" /* Copy SR */ \ 446 "ld.w r0, r7[-1*4] \n\t" /* Read PC */ \ 447 "st.w r7[-7*4], r0 \n\t" /* Copy PC */ \ 448 \ 449 /* Save R8..R12 and LR on the stack. */ \ 450 "stm --r7, r8-r12, lr \n\t" \ 451 \ 452 /* Arriving here we have the following stack organizations: */ \ 453 /* R8..R12, LR, PC, SR, R0..R7. */ \ 454 \ 455 /* Now we can finalize the save. */ \ 456 \ 457 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 458 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 459 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 460 "ld.w r0, r8[0] \n\t" \ 461 "st.w --sp, r0" \ 462 : \ 463 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ) \ 464 ); \ 465 \ 466 /* Disable the its which may cause a context switch (i.e. cause a change of */ \ 467 /* pxCurrentTCB). */ \ 468 /* Basically, all accesses to the pxCurrentTCB structure should be put in a */ \ 469 /* critical section because it is a global structure. */ \ 470 portENTER_CRITICAL(); \ 471 \ 472 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 473 __asm__ __volatile__ ( \ 474 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 475 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 476 "ld.w r0, r8[0] \n\t" \ 477 "st.w r0[0], sp" \ 478 : \ 479 :[ pxCurrentTCB ] "i" ( &pxCurrentTCB ) \ 480 ); \ 481 } 482 483 /* 484 * portRESTORE_CONTEXT() for SupervisorCALL exception. 485 */ 486 #define portRESTORE_CONTEXT_SCALL() \ 487 { \ 488 extern volatile uint32_t ulCriticalNesting; \ 489 extern volatile void * volatile pxCurrentTCB; \ 490 \ 491 /* Restore all registers */ \ 492 \ 493 /* Set SP to point to new stack */ \ 494 __asm__ __volatile__ ( \ 495 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 496 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 497 "ld.w r0, r8[0] \n\t" \ 498 "ld.w sp, r0[0]" \ 499 : \ 500 :[ pxCurrentTCB ] "i" ( &pxCurrentTCB ) \ 501 ); \ 502 \ 503 /* Leave pxCurrentTCB variable access critical section */ \ 504 portEXIT_CRITICAL(); \ 505 \ 506 __asm__ __volatile__ ( \ 507 /* Restore ulCriticalNesting variable */ \ 508 "ld.w r0, sp++ \n\t" \ 509 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 510 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 511 "st.w r8[0], r0 \n\t" \ 512 \ 513 /* skip PC and SR */ \ 514 /* do not use SP if interrupts occurs, SP must be left at bottom of stack */ \ 515 "sub r7, sp, -10*4 \n\t" \ 516 /* Restore r8-r12 and LR */ \ 517 "ldm r7++, r8-r12, lr \n\t" \ 518 \ 519 /* RETS will take care of the extra PC and SR restore. */ \ 520 /* So, we have to prepare the stack for this. */ \ 521 "ld.w r0, r7[-8*4] \n\t" /* Read SR */ \ 522 "st.w r7[-2*4], r0 \n\t" /* Copy SR */ \ 523 "ld.w r0, r7[-7*4] \n\t" /* Read PC */ \ 524 "st.w r7[-1*4], r0 \n\t" /* Copy PC */ \ 525 \ 526 /* Restore R0..R7 */ \ 527 "ldm sp++, r0-r7 \n\t" \ 528 \ 529 "sub sp, -6*4 \n\t" \ 530 \ 531 "rets" \ 532 : \ 533 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ) \ 534 ); \ 535 } 536 537 538 /* 539 * The ISR used depends on whether the cooperative or 540 * the preemptive scheduler is being used. 541 */ 542 #if configUSE_PREEMPTION == 0 543 544 /* 545 * ISR entry and exit macros. These are only required if a task switch 546 * is required from the ISR. 547 */ 548 #define portENTER_SWITCHING_ISR() \ 549 { \ 550 /* Save R0..R7 */ \ 551 __asm__ __volatile__ ( "stm --sp, r0-r7" ); \ 552 \ 553 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 554 /* there is also no context save. */ \ 555 } 556 557 /* 558 * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1 559 */ 560 #define portEXIT_SWITCHING_ISR() \ 561 { \ 562 __asm__ __volatile__ ( \ 563 /* Restore R0..R7 */ \ 564 "ldm sp++, r0-r7 \n\t" \ 565 \ 566 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 567 /* there is also no context restore. */ \ 568 "rete" \ 569 ); \ 570 } 571 572 #else /* if configUSE_PREEMPTION == 0 */ 573 574 /* 575 * ISR entry and exit macros. These are only required if a task switch 576 * is required from the ISR. 577 */ 578 #define portENTER_SWITCHING_ISR() \ 579 { \ 580 extern volatile uint32_t ulCriticalNesting; \ 581 extern volatile void * volatile pxCurrentTCB; \ 582 \ 583 /* When we come here */ \ 584 /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */ \ 585 \ 586 __asm__ __volatile__ ( \ 587 /* Save R0..R7 */ \ 588 "stm --sp, r0-r7 \n\t" \ 589 \ 590 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 591 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 592 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 593 "ld.w r0, r8[0] \n\t" \ 594 "st.w --sp, r0 \n\t" \ 595 \ 596 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 597 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 598 /* level and allow other lower interrupt level to occur). */ \ 599 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 600 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 601 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 602 /* will just be restoring the interrupt handler, no way!!! */ \ 603 /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */ \ 604 "ld.w r0, sp[9*4] \n\t" /* Read SR in stack */ \ 605 "bfextu r0, r0, 22, 3 \n\t" /* Extract the mode bits to R0. */ \ 606 "cp.w r0, 1 \n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 607 "brhi LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE] \n\t" \ 608 \ 609 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 610 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 611 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 612 "ld.w r0, r8[0] \n\t" \ 613 "st.w r0[0], sp \n" \ 614 \ 615 "LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE]:" \ 616 : \ 617 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ), \ 618 [ pxCurrentTCB ] "i" ( &pxCurrentTCB ), \ 619 [ LINE ] "i" ( __LINE__ ) \ 620 ); \ 621 } 622 623 /* 624 * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1 625 */ 626 #define portEXIT_SWITCHING_ISR() \ 627 { \ 628 extern volatile uint32_t ulCriticalNesting; \ 629 extern volatile void * volatile pxCurrentTCB; \ 630 \ 631 __asm__ __volatile__ ( \ 632 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 633 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 634 /* level and allow other lower interrupt level to occur). */ \ 635 /* In this case it's of no use to switch context and restore a new SP because we purposely */ \ 636 /* did not previously save SP in its TCB. */ \ 637 "ld.w r0, sp[9*4] \n\t" /* Read SR in stack */ \ 638 "bfextu r0, r0, 22, 3 \n\t" /* Extract the mode bits to R0. */ \ 639 "cp.w r0, 1 \n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 640 "brhi LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE] \n\t" \ 641 \ 642 /* If a switch is required then we just need to call */ \ 643 /* vTaskSwitchContext() as the context has already been */ \ 644 /* saved. */ \ 645 "cp.w r12, 1 \n\t" /* Check if Switch context is required. */ \ 646 "brne LABEL_ISR_RESTORE_CONTEXT_%[LINE]" \ 647 : \ 648 :[ LINE ] "i" ( __LINE__ ) \ 649 ); \ 650 \ 651 /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */ \ 652 portENTER_CRITICAL(); \ 653 vTaskSwitchContext(); \ 654 portEXIT_CRITICAL(); \ 655 \ 656 __asm__ __volatile__ ( \ 657 "LABEL_ISR_RESTORE_CONTEXT_%[LINE]: \n\t" \ 658 /* Restore the context of which ever task is now the highest */ \ 659 /* priority that is ready to run. */ \ 660 \ 661 /* Restore all registers */ \ 662 \ 663 /* Set SP to point to new stack */ \ 664 "mov r8, LO(%[pxCurrentTCB]) \n\t" \ 665 "orh r8, HI(%[pxCurrentTCB]) \n\t" \ 666 "ld.w r0, r8[0] \n\t" \ 667 "ld.w sp, r0[0] \n" \ 668 \ 669 "LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE]: \n\t" \ 670 \ 671 /* Restore ulCriticalNesting variable */ \ 672 "ld.w r0, sp++ \n\t" \ 673 "mov r8, LO(%[ulCriticalNesting]) \n\t" \ 674 "orh r8, HI(%[ulCriticalNesting]) \n\t" \ 675 "st.w r8[0], r0 \n\t" \ 676 \ 677 /* Restore R0..R7 */ \ 678 "ldm sp++, r0-r7 \n\t" \ 679 \ 680 /* Now, the stack should be R8..R12, LR, PC and SR */ \ 681 "rete" \ 682 : \ 683 :[ ulCriticalNesting ] "i" ( &ulCriticalNesting ), \ 684 [ pxCurrentTCB ] "i" ( &pxCurrentTCB ), \ 685 [ LINE ] "i" ( __LINE__ ) \ 686 ); \ 687 } 688 689 #endif /* if configUSE_PREEMPTION == 0 */ 690 691 692 #define portYIELD() { __asm__ __volatile__ ( "scall" ); } 693 694 /* Task function macros as described on the FreeRTOS.org WEB site. */ 695 #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) 696 #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) 697 698 /* *INDENT-OFF* */ 699 #ifdef __cplusplus 700 } 701 #endif 702 /* *INDENT-ON* */ 703 704 #endif /* PORTMACRO_H */ 705