Feature: SMP (#278)

* Add XMOS XCore ports

Some minor modifications are also made to the kernel to support the
XCore compiler's automatic stack size calculation.

* Update kernel to support SMP

The XMOS XCore ports are also updated to support SMP.

* Fix compiler warnings in xcore ports

The port set and clear interrupt mask from ISR macros were removed from
the ports so that the default macros found in FreeRTOS.h are used
instead. The default macros do not result in warnings when they are
used.

* Remove inline function from timers.h

Inline function converted to macro. This should now build when
optimizations are off and inlining is disabled.

* Fix compiler warnings in xcore ports and tasks.c

* fixed documentation for ulTaskNotifyTake() and ulTaskNotifyTakeIndexed()

* spelling fixes for tasks.c

Co-authored-by: Michael Bruno <mikeb@xmos.com>
This commit is contained in:
Joseph Julicher 2021-03-15 17:29:08 -07:00 committed by GitHub
parent cafae476e4
commit 989bc332b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
509 changed files with 176869 additions and 174380 deletions

View file

@ -256,7 +256,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{
@ -408,7 +408,7 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{
@ -667,6 +667,7 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup )
/* For internal use only - execute a 'set bits' command that was pended from
* an interrupt. */
portTIMER_CALLBACK_ATTRIBUTE
void vEventGroupSetBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToSet )
{
@ -676,6 +677,7 @@ void vEventGroupSetBitsCallback( void * pvEventGroup,
/* For internal use only - execute a 'clear bits' command that was pended from
* an interrupt. */
portTIMER_CALLBACK_ATTRIBUTE
void vEventGroupClearBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToClear )
{

View file

@ -236,6 +236,14 @@
#define configUSE_COUNTING_SEMAPHORES 0
#endif
#ifndef configUSE_TASK_PREEMPTION_DISABLE
#define configUSE_TASK_PREEMPTION_DISABLE 0
#endif
#ifndef configUSE_CORE_EXCLUSION
#define configUSE_CORE_EXCLUSION 0
#endif
#ifndef configUSE_ALTERNATIVE_API
#define configUSE_ALTERNATIVE_API 0
#endif
@ -283,6 +291,15 @@
#define portSOFTWARE_BARRIER()
#endif
#ifndef configNUM_CORES
#define configNUM_CORES 1
#endif
#ifndef configRUN_MULTIPLE_PRIORITIES
#define configRUN_MULTIPLE_PRIORITIES 0
#endif
/* The timers module relies on xTaskGetSchedulerState(). */
#if configUSE_TIMERS == 1
@ -298,6 +315,10 @@
#error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined.
#endif /* configTIMER_TASK_STACK_DEPTH */
#ifndef portTIMER_CALLBACK_ATTRIBUTE
#define portTIMER_CALLBACK_ATTRIBUTE
#endif /* portTIMER_CALLBACK_ATTRIBUTE */
#endif /* configUSE_TIMERS */
#ifndef portSET_INTERRUPT_MASK_FROM_ISR
@ -778,10 +799,6 @@
#define portPRIVILEGE_BIT ( ( UBaseType_t ) 0x00 )
#endif
#ifndef portYIELD_WITHIN_API
#define portYIELD_WITHIN_API portYIELD
#endif
#ifndef portSUPPRESS_TICKS_AND_SLEEP
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime )
#endif
@ -931,6 +948,18 @@
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
#endif
#if( ( configRUN_MULTIPLE_PRIORITIES == 0 ) && ( configUSE_CORE_EXCLUSION != 0 ) )
#error configRUN_MULTIPLE_PRIORITIES must be set to 1 to use core exclusion
#endif
#if( ( configRUN_MULTIPLE_PRIORITIES == 0 ) && ( configUSE_TASK_PREEMPTION_DISABLE != 0 ) )
#error configRUN_MULTIPLE_PRIORITIES must be set to 1 to use task preemption disable
#endif
#if( ( configUSE_PREEMPTION == 0 ) && ( configUSE_TASK_PREEMPTION_DISABLE != 0 ) )
#error configUSE_PREEMPTION must be set to 1 to use task preemption disable
#endif
#ifndef configINITIAL_TICK_COUNT
#define configINITIAL_TICK_COUNT 0
#endif
@ -1175,7 +1204,14 @@ typedef struct xSTATIC_TCB
StaticListItem_t xDummy3[ 2 ];
UBaseType_t uxDummy5;
void * pxDummy6;
BaseType_t xDummy23[ 2 ];
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
BaseType_t xDummy24;
#endif
#if ( configUSE_CORE_EXCLUSION == 1 )
UBaseType_t uxDummy25;
#endif
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
void * pxDummy8;
#endif

View file

@ -214,6 +214,9 @@ typedef enum
* task. h
*
* Macro to disable all maskable interrupts.
* This also returns what the interrupt state was
* upon being called. This state may subsequently
* be passed to taskRESTORE_INTERRUPTS().
*
* \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
* \ingroup SchedulerControl
@ -230,6 +233,28 @@ typedef enum
*/
#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
/**
* task. h
*
* Macro to restore microcontroller interrupts to
* a previous state.
*
* \defgroup taskRESTORE_INTERRUPTS taskRESTORE_INTERRUPTS
* \ingroup SchedulerControl
*/
#define taskRESTORE_INTERRUPTS(ulState) portRESTORE_INTERRUPTS(ulState)
/**
* task. h
*
* Macro that determines if it is being called from within an ISR
* or a task. Returns non-zero if it is in an ISR.
*
* \defgroup taskCHECK_IF_IN_ISR taskCHECK_IF_IN_ISR
* \ingroup SchedulerControl
*/
#define taskCHECK_IF_IN_ISR() portCHECK_IF_IN_ISR()
/* Definitions returned by xTaskGetSchedulerState(). taskSCHEDULER_SUSPENDED is
* 0 to generate more optimal code when configASSERT() is defined as the constant
* is used in assert() statements. */
@ -237,6 +262,8 @@ typedef enum
#define taskSCHEDULER_NOT_STARTED ( ( BaseType_t ) 1 )
#define taskSCHEDULER_RUNNING ( ( BaseType_t ) 2 )
/* Check if core value is valid */
#define taskVALID_CORE_ID( xCoreID ) ( ( BaseType_t ) ( ( 0 <= xCoreID ) && ( xCoreID < configNUM_CORES ) ) )
/*-----------------------------------------------------------
* TASK CREATION API
@ -1208,6 +1235,12 @@ void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
*/
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
void vTaskCoreExclusionSet( const TaskHandle_t xTask, UBaseType_t uxCoreExclude );
UBaseType_t vTaskCoreExclusionGet( const TaskHandle_t xTask );
void vTaskPreemptionDisable( const TaskHandle_t xTask );
void vTaskPreemptionEnable( const TaskHandle_t xTask );
/*-----------------------------------------------------------
* SCHEDULER CONTROL
*----------------------------------------------------------*/
@ -1666,10 +1699,10 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask,
* xTaskGetIdleTaskHandle() is only available if
* INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h.
*
* Simply returns the handle of the idle task. It is not valid to call
* xTaskGetIdleTaskHandle() before the scheduler has been started.
* Simply returns a pointer to the array of idle task handles.
* It is not valid to call xTaskGetIdleTaskHandle() before the scheduler has been started.
*/
TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION;
TaskHandle_t *xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION;
/**
* configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for
@ -2947,7 +2980,7 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,
* Sets the pointer to the current TCB to the TCB of the highest priority task
* that is ready to run.
*/
portDONT_DISCARD void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
portDONT_DISCARD void vTaskSwitchContext( BaseType_t xCoreID ) PRIVILEGED_FUNCTION;
/*
* THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY
@ -2960,6 +2993,11 @@ TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
*/
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
/*
* Return the handle of the task running on specified core.
*/
TaskHandle_t xTaskGetCurrentTaskHandleCPU( UBaseType_t xCoreID ) PRIVILEGED_FUNCTION;
/*
* Shortcut used by the queue implementation to prevent unnecessary call to
* taskYIELD();
@ -3045,6 +3083,11 @@ TaskHandle_t pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
*/
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
/*
* For internal use only. Same as portYIELD_WITHIN_API() in single core FreeRTOS.
* For SMP this is not defined by the port.
*/
void vTaskYieldWithinAPI( void );
/* *INDENT-OFF* */
#ifdef __cplusplus

View file

@ -1312,12 +1312,30 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
* for use by the kernel only.
*/
BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
/*
* Splitting the xTimerGenericCommand into two sub functions and making it a macro
* removes a recursion path when called from ISRs. This is primarily for the XCore
* XCC port which detects the recursion path and throws an error during compilation
* when this is not split.
*/
BaseType_t xTimerGenericCommandFromTask( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
BaseType_t xTimerGenericCommandFromISR( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
#define xTimerGenericCommand( xTimer, xCommandID, xOptionalValue, pxHigherPriorityTaskWoken, xTicksToWait ) \
( ( xCommandID ) < tmrFIRST_FROM_ISR_COMMAND ? \
xTimerGenericCommandFromTask( xTimer, xCommandID, xOptionalValue, pxHigherPriorityTaskWoken, xTicksToWait ) : \
xTimerGenericCommandFromISR( xTimer, xCommandID, xOptionalValue, pxHigherPriorityTaskWoken, xTicksToWait ) )
#if ( configUSE_TRACE_FACILITY == 1 )
void vTimerSetTimerNumber( TimerHandle_t xTimer,
UBaseType_t uxTimerNumber ) PRIVILEGED_FUNCTION;

View file

@ -0,0 +1,238 @@
// Copyright (c) 2019, XMOS Ltd, All rights reserved
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include <xs1.h>
#include <xcore/hwtimer.h>
#include <xcore/triggerable.h>
static hwtimer_t xKernelTimer;
uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ] = { pdFALSE };
/*-----------------------------------------------------------*/
void vIntercoreInterruptISR( void )
{
int xCoreID;
// debug_printf( "In KCALL: %u\n", ulData );
xCoreID = rtos_core_id_get();
ulPortYieldRequired[ xCoreID ] = pdTRUE;
}
/*-----------------------------------------------------------*/
DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
{
uint32_t ulLastTrigger;
uint32_t ulNow;
int xCoreID;
xCoreID = 0;
configASSERT( xCoreID == rtos_core_id_get() );
/* Need the next interrupt to be scheduled relative to
* the current trigger time, rather than the current
* time. */
ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
/* Check to see if the ISR is late. If it is, we don't
* want to schedule the next interrupt to be in the past. */
ulNow = hwtimer_get_time( xKernelTimer );
if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
{
ulLastTrigger = ulNow;
}
ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
#if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
#endif
if( xTaskIncrementTick() != pdFALSE )
{
ulPortYieldRequired[ xCoreID ] = pdTRUE;
}
}
/*-----------------------------------------------------------*/
void vPortYieldOtherCore( int xOtherCoreID )
{
int xCoreID;
/*
* This function must be called from within a critical section.
*/
xCoreID = rtos_core_id_get();
// debug_printf("%d->%d\n", xCoreID, xOtherCoreID);
// debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID );
rtos_irq( xOtherCoreID, xCoreID );
}
/*-----------------------------------------------------------*/
static int prvCoreInit( void )
{
int xCoreID;
xCoreID = rtos_core_register();
debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
asm volatile (
"ldap r11, kexcept\n\t"
"set kep, r11\n\t"
:
:
: "r11"
);
rtos_irq_enable( configNUM_CORES );
/*
* All threads wait here until all have enabled IRQs
*/
while( rtos_irq_ready() == pdFALSE );
if( xCoreID == 0 )
{
uint32_t ulNow;
ulNow = hwtimer_get_time( xKernelTimer );
// debug_printf( "The time is now (%u)\n", ulNow );
ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
hwtimer_set_trigger_time( xKernelTimer, ulNow );
triggerable_enable_trigger( xKernelTimer );
}
return xCoreID;
}
/*-----------------------------------------------------------*/
DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
{
int xCoreID;
xCoreID = prvCoreInit();
debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
/*
* Restore the context of the first thread
* to run and jump into it.
*/
asm volatile (
"mov r6, %0\n\t" /* R6 must be the FreeRTOS core ID*/
"ldaw r5, dp[pxCurrentTCBs]\n\t" /* R5 must be the TCB list which is indexed by R6 */
"bu _freertos_restore_ctx\n\t"
: /* no outputs */
: "r"(xCoreID)
: "r5", "r6"
);
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
/* Public functions required by all ports below: */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
//debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode );
/*
* Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
* so we can push the context onto it.
*/
pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
uint32_t dp;
uint32_t cp;
/*
* We need to get the current CP and DP pointers.
*/
asm volatile (
"ldaw r11, cp[0]\n\t" /* get CP into R11 */
"mov %0, r11\n\t" /* get R11 (CP) into cp */
"ldaw r11, dp[0]\n\t" /* get DP into R11 */
"mov %1, r11\n\t" /* get R11 (DP) into dp */
: "=r"(cp), "=r"(dp) /* output 0 is cp, output 1 is dp */
: /* there are no inputs */
: "r11" /* R11 gets clobbered */
);
/*
* Push the thread context onto the stack.
* Saved PC will point to the new thread's
* entry pointer.
* Interrupts will default to enabled.
* KEDI is also set to enable dual issue mode
* upon kernel entry.
*/
pxTopOfStack[ 1 ] = ( StackType_t ) pxCode; /* SP[1] := SPC */
pxTopOfStack[ 2 ] = XS1_SR_IEBLE_MASK
| XS1_SR_KEDI_MASK; /* SP[2] := SSR */
pxTopOfStack[ 3 ] = 0x00000000; /* SP[3] := SED */
pxTopOfStack[ 4 ] = 0x00000000; /* SP[4] := ET */
pxTopOfStack[ 5 ] = dp; /* SP[5] := DP */
pxTopOfStack[ 6 ] = cp; /* SP[6] := CP */
pxTopOfStack[ 7 ] = 0x00000000; /* SP[7] := LR */
pxTopOfStack[ 8 ] = ( StackType_t ) pvParameters; /* SP[8] := R0 */
pxTopOfStack[ 9 ] = 0x01010101; /* SP[9] := R1 */
pxTopOfStack[ 10 ] = 0x02020202; /* SP[10] := R2 */
pxTopOfStack[ 11 ] = 0x03030303; /* SP[11] := R3 */
pxTopOfStack[ 12 ] = 0x04040404; /* SP[12] := R4 */
pxTopOfStack[ 13 ] = 0x05050505; /* SP[13] := R5 */
pxTopOfStack[ 14 ] = 0x06060606; /* SP[14] := R6 */
pxTopOfStack[ 15 ] = 0x07070707; /* SP[15] := R7 */
pxTopOfStack[ 16 ] = 0x08080808; /* SP[16] := R8 */
pxTopOfStack[ 17 ] = 0x09090909; /* SP[17] := R9 */
pxTopOfStack[ 18 ] = 0x10101010; /* SP[18] := R10 */
pxTopOfStack[ 19 ] = 0x11111111; /* SP[19] := R11 */
//debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode );
/*
* Returns the new top of the stack
*/
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
void vPortStartSMPScheduler( void );
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
if( ( configNUM_CORES > portMAX_CORE_COUNT ) || ( configNUM_CORES <= 0 ) )
{
return pdFAIL;
}
rtos_locks_initialize();
xKernelTimer = hwtimer_alloc();
vPortStartSMPScheduler();
return pdPASS;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Do not implement. */
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,26 @@
/*
* port.xc
*
* Created on: Jul 31, 2019
* Author: mbruno
*/
//#include "rtos_support.h"
extern "C" {
#include "FreeRTOSConfig.h" /* to get configNUM_CORES */
#ifndef configNUM_CORES
#define configNUM_CORES 1
#endif
void __xcore_interrupt_permitted_ugs_vPortStartSchedulerOnCore(void);
} /* extern "C" */
void vPortStartSMPScheduler( void )
{
par (int i = 0; i < configNUM_CORES; i++) {
__xcore_interrupt_permitted_ugs_vPortStartSchedulerOnCore();
}
}

View file

@ -0,0 +1,160 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#include "rtos_support_rtos_config.h"
/* The FreeRTOS interrupt code calls vTaskSwitchContext.
Therfore it must be added to the rtos_isr group with the
rest of the ISR callback functions. */
.weak _fptrgroup.rtos_isr.nstackwords.group
.add_to_set _fptrgroup.rtos_isr.nstackwords.group, vTaskSwitchContext.nstackwords, vTaskSwitchContext
.globl kexcept
.align 128 /* align the kernel section to 128 bytes */
.type kexcept,@function
.issue_mode dual
.cc_top kexcept.function, kexcept
kexcept:
ldc r11, 0x0004
shl r11, r11, 16
ldc r9, 0x0080
or r11, r11, r9
bau r11 //_TrapHandler is at 0x00040080. TODO: Is it always? Why can't I access the symbol _TrapHandler?
_yield:
{set sp, r4 /* Restore the task's SP to save the rest of its context. */
get r11, id} /* Get the logical core ID into r11. */
ldaw r0, dp[rtos_core_map]
ldw r0, r0[r11] /* Translate to the RTOS core ID into r0 */
bu _yield_continue /* Skip the ulPortYieldRequired check and jump right to */
/* the context save and switch. Also skips saving SPC */
/* since the kcall handler has already saved it. */
.align 64
kcall:
/* start saving the thread's context */
extsp RTOS_SUPPORT_INTERRUPT_STACK_GROWTH
stw r1, sp[9]
stw r11, sp[19]
/* kcall sets SPC to the instruction of the kcall rather than the next instruction */
/* so we need to adjust the SPC value that we save to the stack: */
stw spc, sp[1] /* save the saved program counter onto the stack... */
ldw r1, sp[1] /* so that we can load it into r1 (which we have already saved). */
add r1, r1, 4 /* Add 4 to the spc to make it point to the instruction after the kcall. */
{stw r1, sp[1] /* Now save it to the stack. */
/* kcall uses the same common function as interrupt callbacks. */
/* tell it to call _yield above. */
ldap r11, _yield}
mov r1, r11
/* fall into rtos_interrupt_callback_common */
.globl rtos_interrupt_callback_common
rtos_interrupt_callback_common:
/* This is the body of the RTOS _xcore_c_interrupt_callback_XXX functions. */
/* r1 = interrupt_callback_t function */
/* Save the thread's context onto the thread's stack. */
/* The stack was extended for this by the wrapper function. */
/* Begin only by saving some registers. The rest will be saved */
/* later if vTaskSwitchContext() needs to be called. */
/* LR needs to be saved because it is clobbered when calling the callback. */
/* r0-r3, and r11 need to be saved because the callback may clobber them. */
/* r4 is saved because it is used here to hold the task SP. */
stw lr, sp[7]
stw r0, sp[8]
/*stw r1, sp[9] already saved by the wrapper function. */
stw r2, sp[10]
stw r3, sp[11]
{stw r4, sp[12]
/*stw r11, sp[19] already saved by the wrapper function. */
ldaw r4, sp[0]} /* Get value of current stackpointer into r4. */
{kentsp 0 /* switch to the kernel stack. */
/* The value 0 is safe to use since we don't need the SP */
/* that it saves to KSP[0]. We already have it in r4. */
get r11, ed} /* Get the event data... */
{mov r0, r11 /* into the first argument for the callback function... */
bla r1} /* and call the callback function. */
{set sp, r4 /* Restore the task's SP now. */
get r11, id} /* Get the logical core ID into r11. */
ldaw r0, dp[rtos_core_map]
ldw r0, r0[r11] /* Translate to the RTOS core ID into r0. */
ldaw r2, dp[ulPortYieldRequired] /* Get the yield required array into r2. */
ldw r1, r2[r0] /* Is a yield required for this core? */
{bf r1, _freertos_restore_ctx_partial /* If not, restore the context now. */
ldc r1, 0}
stw r1, r2[r0] /* Otherwise, clear the yield required flag. */
/* Save the rest of the current task's context. */
stw spc, sp[1]
_yield_continue:
stw ssr, sp[2]
stw sed, sp[3]
stw et, sp[4]
stw dp, sp[5]
stw cp, sp[6]
stw r5, sp[13]
stw r6, sp[14]
stw r7, sp[15]
stw r8, sp[16]
stw r9, sp[17]
stw r10, sp[18]
ldaw r5, dp[pxCurrentTCBs] /* Get the current TCB array into r5. */
ldw r1, r5[r0] /* Get this core's current TCB pointer into r1. */
stw r4, r1[0x0] /* Save the current task's SP to the first */
/* word (top of stack) in the current TCB. */
{kentsp 0 /* switch back to the kernel stack. */
mov r6, r0} /* copy the RTOS core ID into r6 so we don't lose it. */
ldap r11, vTaskSwitchContext
bla r11 /* Finally call vTaskSwitchContext(core_id) now that the task's */
/* entire context is saved. Note the core id in r0 is the argument. */
//krestsp 0 /* unnecessary since KSP is already set and the SP */
/* is being restored next from the current TCB. */
.globl _freertos_restore_ctx
_freertos_restore_ctx:
ldw r0, r5[r6] /* get this core's current TCB pointer into r0 */
ldw r0, r0[0x0] /* Get the top of the stack from the current TCB... */
set sp, r0; /* into the stack pointer register. */
/* Restore the state */
ldw spc, sp[1]
ldw ssr, sp[2]
ldw sed, sp[3]
ldw et, sp[4]
ldw dp, sp[5]
ldw cp, sp[6]
ldw r5, sp[13]
ldw r6, sp[14]
ldw r7, sp[15]
ldw r8, sp[16]
ldw r9, sp[17]
ldw r10, sp[18]
_freertos_restore_ctx_partial:
ldw lr, sp[7]
ldw r0, sp[8]
ldw r1, sp[9]
ldw r2, sp[10]
ldw r3, sp[11]
ldw r4, sp[12]
{ldw r11, sp[19]
/* shrink the stack by the size of the context just restored */
ldaw sp, sp[RTOS_SUPPORT_INTERRUPT_STACK_GROWTH]}
kret /* exit kernel mode and return to the thread */
.cc_bottom kexcept.function

View file

@ -0,0 +1,218 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifndef __ASSEMBLER__
/* Inclusion of xc1.h will result in clock being defined as a type.
* By default, FreeRTOS will require standard time.h, where clock is a function.
*/
#ifndef USE_XCORE_CLOCK_TYPE
#define _clock_defined
#endif
#include <xs1.h>
#include "rtos_support.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Type definitions. */
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
typedef double portDOUBLE;
typedef int32_t BaseType_t;
typedef uint32_t UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
#endif /* __ASSEMBLER__ */
/* Architecture specifics. These can be used by assembly files as well. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portCRITICAL_NESTING_IN_TCB 1
#define portMAX_CORE_COUNT 8
#ifndef configNUM_CORES
#define configNUM_CORES 1
#endif
/* This may be set to zero in the config file if the rtos_time
functions are not needed or if it is incremented elsewhere. */
#ifndef configUPDATE_RTOS_TIME_FROM_TICK_ISR
#define configUPDATE_RTOS_TIME_FROM_TICK_ISR 1
#endif
/*
* When entering an ISR we need to grow the stack by one more word than
* we actually need to save the thread context. This is because there are
* some functions, written in assembly *cough* memcpy() *cough*, that think
* it is OK to store words at SP[0]. Therefore the ISR must leave SP[0] alone
* even though it is normally not necessary to do so.
*/
#define portTHREAD_CONTEXT_STACK_GROWTH RTOS_SUPPORT_INTERRUPT_STACK_GROWTH
#ifndef __ASSEMBLER__
/* Check validity of number of cores specified in config */
#if ( configNUM_CORES < 1 || portMAX_CORE_COUNT < configNUM_CORES )
#error "Invalid number of cores specified in config!"
#endif
#define portMEMORY_BARRIER() RTOS_MEMORY_BARRIER()
#define portTASK_STACK_DEPTH(pxTaskCode) RTOS_THREAD_STACK_SIZE(pxTaskCode)
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() asm volatile( "KCALLI_lu6 0" ::: "memory" )
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
do \
{ \
if( xSwitchRequired != pdFALSE ) \
{ \
extern uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ]; \
ulPortYieldRequired[ portGET_CORE_ID() ] = pdTRUE; \
} \
} while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* SMP utilities. */
#define portGET_CORE_ID() rtos_core_id_get()
void vPortYieldOtherCore( int xOtherCoreID );
#define portYIELD_CORE( x ) vPortYieldOtherCore( x )
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */
#define portGET_INTERRUPT_STATE() rtos_interrupt_mask_get()
/*
* This differs from the standard portDISABLE_INTERRUPTS()
* in that it also returns what the interrupt state was
* before it disabling interrupts.
*/
#define portDISABLE_INTERRUPTS() rtos_interrupt_mask_all()
#define portENABLE_INTERRUPTS() rtos_interrupt_unmask_all()
/*
* Will enable interrupts if ulState is non-zero.
*/
#define portRESTORE_INTERRUPTS(ulState) rtos_interrupt_mask_set(ulState)
/*
* Returns non-zero if currently running in an
* ISR or otherwise in kernel mode.
*/
#define portCHECK_IF_IN_ISR() rtos_isr_running()
#define portASSERT_IF_IN_ISR() configASSERT( portCHECK_IF_IN_ISR() == 0 )
#define portGET_ISR_LOCK() rtos_lock_acquire(0)
#define portRELEASE_ISR_LOCK() rtos_lock_release(0)
#define portGET_TASK_LOCK() rtos_lock_acquire(1)
#define portRELEASE_TASK_LOCK() rtos_lock_release(1)
void vTaskEnterCritical(void);
void vTaskExitCritical(void);
#define portENTER_CRITICAL() vTaskEnterCritical()
#define portEXIT_CRITICAL() vTaskExitCritical()
/*
* vTaskEnterCritical() has been modified to be safe to use
* from within ISRs. The previous mask does not need to be
* returned since in the xCORE interrupts are always disabled
* in ISRs. Effectively this call just grabs the kernel lock
* when called from an ISR.
*/
#define portSET_INTERRUPT_MASK_FROM_ISR() (vTaskEnterCritical(), 0)
/*
* vTaskExitCritical() has been modified to be safe to use
* from within ISRs. When the nesting level has reached zero
* it releases the lock, but when called from within an ISR
* it will *not* re-enable interrupts since it is assumed they
* were previously disabled. Thus the previous state in x is
* unused.
*/
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) (vTaskExitCritical(), (void) x)
/*-----------------------------------------------------------*/
/* Runtime stats support */
#if ( configGENERATE_RUN_TIME_STATS == 1 )
int xscope_gettime( void );
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() /* nothing needed here */
#define portGET_RUN_TIME_COUNTER_VALUE() xscope_gettime()
#endif
/*-----------------------------------------------------------*/
/* Maps sprintf and snprintf to the lite version in lib_rtos_support */
#if ( configUSE_DEBUG_SPRINTF == 1 )
#define sprintf(...) rtos_sprintf(__VA_ARGS__)
#define snprintf(...) rtos_snprintf(__VA_ARGS__)
#endif
/* Attribute for the pxCallbackFunction member of the Timer_t struct.
Required by xcc to calculate stack usage. */
#define portTIMER_CALLBACK_ATTRIBUTE __attribute__((fptrgroup("timerCallbackGroup")))
/* Timer callback function macros. For xcc this ensures they get added to the timer callback
group so that stack usage for certain functions in timers.c can be calculated. */
#define portTIMER_CALLBACK_FUNCTION_PROTO( vFunction, xTimer ) void vFunction( TimerHandle_t xTimer )
#define portTIMER_CALLBACK_FUNCTION( vFunction, xTimer ) portTIMER_CALLBACK_ATTRIBUTE void vFunction( TimerHandle_t xTimer )
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLER__ */
#endif /* PORTMACRO_H */

View file

@ -0,0 +1,95 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#ifndef RTOS_SUPPORT_RTOS_CONFIG_H_
#define RTOS_SUPPORT_RTOS_CONFIG_H_
/**
* Lets the application know that the RTOS in use is FreeRTOS.
*/
#define RTOS_FREERTOS 1
/**
* The number of words to extend the stack by when entering an ISR.
*
* When entering an ISR we need to grow the stack by one more word than
* we actually need to save the thread context. This is because there are
* some functions, written in assembly *cough* memcpy() *cough*, that think
* it is OK to store words at SP[0]. Therefore the ISR must leave SP[0] alone
* even though it is normally not necessary to do so.
*/
#define RTOS_SUPPORT_INTERRUPT_STACK_GROWTH ( 19 + 1 )
/**
* The word offset into the stack where R1 is to be stored after it
* is extended when saving a thread's context.
*/
#define RTOS_SUPPORT_INTERRUPT_R1_STACK_OFFSET 9
/**
* The word offset into the stack where R11 is to be stored after it
* is extended when saving a thread's context.
*/
#define RTOS_SUPPORT_INTERRUPT_R11_STACK_OFFSET 19
/**
* The RTOS provided handler that should run when a
* core receives an intercore interrupt request.
*/
#define RTOS_INTERCORE_INTERRUPT_ISR() do { \
void vIntercoreInterruptISR( void ); \
vIntercoreInterruptISR(); \
} while ( 0 )
/**
* The number of hardware locks that the RTOS
* requires. For a single core RTOS this could be
* zero. Locks are recursive.
*
* Note that the IRQ routines require a lock and
* will share the first one with the RTOS.
*/
#define RTOS_LOCK_COUNT 2
/**
* Remaps all calls to debug_printf() to rtos_printf().
* When this is on, files should not include both rtos_support.h
* and debug_print.h.
*/
#define RTOS_DEBUG_PRINTF_REMAP 1
#ifdef configENABLE_DEBUG_PRINTF
#if configENABLE_DEBUG_PRINTF
/* ensure that debug_printf is enabled */
#ifdef DEBUG_PRINT_ENABLE
#undef DEBUG_PRINT_ENABLE
#endif
#define DEBUG_PRINT_ENABLE 1
#ifndef configTASKS_DEBUG
#define configTASKS_DEBUG 0
#endif
#if configTASKS_DEBUG == 1
#define DEBUG_PRINT_ENABLE_FREERTOS_TASKS 1
#else
#define DEBUG_PRINT_DISABLE_FREERTOS_TASKS 1
#endif
#else /* configENABLE_DEBUG_PRINTF */
/* ensure that debug_printf is disabled */
#ifdef DEBUG_UNIT
#undef DEBUG_UNIT
#endif
#ifdef DEBUG_PRINT_ENABLE
#undef DEBUG_PRINT_ENABLE
#endif
#define DEBUG_PRINT_ENABLE 0
#endif /* configENABLE_DEBUG_PRINTF */
#endif
#endif /* RTOS_SUPPORT_RTOS_CONFIG_H_ */

251
portable/XCC/XCOREAI/port.c Normal file
View file

@ -0,0 +1,251 @@
// Copyright (c) 2019, XMOS Ltd, All rights reserved
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
#include <xs1.h>
#include <xcore/hwtimer.h>
#include <xcore/triggerable.h>
static hwtimer_t xKernelTimer;
uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ] = { pdFALSE };
/*-----------------------------------------------------------*/
void vIntercoreInterruptISR( void )
{
int xCoreID;
// debug_printf( "In KCALL: %u\n", ulData );
xCoreID = rtos_core_id_get();
ulPortYieldRequired[ xCoreID ] = pdTRUE;
}
/*-----------------------------------------------------------*/
DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
{
uint32_t ulLastTrigger;
uint32_t ulNow;
int xCoreID;
xCoreID = 0;
configASSERT( xCoreID == rtos_core_id_get() );
/* Need the next interrupt to be scheduled relative to
* the current trigger time, rather than the current
* time. */
ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
/* Check to see if the ISR is late. If it is, we don't
* want to schedule the next interrupt to be in the past. */
ulNow = hwtimer_get_time( xKernelTimer );
if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
{
ulLastTrigger = ulNow;
}
ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
#if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
#endif
if( xTaskIncrementTick() != pdFALSE )
{
ulPortYieldRequired[ xCoreID ] = pdTRUE;
}
}
/*-----------------------------------------------------------*/
void vPortYieldOtherCore( int xOtherCoreID )
{
int xCoreID;
/*
* This function must be called from within a critical section.
*/
xCoreID = rtos_core_id_get();
// debug_printf("%d->%d\n", xCoreID, xOtherCoreID);
// debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID );
rtos_irq( xOtherCoreID, xCoreID );
}
/*-----------------------------------------------------------*/
static int prvCoreInit( void )
{
int xCoreID;
xCoreID = rtos_core_register();
debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
asm volatile (
"ldap r11, kexcept\n\t"
"set kep, r11\n\t"
:
:
: "r11"
);
rtos_irq_enable( configNUM_CORES );
/*
* All threads wait here until all have enabled IRQs
*/
while( rtos_irq_ready() == pdFALSE );
if( xCoreID == 0 )
{
uint32_t ulNow;
ulNow = hwtimer_get_time( xKernelTimer );
// debug_printf( "The time is now (%u)\n", ulNow );
ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
hwtimer_set_trigger_time( xKernelTimer, ulNow );
triggerable_enable_trigger( xKernelTimer );
}
return xCoreID;
}
/*-----------------------------------------------------------*/
DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
{
int xCoreID;
xCoreID = prvCoreInit();
#if( configUSE_CORE_INIT_HOOK == 1 )
{
extern void vApplicationCoreInitHook( BaseType_t xCoreID );
vApplicationCoreInitHook( xCoreID );
}
#endif
debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
/*
* Restore the context of the first thread
* to run and jump into it.
*/
asm volatile (
"mov r6, %0\n\t" /* R6 must be the FreeRTOS core ID*/
"ldaw r5, dp[pxCurrentTCBs]\n\t" /* R5 must be the TCB list which is indexed by R6 */
"bu _freertos_restore_ctx\n\t"
: /* no outputs */
: "r"(xCoreID)
: "r5", "r6"
);
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
/* Public functions required by all ports below: */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
//debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode );
/*
* Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
* so we can push the context onto it.
*/
pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
uint32_t dp;
uint32_t cp;
/*
* We need to get the current CP and DP pointers.
*/
asm volatile (
"ldaw r11, cp[0]\n\t" /* get CP into R11 */
"mov %0, r11\n\t" /* get R11 (CP) into cp */
"ldaw r11, dp[0]\n\t" /* get DP into R11 */
"mov %1, r11\n\t" /* get R11 (DP) into dp */
: "=r"(cp), "=r"(dp) /* output 0 is cp, output 1 is dp */
: /* there are no inputs */
: "r11" /* R11 gets clobbered */
);
/*
* Push the thread context onto the stack.
* Saved PC will point to the new thread's
* entry pointer.
* Interrupts will default to enabled.
* KEDI is also set to enable dual issue mode
* upon kernel entry.
*/
pxTopOfStack[ 1 ] = ( StackType_t ) pxCode; /* SP[1] := SPC */
pxTopOfStack[ 2 ] = XS1_SR_IEBLE_MASK
| XS1_SR_KEDI_MASK; /* SP[2] := SSR */
pxTopOfStack[ 3 ] = 0x00000000; /* SP[3] := SED */
pxTopOfStack[ 4 ] = 0x00000000; /* SP[4] := ET */
pxTopOfStack[ 5 ] = dp; /* SP[5] := DP */
pxTopOfStack[ 6 ] = cp; /* SP[6] := CP */
pxTopOfStack[ 7 ] = 0x00000000; /* SP[7] := LR */
pxTopOfStack[ 8 ] = ( StackType_t ) pvParameters; /* SP[8] := R0 */
pxTopOfStack[ 9 ] = 0x01010101; /* SP[9] := R1 */
pxTopOfStack[ 10 ] = 0x02020202; /* SP[10] := R2 */
pxTopOfStack[ 11 ] = 0x03030303; /* SP[11] := R3 */
pxTopOfStack[ 12 ] = 0x04040404; /* SP[12] := R4 */
pxTopOfStack[ 13 ] = 0x05050505; /* SP[13] := R5 */
pxTopOfStack[ 14 ] = 0x06060606; /* SP[14] := R6 */
pxTopOfStack[ 15 ] = 0x07070707; /* SP[15] := R7 */
pxTopOfStack[ 16 ] = 0x08080808; /* SP[16] := R8 */
pxTopOfStack[ 17 ] = 0x09090909; /* SP[17] := R9 */
pxTopOfStack[ 18 ] = 0x10101010; /* SP[18] := R10 */
pxTopOfStack[ 19 ] = 0x11111111; /* SP[19] := R11 */
pxTopOfStack[ 20 ] = 0x00000000; /* SP[20] := vH and vSR */
memset(&pxTopOfStack[21], 0, 32); /* SP[21 - 28] := vR */
memset(&pxTopOfStack[29], 1, 32); /* SP[29 - 36] := vD */
memset(&pxTopOfStack[37], 2, 32); /* SP[37 - 44] := vC */
//debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode );
/*
* Returns the new top of the stack
*/
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
void vPortStartSMPScheduler( void );
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
if( ( configNUM_CORES > portMAX_CORE_COUNT ) || ( configNUM_CORES <= 0 ) )
{
return pdFAIL;
}
rtos_locks_initialize();
xKernelTimer = hwtimer_alloc();
vPortStartSMPScheduler();
return pdPASS;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Do not implement. */
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,26 @@
/*
* port.xc
*
* Created on: Jul 31, 2019
* Author: mbruno
*/
//#include "rtos_support.h"
extern "C" {
#include "FreeRTOSConfig.h" /* to get configNUM_CORES */
#ifndef configNUM_CORES
#define configNUM_CORES 1
#endif
void __xcore_interrupt_permitted_ugs_vPortStartSchedulerOnCore(void);
} /* extern "C" */
void vPortStartSMPScheduler( void )
{
par (int i = 0; i < configNUM_CORES; i++) {
__xcore_interrupt_permitted_ugs_vPortStartSchedulerOnCore();
}
}

View file

@ -0,0 +1,186 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#include "rtos_support_rtos_config.h"
/* The FreeRTOS interrupt code calls vTaskSwitchContext.
Therfore it must be added to the rtos_isr group with the
rest of the ISR callback functions. */
.weak _fptrgroup.rtos_isr.nstackwords.group
.add_to_set _fptrgroup.rtos_isr.nstackwords.group, vTaskSwitchContext.nstackwords, vTaskSwitchContext
.globl kexcept
.align 128 /* align the kernel section to 128 bytes */
.type kexcept,@function
.issue_mode dual
.cc_top kexcept.function, kexcept
kexcept:
ldc r11, 0x0008
shl r11, r11, 16
ldc r9, 0x0080
or r11, r11, r9
bau r11 //_TrapHandler is at 0x00080080. TODO: Is it always? Why can't I access the symbol _TrapHandler?
_yield:
{set sp, r4 /* Restore the task's SP to save the rest of its context. */
get r11, id} /* Get the logical core ID into r11. */
ldaw r0, dp[rtos_core_map]
ldw r0, r0[r11] /* Translate to the RTOS core ID into r0 */
bu _yield_continue /* Skip the ulPortYieldRequired check and jump right to */
/* the context save and switch. Also skips saving SPC */
/* since the kcall handler has already saved it. */
.align 64
kcall:
/* start saving the thread's context */
extsp RTOS_SUPPORT_INTERRUPT_STACK_GROWTH
stw r1, sp[9]
stw r11, sp[19]
/* kcall sets SPC to the instruction of the kcall rather than the next instruction */
/* so we need to adjust the SPC value that we save to the stack: */
stw spc, sp[1] /* save the saved program counter onto the stack... */
ldw r1, sp[1] /* so that we can load it into r1 (which we have already saved). */
add r1, r1, 4 /* Add 4 to the spc to make it point to the instruction after the kcall. */
{stw r1, sp[1] /* Now save it to the stack. */
/* kcall uses the same common function as interrupt callbacks. */
/* tell it to call _yield above. */
ldap r11, _yield}
mov r1, r11
/* fall into rtos_interrupt_callback_common */
.globl rtos_interrupt_callback_common
rtos_interrupt_callback_common:
/* This is the body of the RTOS _xcore_c_interrupt_callback_XXX functions. */
/* r1 = interrupt_callback_t function */
/* Save the thread's context onto the thread's stack. */
/* The stack was extended for this by the wrapper function. */
/* Begin only by saving some registers. The rest will be saved */
/* later if vTaskSwitchContext() needs to be called. */
/* LR needs to be saved because it is clobbered when calling the callback. */
/* r0-r3, and r11 need to be saved because the callback may clobber them. */
/* r4 is saved because it is used here to hold the task SP. */
stw lr, sp[7]
stw r0, sp[8]
/*stw r1, sp[9] already saved by the wrapper function. */
stw r2, sp[10]
stw r3, sp[11]
{stw r4, sp[12]
/*stw r11, sp[19] already saved by the wrapper function. */
ldaw r4, sp[0]} /* Get value of current stackpointer into r4. */
{kentsp 0 /* switch to the kernel stack. */
/* The value 0 is safe to use since we don't need the SP */
/* that it saves to KSP[0]. We already have it in r4. */
get r11, ed} /* Get the event data... */
{mov r0, r11 /* into the first argument for the callback function... */
bla r1} /* and call the callback function. */
{set sp, r4 /* Restore the task's SP now. */
get r11, id} /* Get the logical core ID into r11. */
ldaw r0, dp[rtos_core_map]
ldw r0, r0[r11] /* Translate to the RTOS core ID into r0. */
ldaw r2, dp[ulPortYieldRequired] /* Get the yield required array into r2. */
ldw r1, r2[r0] /* Is a yield required for this core? */
{bf r1, _freertos_restore_ctx_partial /* If not, restore the context now. */
ldc r1, 0}
stw r1, r2[r0] /* Otherwise, clear the yield required flag. */
/* Save the rest of the current task's context. */
/* Save standard xs2 regs */
stw spc, sp[1]
_yield_continue:
stw ssr, sp[2]
stw sed, sp[3]
stw et, sp[4]
stw dp, sp[5]
stw cp, sp[6]
stw r5, sp[13]
stw r6, sp[14]
stw r7, sp[15]
stw r8, sp[16]
stw r9, sp[17]
stw r10, sp[18]
#if 1
/* Save VPU status and headroom */
vgetc r11
{stw r11, sp[20]
/* Save VPU regs */
ldaw r11, sp[21]}
{vstr r11[0]
ldaw r11, sp[29]}
{vstd r11[0]
ldaw r11, sp[37]}
vstc r11[0]
#endif
ldaw r5, dp[pxCurrentTCBs] /* Get the current TCB array into r5. */
ldw r1, r5[r0] /* Get this core's current TCB pointer into r1. */
stw r4, r1[0x0] /* Save the current task's SP to the first */
/* word (top of stack) in the current TCB. */
{kentsp 0 /* switch back to the kernel stack. */
mov r6, r0} /* copy the RTOS core ID into r6 so we don't lose it. */
ldap r11, vTaskSwitchContext
bla r11 /* Finally call vTaskSwitchContext(core_id) now that the task's */
/* entire context is saved. Note the core id in r0 is the argument. */
//krestsp 0 /* unnecessary since KSP is already set and the SP */
/* is being restored next from the current TCB. */
.globl _freertos_restore_ctx
_freertos_restore_ctx:
ldw r0, r5[r6] /* get this core's current TCB pointer into r0 */
ldw r0, r0[0x0] /* Get the top of the stack from the current TCB... */
set sp, r0 /* into the stack pointer register. */
/* Restore the current task's context */
#if 1
/* Restore VPU regs */
ldaw r11, sp[37]
{vldc r11[0]
ldaw r11, sp[29]}
{vldd r11[0]
ldaw r11, sp[21]}
vldr r11[0]
/* Restore VPU status and headroom */
ldw r11, sp[20]
vsetc r11
#endif
/* Restore standard xs2 regs */
ldw spc, sp[1]
ldw ssr, sp[2]
ldw sed, sp[3]
ldw et, sp[4]
ldw dp, sp[5]
ldw cp, sp[6]
ldw r5, sp[13]
ldw r6, sp[14]
ldw r7, sp[15]
ldw r8, sp[16]
ldw r9, sp[17]
ldw r10, sp[18]
_freertos_restore_ctx_partial:
ldw lr, sp[7]
ldw r0, sp[8]
ldw r1, sp[9]
ldw r2, sp[10]
ldw r3, sp[11]
ldw r4, sp[12]
{ldw r11, sp[19]
/* shrink the stack by the size of the context just restored */
ldaw sp, sp[RTOS_SUPPORT_INTERRUPT_STACK_GROWTH]}
kret /* exit kernel mode and return to the thread */
.cc_bottom kexcept.function

View file

@ -0,0 +1,218 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifndef __ASSEMBLER__
/* Inclusion of xc1.h will result in clock being defined as a type.
* By default, FreeRTOS will require standard time.h, where clock is a function.
*/
#ifndef USE_XCORE_CLOCK_TYPE
#define _clock_defined
#endif
#include <xs1.h>
#include "rtos_support.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Type definitions. */
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
typedef double portDOUBLE;
typedef int32_t BaseType_t;
typedef uint32_t UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
#endif /* __ASSEMBLER__ */
/* Architecture specifics. These can be used by assembly files as well. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portCRITICAL_NESTING_IN_TCB 1
#define portMAX_CORE_COUNT 8
#ifndef configNUM_CORES
#define configNUM_CORES 1
#endif
/* This may be set to zero in the config file if the rtos_time
functions are not needed or if it is incremented elsewhere. */
#ifndef configUPDATE_RTOS_TIME_FROM_TICK_ISR
#define configUPDATE_RTOS_TIME_FROM_TICK_ISR 1
#endif
/*
* When entering an ISR we need to grow the stack by one more word than
* we actually need to save the thread context. This is because there are
* some functions, written in assembly *cough* memcpy() *cough*, that think
* it is OK to store words at SP[0]. Therefore the ISR must leave SP[0] alone
* even though it is normally not necessary to do so.
*/
#define portTHREAD_CONTEXT_STACK_GROWTH RTOS_SUPPORT_INTERRUPT_STACK_GROWTH
#ifndef __ASSEMBLER__
/* Check validity of number of cores specified in config */
#if ( configNUM_CORES < 1 || portMAX_CORE_COUNT < configNUM_CORES )
#error "Invalid number of cores specified in config!"
#endif
#define portMEMORY_BARRIER() RTOS_MEMORY_BARRIER()
#define portTASK_STACK_DEPTH(pxTaskCode) RTOS_THREAD_STACK_SIZE(pxTaskCode)
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() asm volatile( "KCALLI_lu6 0" ::: "memory" )
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
do \
{ \
if( xSwitchRequired != pdFALSE ) \
{ \
extern uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ]; \
ulPortYieldRequired[ portGET_CORE_ID() ] = pdTRUE; \
} \
} while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* SMP utilities. */
#define portGET_CORE_ID() rtos_core_id_get()
void vPortYieldOtherCore( int xOtherCoreID );
#define portYIELD_CORE( x ) vPortYieldOtherCore( x )
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */
#define portGET_INTERRUPT_STATE() rtos_interrupt_mask_get()
/*
* This differs from the standard portDISABLE_INTERRUPTS()
* in that it also returns what the interrupt state was
* before it disabling interrupts.
*/
#define portDISABLE_INTERRUPTS() rtos_interrupt_mask_all()
#define portENABLE_INTERRUPTS() rtos_interrupt_unmask_all()
/*
* Will enable interrupts if ulState is non-zero.
*/
#define portRESTORE_INTERRUPTS(ulState) rtos_interrupt_mask_set(ulState)
/*
* Returns non-zero if currently running in an
* ISR or otherwise in kernel mode.
*/
#define portCHECK_IF_IN_ISR() rtos_isr_running()
#define portASSERT_IF_IN_ISR() configASSERT( portCHECK_IF_IN_ISR() == 0 )
#define portGET_ISR_LOCK() rtos_lock_acquire(0)
#define portRELEASE_ISR_LOCK() rtos_lock_release(0)
#define portGET_TASK_LOCK() rtos_lock_acquire(1)
#define portRELEASE_TASK_LOCK() rtos_lock_release(1)
void vTaskEnterCritical(void);
void vTaskExitCritical(void);
#define portENTER_CRITICAL() vTaskEnterCritical()
#define portEXIT_CRITICAL() vTaskExitCritical()
/*
* vTaskEnterCritical() has been modified to be safe to use
* from within ISRs. The previous mask does not need to be
* returned since in the xCORE interrupts are always disabled
* in ISRs. Effectively this call just grabs the kernel lock
* when called from an ISR.
*/
#define portSET_INTERRUPT_MASK_FROM_ISR() (vTaskEnterCritical(), 0)
/*
* vTaskExitCritical() has been modified to be safe to use
* from within ISRs. When the nesting level has reached zero
* it releases the lock, but when called from within an ISR
* it will *not* re-enable interrupts since it is assumed they
* were previously disabled. Thus the previous state in x is
* unused.
*/
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) (vTaskExitCritical(), (void) x)
/*-----------------------------------------------------------*/
/* Runtime stats support */
#if ( configGENERATE_RUN_TIME_STATS == 1 )
int xscope_gettime( void );
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() /* nothing needed here */
#define portGET_RUN_TIME_COUNTER_VALUE() xscope_gettime()
#endif
/*-----------------------------------------------------------*/
/* Maps sprintf and snprintf to the lite version in lib_rtos_support */
#if ( configUSE_DEBUG_SPRINTF == 1 )
#define sprintf(...) rtos_sprintf(__VA_ARGS__)
#define snprintf(...) rtos_snprintf(__VA_ARGS__)
#endif
/* Attribute for the pxCallbackFunction member of the Timer_t struct.
Required by xcc to calculate stack usage. */
#define portTIMER_CALLBACK_ATTRIBUTE __attribute__((fptrgroup("timerCallbackGroup")))
/* Timer callback function macros. For xcc this ensures they get added to the timer callback
group so that stack usage for certain functions in timers.c can be calculated. */
#define portTIMER_CALLBACK_FUNCTION_PROTO( vFunction, xTimer ) void vFunction( TimerHandle_t xTimer )
#define portTIMER_CALLBACK_FUNCTION( vFunction, xTimer ) portTIMER_CALLBACK_ATTRIBUTE void vFunction( TimerHandle_t xTimer )
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLER__ */
#endif /* PORTMACRO_H */

View file

@ -0,0 +1,95 @@
// Copyright (c) 2020, XMOS Ltd, All rights reserved
#ifndef RTOS_SUPPORT_RTOS_CONFIG_H_
#define RTOS_SUPPORT_RTOS_CONFIG_H_
/**
* Lets the application know that the RTOS in use is FreeRTOS.
*/
#define RTOS_FREERTOS 1
/**
* The number of words to extend the stack by when entering an ISR.
*
* When entering an ISR we need to grow the stack by one more word than
* we actually need to save the thread context. This is because there are
* some functions, written in assembly *cough* memcpy() *cough*, that think
* it is OK to store words at SP[0]. Therefore the ISR must leave SP[0] alone
* even though it is normally not necessary to do so.
*/
#define RTOS_SUPPORT_INTERRUPT_STACK_GROWTH ( 44 + 1 )
/**
* The word offset into the stack where R1 is to be stored after it
* is extended when saving a thread's context.
*/
#define RTOS_SUPPORT_INTERRUPT_R1_STACK_OFFSET 9
/**
* The word offset into the stack where R11 is to be stored after it
* is extended when saving a thread's context.
*/
#define RTOS_SUPPORT_INTERRUPT_R11_STACK_OFFSET 19
/**
* The RTOS provided handler that should run when a
* core receives an intercore interrupt request.
*/
#define RTOS_INTERCORE_INTERRUPT_ISR() do { \
void vIntercoreInterruptISR( void ); \
vIntercoreInterruptISR(); \
} while ( 0 )
/**
* The number of hardware locks that the RTOS
* requires. For a single core RTOS this could be
* zero. Locks are recursive.
*
* Note that the IRQ routines require a lock and
* will share the first one with the RTOS.
*/
#define RTOS_LOCK_COUNT 2
/**
* Remaps all calls to debug_printf() to rtos_printf().
* When this is on, files should not include both rtos_support.h
* and debug_print.h.
*/
#define RTOS_DEBUG_PRINTF_REMAP 1
#ifdef configENABLE_DEBUG_PRINTF
#if configENABLE_DEBUG_PRINTF
/* ensure that debug_printf is enabled */
#ifdef DEBUG_PRINT_ENABLE
#undef DEBUG_PRINT_ENABLE
#endif
#define DEBUG_PRINT_ENABLE 1
#ifndef configTASKS_DEBUG
#define configTASKS_DEBUG 0
#endif
#if configTASKS_DEBUG == 1
#define DEBUG_PRINT_ENABLE_FREERTOS_TASKS 1
#else
#define DEBUG_PRINT_DISABLE_FREERTOS_TASKS 1
#endif
#else /* configENABLE_DEBUG_PRINTF */
/* ensure that debug_printf is disabled */
#ifdef DEBUG_UNIT
#undef DEBUG_UNIT
#endif
#ifdef DEBUG_PRINT_ENABLE
#undef DEBUG_PRINT_ENABLE
#endif
#define DEBUG_PRINT_ENABLE 0
#endif /* configENABLE_DEBUG_PRINTF */
#endif
#endif /* RTOS_SUPPORT_RTOS_CONFIG_H_ */

10
queue.c
View file

@ -87,7 +87,7 @@ typedef struct SemaphoreData
* performed just because a higher priority task has been woken. */
#define queueYIELD_IF_USING_PREEMPTION()
#else
#define queueYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
#define queueYIELD_IF_USING_PREEMPTION() vTaskYieldWithinAPI()
#endif
/*
@ -961,7 +961,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
* is also a higher priority task in the pending ready list. */
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
}
else
@ -1426,7 +1426,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{
@ -1618,7 +1618,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{
@ -1796,7 +1796,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{

1455
tasks.c

File diff suppressed because it is too large Load diff

View file

@ -75,6 +75,7 @@
ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
TickType_t xTimerPeriodInTicks; /*<< How quickly and often the timer expires. */
void * pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
portTIMER_CALLBACK_ATTRIBUTE
TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
@ -100,6 +101,7 @@
typedef struct tmrCallbackParameters
{
portTIMER_CALLBACK_ATTRIBUTE
PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */
void * pvParameter1; /* << The value that will be used as the callback functions first parameter. */
uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */
@ -374,7 +376,7 @@
}
/*-----------------------------------------------------------*/
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
BaseType_t xTimerGenericCommandFromTask( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
@ -394,6 +396,8 @@
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer;
configASSERT( xCommandID < tmrFIRST_FROM_ISR_COMMAND );
if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
{
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
@ -405,7 +409,41 @@
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
}
}
traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xTimerGenericCommandFromISR( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait )
{
BaseType_t xReturn = pdFAIL;
DaemonTaskMessage_t xMessage;
configASSERT( xTimer );
/* Send a message to the timer service task to perform a particular action
* on a particular timer definition. */
if( xTimerQueue != NULL )
{
/* Send a command to the timer service task to start the xTimer timer. */
xMessage.xMessageID = xCommandID;
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer;
configASSERT( xCommandID >= tmrFIRST_FROM_ISR_COMMAND );
if( xCommandID >= tmrFIRST_FROM_ISR_COMMAND )
{
xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
}
@ -630,7 +668,7 @@
* block time to expire. If a command arrived between the
* critical section being exited and this yield then the yield
* will not cause the task to block. */
portYIELD_WITHIN_API();
vTaskYieldWithinAPI();
}
else
{