mirror of
				https://github.com/FreeRTOS/FreeRTOS-Kernel.git
				synced 2025-11-04 11:09:01 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			546 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			546 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
 | 
						|
 * 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>
 | 
						|
#include <microblaze_instructions.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 )
 | 
						|
/*
 | 
						|
 * Global counter used for calculation of run time statistics of tasks.
 | 
						|
 * Defined only when the relevant option is turned on
 | 
						|
 */
 | 
						|
#if (configGENERATE_RUN_TIME_STATS==1)
 | 
						|
    volatile uint32_t ulHighFrequencyTimerTicks;
 | 
						|
#endif
 | 
						|
 | 
						|
/*-----------------------------------------------------------*/
 | 
						|
 | 
						|
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
 | 
						|
    StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
 | 
						|
                                         StackType_t * pxEndOfStack,
 | 
						|
                                         TaskFunction_t pxCode,
 | 
						|
                                         void * pvParameters )
 | 
						|
#else
 | 
						|
    StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
 | 
						|
                                         TaskFunction_t pxCode,
 | 
						|
                                         void * pvParameters )
 | 
						|
#endif
 | 
						|
{
 | 
						|
    extern void *_SDA2_BASE_;
 | 
						|
    extern void *_SDA_BASE_;
 | 
						|
    const UINTPTR ulR2 = ( UINTPTR ) &_SDA2_BASE_;
 | 
						|
    const UINTPTR ulR13 = ( UINTPTR ) &_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 ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
 | 
						|
        /* Store the stack limits. */
 | 
						|
        *pxTopOfStack = ( StackType_t ) ( pxTopOfStack + 3 );
 | 
						|
        pxTopOfStack--;
 | 
						|
        *pxTopOfStack = ( StackType_t ) pxEndOfStack;
 | 
						|
        pxTopOfStack--;
 | 
						|
    #endif
 | 
						|
 | 
						|
    #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 /* ifdef portPRE_LOAD_STACK_FOR_DEBUGGING */
 | 
						|
        pxTopOfStack -= 8;
 | 
						|
    #endif /* ifdef portPRE_LOAD_STACK_FOR_DEBUGGING */
 | 
						|
 | 
						|
    *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 /* ifdef portPRE_LOAD_STACK_FOR_DEBUGGING */
 | 
						|
        pxTopOfStack -= 13;
 | 
						|
    #endif /* ifdef portPRE_LOAD_STACK_FOR_DEBUGGING */
 | 
						|
 | 
						|
    /* 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 UINTPTR _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 = ( UINTPTR * ) _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. */
 | 
						|
        #ifdef __arch64__
 | 
						|
            asm volatile (	"brealid r14, VPortYieldASM		\n\t" \
 | 
						|
        		         				"or r0, r0, r0					      \n\t" );
 | 
						|
        #else
 | 
						|
         		asm volatile (	"bralid r14, VPortYieldASM		\n\t" \
 | 
						|
				                 		"or r0, r0, r0					      \n\t" );
 | 
						|
        #endif
 | 
						|
  	}
 | 
						|
	  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 == pdPASS );
 | 
						|
}
 | 
						|
/*-----------------------------------------------------------*/
 | 
						|
 | 
						|
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 == pdPASS );
 | 
						|
}
 | 
						|
/*-----------------------------------------------------------*/
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
/*-----------------------------------------------------------*/
 | 
						|
 | 
						|
void vPortRemoveInterruptHandler( uint8_t ucInterruptID )
 | 
						|
{
 | 
						|
    int32_t lReturn;
 | 
						|
 | 
						|
    /* An API function is provided to remove an interrupt handler because the
 | 
						|
     * interrupt controller instance variable is private to this file. */
 | 
						|
 | 
						|
    lReturn = prvEnsureInterruptControllerIsInitialised();
 | 
						|
 | 
						|
    if( lReturn == pdPASS )
 | 
						|
    {
 | 
						|
        XIntc_Disconnect( &xInterruptControllerInstance, ucInterruptID );
 | 
						|
    }
 | 
						|
 | 
						|
    configASSERT( lReturn == pdPASS );
 | 
						|
}
 | 
						|
/*-----------------------------------------------------------*/
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
    /* The Xilinx implementation of generating run time task stats uses the same timer used for generating
 | 
						|
	   * FreeRTOS ticks. In case user decides to generate run time stats the tick handler is called more
 | 
						|
	   * frequently (10 times faster). The timer    ick handler uses logic to handle the same. It handles
 | 
						|
	   * the FreeRTOS tick once per 10 interrupts.
 | 
						|
	   * For handling generation of run time stats, it increments a pre-defined counter every time the
 | 
						|
	   * interrupt handler executes. */
 | 
						|
#if (configGENERATE_RUN_TIME_STATS == 1)
 | 
						|
    ulHighFrequencyTimerTicks++;
 | 
						|
    if (!(ulHighFrequencyTimerTicks % 10))
 | 
						|
#endif
 | 
						|
    {
 | 
						|
        /* 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;
 | 
						|
}
 | 
						|
 | 
						|
#if( configGENERATE_RUN_TIME_STATS == 1 )
 | 
						|
/*
 | 
						|
 * For Xilinx implementation this is a dummy function that does a redundant operation
 | 
						|
 * of zeroing out the global counter.
 | 
						|
 * It is called by FreeRTOS kernel.
 | 
						|
 */
 | 
						|
void xCONFIGURE_TIMER_FOR_RUN_TIME_STATS (void)
 | 
						|
{
 | 
						|
	ulHighFrequencyTimerTicks = 0;
 | 
						|
}
 | 
						|
/*
 | 
						|
 * For Xilinx implementation this function returns the global counter used for
 | 
						|
 * run time task stats calculation.
 | 
						|
 * It is called by FreeRTOS kernel task handling logic.
 | 
						|
 */
 | 
						|
uint32_t xGET_RUN_TIME_COUNTER_VALUE (void)
 | 
						|
{
 | 
						|
	return ulHighFrequencyTimerTicks;
 | 
						|
}
 | 
						|
#endif
 | 
						|
/*-----------------------------------------------------------*/
 |