text: /*
   * FreeRTOS Kernel V10.4.2
   * Copyright (C) 2020 Synopsys, Inc. or its affiliates.  All Rights Reserved.
   *
   * 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
   *
   * 1 tab == 4 spaces!
   */
  
  /*
   * Implementation of functions defined in portable.h
   */
  
  #include "FreeRTOS.h"
  #include "task.h"
  #include "FreeRTOSConfig.h"
  
  #include "arc/arc_exception.h"
  #include "arc/arc_timer.h"
  #include "board.h"
  
  #include "arc_freertos_exceptions.h"
  
  volatile unsigned int ulCriticalNesting = 999UL;
  volatile unsigned int context_switch_reqflg; /* task context switch request flag in exceptions and interrupts handling */
  
  /**
   * \var exc_nest_count
   * \brief the counter for exc/int processing, =0 no int/exc
   * >1 in int/exc processing
   * @}
   */
  uint32_t exc_nest_count;
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief kernel tick interrupt handler of freertos
   */
  /* ----------------------------------------------------------------------------*/
  static void vKernelTick( void * ptr )
  {
      /* clear timer interrupt */
      arc_timer_int_clear( BOARD_OS_TIMER_ID );
      board_timer_update( configTICK_RATE_HZ );
  
      if( xTaskIncrementTick() )
      {
          portYIELD_FROM_ISR(); /* need to make task switch */
      }
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief  setup freertos kernel tick
   */
  /* ----------------------------------------------------------------------------*/
  static void prvSetupTimerInterrupt( void )
  {
      unsigned int cyc = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
  
      int_disable( BOARD_OS_TIMER_INTNO ); /* disable os timer interrupt */
      arc_timer_stop( BOARD_OS_TIMER_ID );
      arc_timer_start( BOARD_OS_TIMER_ID, TIMER_CTRL_IE | TIMER_CTRL_NH, cyc );
  
      int_handler_install( BOARD_OS_TIMER_INTNO, ( INT_HANDLER_T ) vKernelTick );
      int_pri_set( BOARD_OS_TIMER_INTNO, INT_PRI_MIN );
      int_enable( BOARD_OS_TIMER_INTNO );
  }
  
  /*
   * Setup the stack of a new task so it is ready to be placed under the
   * scheduler control.  The registers have to be placed on the stack in
   * the order that the port expects to find them.
   *
   * For ARC, task context switch is implemented with the help of SWI exception
   * It's not efficient but simple.
   *
   */
  StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
                                       TaskFunction_t pxCode,
                                       void * pvParameters )
  {
      /* To ensure asserts in tasks.c don't fail, although in this case the assert
       * is not really required. */
      pxTopOfStack--;
  
      /* Setup the initial stack of the task.  The stack is set exactly as
       * expected by the portRESTORE_CONTEXT() macro. */
  
      /* When the task starts is will expect to find the function parameter in
       * R0. */
      *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
  
      pxTopOfStack--;
      *pxTopOfStack = ( StackType_t ) pxCode; /* function body */
  
      /* PC */
      pxTopOfStack--;
      *pxTopOfStack = ( StackType_t ) start_r; /* dispatch return address */
  
      pxTopOfStack--;
      *pxTopOfStack = ( StackType_t ) portNO_CRITICAL_NESTING;
      return pxTopOfStack;
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief  start the freertos scheduler, go to the first task
   *
   * @returns
   */
  /* ----------------------------------------------------------------------------*/
  BaseType_t xPortStartScheduler( void )
  {
      /* Start the timer that generates the tick ISR. */
      prvSetupTimerInterrupt();
      start_dispatch();
  
      /* Should not get here! */
      return 0;
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief
   */
  /* ----------------------------------------------------------------------------*/
  void vPortEndScheduler( void )
  {
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief  generate a task switch request in ISR
   */
  /* ----------------------------------------------------------------------------*/
  void vPortYieldFromIsr( void )
  {
      unsigned int status32;
  
      status32 = cpu_lock_save();
      context_switch_reqflg = true;
      cpu_unlock_restore( status32 );
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief
   */
  /* ----------------------------------------------------------------------------*/
  void vPortYield( void )
  {
      unsigned int status32;
  
      status32 = cpu_lock_save();
      dispatch();
      cpu_unlock_restore( status32 );
  }
  
  /* --------------------------------------------------------------------------*/
  
  /**
   * @brief
   */
  /* ----------------------------------------------------------------------------*/
  void vPortEndTask( void )
  {
      #if ( INCLUDE_vTaskDelete == 1 )
          vTaskDelete( NULL ); /* Delete task itself */
      #endif
  
      while( 1 ) /* Yield to other task */
      {
          vPortYield();
      }
  }
  
  #if ARC_FEATURE_STACK_CHECK
  
  /*
   * !!! Note !!!
   * This a trick!!!
   * It's a copy from task.c. We need to konw the definition of TCB for the purpose of hardware
   * stack check. Pls don't forget to update it when FreeRTOS is updated.
   */
      typedef struct tskTaskControlBlock       /* The old naming convention is used to prevent breaking kernel aware debuggers. */
      {
          volatile StackType_t * pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
  
          #if ( portUSING_MPU_WRAPPERS == 1 )
              xMPU_SETTINGS xMPUSettings;     /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
          #endif
  
          ListItem_t xStateListItem;                  /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
          ListItem_t xEventListItem;                  /*< Used to reference a task from an event list. */
          UBaseType_t uxPriority;                     /*< The priority of the task.  0 is the lowest priority. */
          StackType_t * pxStack;                      /*< Points to the start of the stack. */
          char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
  
          #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
              StackType_t * pxEndOfStack;     /*< Points to the highest valid address for the stack. */
          #endif
  
          #if ( portCRITICAL_NESTING_IN_TCB == 1 )
              UBaseType_t uxCriticalNesting;  /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
          #endif
  
          #if ( configUSE_TRACE_FACILITY == 1 )
              UBaseType_t uxTCBNumber;        /*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
              UBaseType_t uxTaskNumber;       /*< Stores a number specifically for use by third party trace code. */
          #endif
  
          #if ( configUSE_MUTEXES == 1 )
              UBaseType_t uxBasePriority;     /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
              UBaseType_t uxMutexesHeld;
          #endif
  
          #if ( configUSE_APPLICATION_TASK_TAG == 1 )
              TaskHookFunction_t pxTaskTag;
          #endif
  
          #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
              void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
          #endif
  
          #if ( configGENERATE_RUN_TIME_STATS == 1 )
              uint32_t ulRunTimeCounter;      /*< Stores the amount of time the task has spent in the Running state. */
          #endif
  
          #if ( configUSE_NEWLIB_REENTRANT == 1 )
  
              /* Allocate a Newlib reent structure that is specific to this task.
               * Note Newlib support has been included by popular demand, but is not
               * used by the FreeRTOS maintainers themselves.  FreeRTOS is not
               * responsible for resulting newlib operation.  User must be familiar with
               * newlib and must provide system-wide implementations of the necessary
               * stubs. Be warned that (at the time of writing) the current newlib design
               * implements a system-wide malloc() that must be provided with locks. */
              struct  _reent xNewLib_reent;
          #endif
  
          #if ( configUSE_TASK_NOTIFICATIONS == 1 )
              volatile uint32_t ulNotifiedValue;
              volatile uint8_t ucNotifyState;
          #endif
  
          /* See the comments above the definition of
           * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
          #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
              uint8_t ucStaticallyAllocated;                     /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
          #endif
  
          #if ( INCLUDE_xTaskAbortDelay == 1 )
              uint8_t ucDelayAborted;
          #endif
  
          #if ( configUSE_POSIX_ERRNO == 1 )
              int iTaskErrno;
          #endif
      } tskTCB;
  
  
      void vPortSetStackCheck( TaskHandle_t old,
                               TaskHandle_t new )
      {
          if( new != NULL )
          {
              arc_aux_write( AUX_USTACK_BASE, ( uint32_t ) ( new->pxEndOfStack ) );
              arc_aux_write( AUX_USTACK_TOP, ( uint32_t ) ( new->pxStack ) );
          }
      }
  #endif /* if ARC_FEATURE_STACK_CHECK */
  