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

@ -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_ */