123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- /*
- * FreeRTOS Kernel V10.4.6
- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * SPDX-License-Identifier: MIT
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /*-----------------------------------------------------------
- * Implementation of functions defined in portable.h for the MicroBlaze port.
- *----------------------------------------------------------*/
- /* Scheduler includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- /* Standard includes. */
- #include <string.h>
- /* Hardware includes. */
- #include <xintc_i.h>
- #include <xil_exception.h>
- #include <microblaze_exceptions_g.h>
- /* Tasks are started with a critical section nesting of 0 - however, prior to
- the scheduler being commenced interrupts should not be enabled, so the critical
- nesting variable is initialised to a non-zero value. */
- #define portINITIAL_NESTING_VALUE ( 0xff )
- /* The bit within the MSR register that enabled/disables interrupts and
- exceptions respectively. */
- #define portMSR_IE ( 0x02U )
- #define portMSR_EE ( 0x100U )
- /* If the floating point unit is included in the MicroBlaze build, then the
- FSR register is saved as part of the task context. portINITIAL_FSR is the value
- given to the FSR register when the initial context is set up for a task being
- created. */
- #define portINITIAL_FSR ( 0U )
- /*-----------------------------------------------------------*/
- /*
- * Initialise the interrupt controller instance.
- */
- static int32_t prvInitialiseInterruptController( void );
- /* Ensure the interrupt controller instance variable is initialised before it is
- * used, and that the initialisation only happens once.
- */
- static int32_t prvEnsureInterruptControllerIsInitialised( void );
- /*-----------------------------------------------------------*/
- /* Counts the nesting depth of calls to portENTER_CRITICAL(). Each task
- maintains its own count, so this variable is saved as part of the task
- context. */
- volatile UBaseType_t uxCriticalNesting = portINITIAL_NESTING_VALUE;
- /* This port uses a separate stack for interrupts. This prevents the stack of
- every task needing to be large enough to hold an entire interrupt stack on top
- of the task stack. */
- uint32_t *pulISRStack;
- /* If an interrupt requests a context switch, then ulTaskSwitchRequested will
- get set to 1. ulTaskSwitchRequested is inspected just before the main interrupt
- handler exits. If, at that time, ulTaskSwitchRequested is set to 1, the kernel
- will call vTaskSwitchContext() to ensure the task that runs immediately after
- the interrupt exists is the highest priority task that is able to run. This is
- an unusual mechanism, but is used for this port because a single interrupt can
- cause the servicing of multiple peripherals - and it is inefficient to call
- vTaskSwitchContext() multiple times as each peripheral is serviced. */
- volatile uint32_t ulTaskSwitchRequested = 0UL;
- /* The instance of the interrupt controller used by this port. This is required
- by the Xilinx library API functions. */
- static XIntc xInterruptControllerInstance;
- /*-----------------------------------------------------------*/
- /*
- * Initialise the stack of a task to look exactly as if a call to
- * portSAVE_CONTEXT had been made.
- *
- * See the portable.h header file.
- */
- StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
- {
- extern void *_SDA2_BASE_, *_SDA_BASE_;
- const uint32_t ulR2 = ( uint32_t ) &_SDA2_BASE_;
- const uint32_t ulR13 = ( uint32_t ) &_SDA_BASE_;
- extern void _start1( void );
- /* Place a few bytes of known values on the bottom of the stack.
- This is essential for the Microblaze port and these lines must
- not be omitted. */
- *pxTopOfStack = ( StackType_t ) 0x00000000;
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x00000000;
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x00000000;
- pxTopOfStack--;
- #if( XPAR_MICROBLAZE_USE_FPU != 0 )
- /* The FSR value placed in the initial task context is just 0. */
- *pxTopOfStack = portINITIAL_FSR;
- pxTopOfStack--;
- #endif
- /* The MSR value placed in the initial task context should have interrupts
- disabled. Each task will enable interrupts automatically when it enters
- the running state for the first time. */
- *pxTopOfStack = mfmsr() & ~portMSR_IE;
- #if( MICROBLAZE_EXCEPTIONS_ENABLED == 1 )
- {
- /* Ensure exceptions are enabled for the task. */
- *pxTopOfStack |= portMSR_EE;
- }
- #endif
- pxTopOfStack--;
- /* First stack an initial value for the critical section nesting. This
- is initialised to zero. */
- *pxTopOfStack = ( StackType_t ) 0x00;
- /* R0 is always zero. */
- /* R1 is the SP. */
- /* Place an initial value for all the general purpose registers. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) ulR2; /* R2 - read only small data area. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x03; /* R3 - return values and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x04; /* R4 - return values and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) pvParameters;/* R5 contains the function call parameters. */
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x06; /* R6 - other parameters and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x07; /* R7 - other parameters and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) NULL; /* R8 - other parameters and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x09; /* R9 - other parameters and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x0a; /* R10 - other parameters and temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x0b; /* R11 - temporaries. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x0c; /* R12 - temporaries. */
- pxTopOfStack--;
- #else
- pxTopOfStack-= 8;
- #endif
- *pxTopOfStack = ( StackType_t ) ulR13; /* R13 - read/write small data area. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) pxCode; /* R14 - return address for interrupt. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) _start1; /* R15 - return address for subroutine. */
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x10; /* R16 - return address for trap (debugger). */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x11; /* R17 - return address for exceptions, if configured. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x12; /* R18 - reserved for assembler and compiler temporaries. */
- pxTopOfStack--;
- #else
- pxTopOfStack -= 4;
- #endif
- *pxTopOfStack = ( StackType_t ) 0x00; /* R19 - must be saved across function calls. Callee-save. Seems to be interpreted as the frame pointer. */
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x14; /* R20 - reserved for storing a pointer to the Global Offset Table (GOT) in Position Independent Code (PIC). Non-volatile in non-PIC code. Must be saved across function calls. Callee-save. Not used by FreeRTOS. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x15; /* R21 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x16; /* R22 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x17; /* R23 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x18; /* R24 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x19; /* R25 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1a; /* R26 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1b; /* R27 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1c; /* R28 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1d; /* R29 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1e; /* R30 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x1f; /* R31 - must be saved across function calls. Callee-save. */
- pxTopOfStack--;
- #else
- pxTopOfStack -= 13;
- #endif
- /* Return a pointer to the top of the stack that has been generated so this
- can be stored in the task control block for the task. */
- return pxTopOfStack;
- }
- /*-----------------------------------------------------------*/
- BaseType_t xPortStartScheduler( void )
- {
- extern void ( vPortStartFirstTask )( void );
- extern uint32_t _stack[];
- /* Setup the hardware to generate the tick. Interrupts are disabled when
- this function is called.
- This port uses an application defined callback function to install the tick
- interrupt handler because the kernel will run on lots of different
- MicroBlaze and FPGA configurations - not all of which will have the same
- timer peripherals defined or available. An example definition of
- vApplicationSetupTimerInterrupt() is provided in the official demo
- application that accompanies this port. */
- vApplicationSetupTimerInterrupt();
- /* Reuse the stack from main() as the stack for the interrupts/exceptions. */
- pulISRStack = ( uint32_t * ) _stack;
- /* Ensure there is enough space for the functions called from the interrupt
- service routines to write back into the stack frame of the caller. */
- pulISRStack -= 2;
- /* Restore the context of the first task that is going to run. From here
- on, the created tasks will be executing. */
- vPortStartFirstTask();
- /* Should not get here as the tasks are now running! */
- return pdFALSE;
- }
- /*-----------------------------------------------------------*/
- void vPortEndScheduler( void )
- {
- /* Not implemented in ports where there is nothing to return to.
- Artificially force an assert. */
- configASSERT( uxCriticalNesting == 1000UL );
- }
- /*-----------------------------------------------------------*/
- /*
- * Manual context switch called by portYIELD or taskYIELD.
- */
- void vPortYield( void )
- {
- extern void VPortYieldASM( void );
- /* Perform the context switch in a critical section to assure it is
- not interrupted by the tick ISR. It is not a problem to do this as
- each task maintains its own interrupt status. */
- portENTER_CRITICAL();
- {
- /* Jump directly to the yield function to ensure there is no
- compiler generated prologue code. */
- asm volatile ( "bralid r14, VPortYieldASM \n\t" \
- "or r0, r0, r0 \n\t" );
- }
- portEXIT_CRITICAL();
- }
- /*-----------------------------------------------------------*/
- void vPortEnableInterrupt( uint8_t ucInterruptID )
- {
- int32_t lReturn;
- /* An API function is provided to enable an interrupt in the interrupt
- controller because the interrupt controller instance variable is private
- to this file. */
- lReturn = prvEnsureInterruptControllerIsInitialised();
- if( lReturn == pdPASS )
- {
- /* Critical section protects read/modify/writer operation inside
- XIntc_Enable(). */
- portENTER_CRITICAL();
- {
- XIntc_Enable( &xInterruptControllerInstance, ucInterruptID );
- }
- portEXIT_CRITICAL();
- }
- configASSERT( lReturn );
- }
- /*-----------------------------------------------------------*/
- void vPortDisableInterrupt( uint8_t ucInterruptID )
- {
- int32_t lReturn;
- /* An API function is provided to disable an interrupt in the interrupt
- controller because the interrupt controller instance variable is private
- to this file. */
- lReturn = prvEnsureInterruptControllerIsInitialised();
- if( lReturn == pdPASS )
- {
- XIntc_Disable( &xInterruptControllerInstance, ucInterruptID );
- }
- configASSERT( lReturn );
- }
- /*-----------------------------------------------------------*/
- BaseType_t xPortInstallInterruptHandler( uint8_t ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef )
- {
- int32_t lReturn;
- /* An API function is provided to install an interrupt handler because the
- interrupt controller instance variable is private to this file. */
- lReturn = prvEnsureInterruptControllerIsInitialised();
- if( lReturn == pdPASS )
- {
- lReturn = XIntc_Connect( &xInterruptControllerInstance, ucInterruptID, pxHandler, pvCallBackRef );
- }
- if( lReturn == XST_SUCCESS )
- {
- lReturn = pdPASS;
- }
- configASSERT( lReturn == pdPASS );
- return lReturn;
- }
- /*-----------------------------------------------------------*/
- static int32_t prvEnsureInterruptControllerIsInitialised( void )
- {
- static int32_t lInterruptControllerInitialised = pdFALSE;
- int32_t lReturn;
- /* Ensure the interrupt controller instance variable is initialised before
- it is used, and that the initialisation only happens once. */
- if( lInterruptControllerInitialised != pdTRUE )
- {
- lReturn = prvInitialiseInterruptController();
- if( lReturn == pdPASS )
- {
- lInterruptControllerInitialised = pdTRUE;
- }
- }
- else
- {
- lReturn = pdPASS;
- }
- return lReturn;
- }
- /*-----------------------------------------------------------*/
- /*
- * Handler for the timer interrupt. This is the handler that the application
- * defined callback function vApplicationSetupTimerInterrupt() should install.
- */
- void vPortTickISR( void *pvUnused )
- {
- extern void vApplicationClearTimerInterrupt( void );
- /* Ensure the unused parameter does not generate a compiler warning. */
- ( void ) pvUnused;
- /* This port uses an application defined callback function to clear the tick
- interrupt because the kernel will run on lots of different MicroBlaze and
- FPGA configurations - not all of which will have the same timer peripherals
- defined or available. An example definition of
- vApplicationClearTimerInterrupt() is provided in the official demo
- application that accompanies this port. */
- vApplicationClearTimerInterrupt();
- /* Increment the RTOS tick - this might cause a task to unblock. */
- if( xTaskIncrementTick() != pdFALSE )
- {
- /* Force vTaskSwitchContext() to be called as the interrupt exits. */
- ulTaskSwitchRequested = 1;
- }
- }
- /*-----------------------------------------------------------*/
- static int32_t prvInitialiseInterruptController( void )
- {
- int32_t lStatus;
- lStatus = XIntc_Initialize( &xInterruptControllerInstance, configINTERRUPT_CONTROLLER_TO_USE );
- if( lStatus == XST_SUCCESS )
- {
- /* Initialise the exception table. */
- Xil_ExceptionInit();
- /* Service all pending interrupts each time the handler is entered. */
- XIntc_SetIntrSvcOption( xInterruptControllerInstance.BaseAddress, XIN_SVC_ALL_ISRS_OPTION );
- /* Install exception handlers if the MicroBlaze is configured to handle
- exceptions, and the application defined constant
- configINSTALL_EXCEPTION_HANDLERS is set to 1. */
- #if ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 )
- {
- vPortExceptionsInstallHandlers();
- }
- #endif /* MICROBLAZE_EXCEPTIONS_ENABLED */
- /* Start the interrupt controller. Interrupts are enabled when the
- scheduler starts. */
- lStatus = XIntc_Start( &xInterruptControllerInstance, XIN_REAL_MODE );
- if( lStatus == XST_SUCCESS )
- {
- lStatus = pdPASS;
- }
- else
- {
- lStatus = pdFAIL;
- }
- }
- configASSERT( lStatus == pdPASS );
- return lStatus;
- }
- /*-----------------------------------------------------------*/
|