mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-09-05 13:53:50 -04:00
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:
parent
cafae476e4
commit
989bc332b2
509 changed files with 176869 additions and 174380 deletions
238
portable/XCC/XCORE200/port.c
Normal file
238
portable/XCC/XCORE200/port.c
Normal 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. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
26
portable/XCC/XCORE200/port.xc
Normal file
26
portable/XCC/XCORE200/port.xc
Normal 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();
|
||||
}
|
||||
}
|
160
portable/XCC/XCORE200/portasm.S
Normal file
160
portable/XCC/XCORE200/portasm.S
Normal 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
|
||||
|
218
portable/XCC/XCORE200/portmacro.h
Normal file
218
portable/XCC/XCORE200/portmacro.h
Normal 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 */
|
||||
|
95
portable/XCC/XCORE200/rtos_support_rtos_config.h
Normal file
95
portable/XCC/XCORE200/rtos_support_rtos_config.h
Normal 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
251
portable/XCC/XCOREAI/port.c
Normal 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. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
26
portable/XCC/XCOREAI/port.xc
Normal file
26
portable/XCC/XCOREAI/port.xc
Normal 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();
|
||||
}
|
||||
}
|
186
portable/XCC/XCOREAI/portasm.S
Normal file
186
portable/XCC/XCOREAI/portasm.S
Normal 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
|
||||
|
218
portable/XCC/XCOREAI/portmacro.h
Normal file
218
portable/XCC/XCOREAI/portmacro.h
Normal 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 */
|
||||
|
95
portable/XCC/XCOREAI/rtos_support_rtos_config.h
Normal file
95
portable/XCC/XCOREAI/rtos_support_rtos_config.h
Normal 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_ */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue