From a64ead12b07d861cb6494371fe9265e64d64c8f9 Mon Sep 17 00:00:00 2001 From: jzlv Date: Tue, 27 Apr 2021 12:36:18 +0800 Subject: [PATCH] [feat] add freertos port and demo --- components/freertos/include/FreeRTOSConfig.h | 103 ++++ .../gcc/risc-v/bl702/FreeRTOSConfig.h | 103 ++++ ...freertos_risc_v_chip_specific_extensions.h | 68 +++ .../freertos/portable/gcc/risc-v/bl702/port.c | 195 ++++++++ .../portable/gcc/risc-v/bl702/portASM.S | 440 ++++++++++++++++++ .../portable/gcc/risc-v/bl702/portmacro.h | 163 +++++++ .../freertos_semaphore/CMakeLists.txt | 6 + examples/freertos/freertos_semaphore/main.c | 186 ++++++++ 8 files changed, 1264 insertions(+) create mode 100644 components/freertos/include/FreeRTOSConfig.h create mode 100644 components/freertos/portable/gcc/risc-v/bl702/FreeRTOSConfig.h create mode 100644 components/freertos/portable/gcc/risc-v/bl702/freertos_risc_v_chip_specific_extensions.h create mode 100644 components/freertos/portable/gcc/risc-v/bl702/port.c create mode 100644 components/freertos/portable/gcc/risc-v/bl702/portASM.S create mode 100644 components/freertos/portable/gcc/risc-v/bl702/portmacro.h create mode 100644 examples/freertos/freertos_semaphore/CMakeLists.txt create mode 100644 examples/freertos/freertos_semaphore/main.c diff --git a/components/freertos/include/FreeRTOSConfig.h b/components/freertos/include/FreeRTOSConfig.h new file mode 100644 index 00000000..702e896b --- /dev/null +++ b/components/freertos/include/FreeRTOSConfig.h @@ -0,0 +1,103 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ +#define configSUPPORT_STATIC_ALLOCATION 1 +#define CLINT_CTRL_ADDR ( 0x02000000UL ) +#define configCLINT_BASE_ADDRESS CLINT_CTRL_ADDR +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 1 +#define configCPU_CLOCK_HZ ( 9000000UL ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES ( 7 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 160 ) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) 48 * 1024 ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 8 +#define configTIMER_TASK_STACK_DEPTH ( 160 ) + +/* Task priorities. Allow these to be overridden. */ +#ifndef uartPRIMARY_PRIORITY + #define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 ) +#endif + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled( void ); +#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled() + +#endif /* FREERTOS_CONFIG_H */ diff --git a/components/freertos/portable/gcc/risc-v/bl702/FreeRTOSConfig.h b/components/freertos/portable/gcc/risc-v/bl702/FreeRTOSConfig.h new file mode 100644 index 00000000..702e896b --- /dev/null +++ b/components/freertos/portable/gcc/risc-v/bl702/FreeRTOSConfig.h @@ -0,0 +1,103 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ +#define configSUPPORT_STATIC_ALLOCATION 1 +#define CLINT_CTRL_ADDR ( 0x02000000UL ) +#define configCLINT_BASE_ADDRESS CLINT_CTRL_ADDR +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 1 +#define configCPU_CLOCK_HZ ( 9000000UL ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES ( 7 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 160 ) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) 48 * 1024 ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 8 +#define configTIMER_TASK_STACK_DEPTH ( 160 ) + +/* Task priorities. Allow these to be overridden. */ +#ifndef uartPRIMARY_PRIORITY + #define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 ) +#endif + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled( void ); +#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled() + +#endif /* FREERTOS_CONFIG_H */ diff --git a/components/freertos/portable/gcc/risc-v/bl702/freertos_risc_v_chip_specific_extensions.h b/components/freertos/portable/gcc/risc-v/bl702/freertos_risc_v_chip_specific_extensions.h new file mode 100644 index 00000000..3333a7cf --- /dev/null +++ b/components/freertos/portable/gcc/risc-v/bl702/freertos_risc_v_chip_specific_extensions.h @@ -0,0 +1,68 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * The FreeRTOS kernel's RISC-V port is split between the the code that is + * common across all currently supported RISC-V chips (implementations of the + * RISC-V ISA), and code that tailors the port to a specific RISC-V chip: + * + * + FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S contains the code that + * is common to all currently supported RISC-V chips. There is only one + * portASM.S file because the same file is built for all RISC-V target chips. + * + * + Header files called freertos_risc_v_chip_specific_extensions.h contain the + * code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V + * chip. There are multiple freertos_risc_v_chip_specific_extensions.h files + * as there are multiple RISC-V chip implementations. + * + * !!!NOTE!!! + * TAKE CARE TO INCLUDE THE CORRECT freertos_risc_v_chip_specific_extensions.h + * HEADER FILE FOR THE CHIP IN USE. This is done using the assembler's (not the + * compiler's!) include path. For example, if the chip in use includes a core + * local interrupter (CLINT) and does not include any chip specific register + * extensions then add the path below to the assembler's include path: + * FreeRTOS\Source\portable\GCC\RISC-V-RV32\chip_specific_extensions\RV32I_CLINT_no_extensions + * + */ + + +#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__ +#define __FREERTOS_RISC_V_EXTENSIONS_H__ + +#define portasmHAS_CLINT 1 +#define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */ + +.macro portasmSAVE_ADDITIONAL_REGISTERS + /* No additional registers to save, so this macro does nothing. */ + .endm + +/* Restore the additional registers found on the Pulpino. */ +.macro portasmRESTORE_ADDITIONAL_REGISTERS + /* No additional registers to restore, so this macro does nothing. */ + .endm + +#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */ diff --git a/components/freertos/portable/gcc/risc-v/bl702/port.c b/components/freertos/portable/gcc/risc-v/bl702/port.c new file mode 100644 index 00000000..c65cb1d4 --- /dev/null +++ b/components/freertos/portable/gcc/risc-v/bl702/port.c @@ -0,0 +1,195 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the RISC-V RV32 port. + *----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portmacro.h" + +#ifndef configCLINT_BASE_ADDRESS + #warning configCLINT_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a Core Local Interrupter (CLINT) then set configCLINT_BASE_ADDRESS to the CLINT base address. Otherwise set configCLINT_BASE_ADDRESS to 0. +#endif + +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case it messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + +/* The stack used by interrupt service routines. Set configISR_STACK_SIZE_WORDS +to use a statically allocated array as the interrupt stack. Alternative leave +configISR_STACK_SIZE_WORDS undefined and update the linker script so that a +linker variable names __freertos_irq_stack_top has the same value as the top +of the stack used by main. Using the linker script method will repurpose the +stack that was used by main before the scheduler was started for use as the +interrupt stack after the scheduler has started. */ +#ifdef configISR_STACK_SIZE_WORDS + static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 }; + const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] ); +#else + extern const uint32_t __freertos_irq_stack_top[]; + const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top; +#endif + +/* + * Setup the timer to generate the tick interrupts. The implementation in this + * file is weak to allow application writers to change the timer used to + * generate the tick interrupt. + */ +void vPortSetupTimerInterrupt( void ) __attribute__(( weak )); + +/*-----------------------------------------------------------*/ + +/* Used to program the machine timer compare register. */ +uint64_t ullNextTime = 0ULL; +const uint64_t *pullNextTime = &ullNextTime; +const size_t uxTimerIncrementsForOneTick = ( size_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */ +volatile uint64_t * const pullMachineTimerCompareRegisterBase = ( volatile uint64_t * const ) ( configCLINT_BASE_ADDRESS + 0x4000 ); +volatile uint64_t * pullMachineTimerCompareRegister = 0; + +/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task +stack checking. A problem in the ISR stack will trigger an assert, not call the +stack overflow hook function (because the stack overflow hook is specific to a +task stack, not the ISR stack). */ +#if( configCHECK_FOR_STACK_OVERFLOW > 2 ) + #warning This path not tested, or even compiled yet. + /* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for + the task stacks, and so will legitimately appear in many positions within + the ISR stack. */ + #define portISR_STACK_FILL_BYTE 0xee + + static const uint8_t ucExpectedStackBytes[] = { + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \ + + #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) ) +#else + /* Define the function away. */ + #define portCHECK_ISR_STACK() +#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */ + +/*-----------------------------------------------------------*/ + +#if( configCLINT_BASE_ADDRESS != 0 ) + + void vPortSetupTimerInterrupt( void ) + { + uint32_t ulCurrentTimeHigh, ulCurrentTimeLow; + volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFFC ); + volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFF8 ); + volatile uint32_t ulHartId = 0; + + __asm volatile( "csrr %0, mhartid" : "=r"( ulHartId ) ); + pullMachineTimerCompareRegister = &( pullMachineTimerCompareRegisterBase[ ulHartId ] ); + + do + { + ulCurrentTimeHigh = *pulTimeHigh; + ulCurrentTimeLow = *pulTimeLow; + } while( ulCurrentTimeHigh != *pulTimeHigh ); + + ullNextTime = ( uint64_t ) ulCurrentTimeHigh; + ullNextTime <<= 32ULL; + ullNextTime |= ( uint64_t ) ulCurrentTimeLow; + ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; + *pullMachineTimerCompareRegister = ullNextTime; + + /* Prepare the time to use after the next tick interrupt. */ + ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; + } + +#endif /* ( configCLINT_BASE_ADDRESS != 0 ) */ +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler( void ) +{ +extern void xPortStartFirstTask( void ); + + #if( configASSERT_DEFINED == 1 ) + { + volatile uint32_t mtvec = 0; + + /* Check the least significant two bits of mtvec are 00 - indicating + single vector mode. */ + __asm volatile( "csrr %0, mtvec" : "=r"( mtvec ) ); + //configASSERT( ( mtvec & 0x03UL ) == 0 ); + + /* Check alignment of the interrupt stack - which is the same as the + stack that was being used by main() prior to the scheduler being + started. */ + configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 ); + } + #endif /* configASSERT_DEFINED */ + + /* If there is a CLINT then it is ok to use the default implementation + in this file, otherwise vPortSetupTimerInterrupt() must be implemented to + configure whichever clock is to be used to generate the tick interrupt. */ + vPortSetupTimerInterrupt(); + + #if( configCLINT_BASE_ADDRESS != 0 ) + { + /* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11 + for external interrupt. _RB_ What happens here when mtime is not present as + with pulpino? */ + __asm volatile( "csrs mie, %0" :: "r"(0x880) ); + } + #else + { + /* Enable external interrupts. */ + __asm volatile( "csrs mie, %0" :: "r"(0x800) ); + } + #endif /* configCLINT_BASE_ADDRESS */ + + *(uint8_t *)(0x02800400 + 7) = 1; + xPortStartFirstTask(); + + /* Should not get here as after calling xPortStartFirstTask() only tasks + should be executing. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented. */ + for( ;; ); +} + + + + + diff --git a/components/freertos/portable/gcc/risc-v/bl702/portASM.S b/components/freertos/portable/gcc/risc-v/bl702/portASM.S new file mode 100644 index 00000000..432f7db2 --- /dev/null +++ b/components/freertos/portable/gcc/risc-v/bl702/portASM.S @@ -0,0 +1,440 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * The FreeRTOS kernel's RISC-V port is split between the the code that is + * common across all currently supported RISC-V chips (implementations of the + * RISC-V ISA), and code which tailors the port to a specific RISC-V chip: + * + * + The code that is common to all RISC-V chips is implemented in + * FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S. There is only one + * portASM.S file because the same file is used no matter which RISC-V chip is + * in use. + * + * + The code that tailors the kernel's RISC-V port to a specific RISC-V + * chip is implemented in freertos_risc_v_chip_specific_extensions.h. There + * is one freertos_risc_v_chip_specific_extensions.h that can be used with any + * RISC-V chip that both includes a standard CLINT and does not add to the + * base set of RISC-V registers. There are additional + * freertos_risc_v_chip_specific_extensions.h files for RISC-V implementations + * that do not include a standard CLINT or do add to the base set of RISC-V + * registers. + * + * CARE MUST BE TAKEN TO INCLDUE THE CORRECT + * freertos_risc_v_chip_specific_extensions.h HEADER FILE FOR THE CHIP + * IN USE. To include the correct freertos_risc_v_chip_specific_extensions.h + * header file ensure the path to the correct header file is in the assembler's + * include path. + * + * This freertos_risc_v_chip_specific_extensions.h is for use on RISC-V chips + * that include a standard CLINT and do not add to the base set of RISC-V + * registers. + * + */ +#if __riscv_xlen == 64 + #define portWORD_SIZE 8 + #define store_x sd + #define load_x ld +#elif __riscv_xlen == 32 + #define store_x sw + #define load_x lw + #define portWORD_SIZE 4 +#else + #error Assembler did not define __riscv_xlen +#endif + +#include "freertos_risc_v_chip_specific_extensions.h" + +/* Check the freertos_risc_v_chip_specific_extensions.h and/or command line +definitions. */ +#ifndef portasmHAS_CLINT + #error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_CLINT to either 1 (CLINT present) or 0 (clint not present). +#endif + +#ifndef portasmHANDLE_INTERRUPT + #error portasmHANDLE_INTERRUPT must be defined to the function to be called to handle external/peripheral interrupts. portasmHANDLE_INTERRUPT can be defined on the assmbler command line or in the appropriate freertos_risc_v_chip_specific_extensions.h header file. +#endif + +/* Only the standard core registers are stored by default. Any additional +registers must be saved by the portasmSAVE_ADDITIONAL_REGISTERS and +portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip +specific version of freertos_risc_v_chip_specific_extensions.h. See the notes +at the top of this file. */ +#define portCONTEXT_SIZE ( 30 * portWORD_SIZE ) + +.global xPortStartFirstTask +.global freertos_risc_v_trap_handler +.global pxPortInitialiseStack +.extern pxCurrentTCB +.extern ulPortTrapHandler +.extern vTaskSwitchContext +.extern xTaskIncrementTick +.extern Timer_IRQHandler +.extern pullMachineTimerCompareRegister +.extern pullNextTime +.extern uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */ +.extern xISRStackTop +.extern portasmHANDLE_INTERRUPT +.extern Trap_Handler + +/*-----------------------------------------------------------*/ + +.align 8 +.func +freertos_risc_v_trap_handler: + addi sp, sp, -portCONTEXT_SIZE + store_x x1, 1 * portWORD_SIZE( sp ) + store_x x5, 2 * portWORD_SIZE( sp ) + store_x x6, 3 * portWORD_SIZE( sp ) + store_x x7, 4 * portWORD_SIZE( sp ) + store_x x8, 5 * portWORD_SIZE( sp ) + store_x x9, 6 * portWORD_SIZE( sp ) + store_x x10, 7 * portWORD_SIZE( sp ) + store_x x11, 8 * portWORD_SIZE( sp ) + store_x x12, 9 * portWORD_SIZE( sp ) + store_x x13, 10 * portWORD_SIZE( sp ) + store_x x14, 11 * portWORD_SIZE( sp ) + store_x x15, 12 * portWORD_SIZE( sp ) + store_x x16, 13 * portWORD_SIZE( sp ) + store_x x17, 14 * portWORD_SIZE( sp ) + store_x x18, 15 * portWORD_SIZE( sp ) + store_x x19, 16 * portWORD_SIZE( sp ) + store_x x20, 17 * portWORD_SIZE( sp ) + store_x x21, 18 * portWORD_SIZE( sp ) + store_x x22, 19 * portWORD_SIZE( sp ) + store_x x23, 20 * portWORD_SIZE( sp ) + store_x x24, 21 * portWORD_SIZE( sp ) + store_x x25, 22 * portWORD_SIZE( sp ) + store_x x26, 23 * portWORD_SIZE( sp ) + store_x x27, 24 * portWORD_SIZE( sp ) + store_x x28, 25 * portWORD_SIZE( sp ) + store_x x29, 26 * portWORD_SIZE( sp ) + store_x x30, 27 * portWORD_SIZE( sp ) + store_x x31, 28 * portWORD_SIZE( sp ) + + csrr t0, mstatus /* Required for MPIE bit. */ + store_x t0, 29 * portWORD_SIZE( sp ) + + portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */ + + load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */ + store_x sp, 0( t0 ) /* Write sp to first TCB member. */ + + csrr a0, mcause + csrr a1, mepc + + li t0, 0x80000FFF + and a0, a0, t0 +test_if_asynchronous: + srli a2, a0, __riscv_xlen - 1 /* MSB of mcause is 1 if handing an asynchronous interrupt - shift to LSB to clear other bits. */ + beq a2, x0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */ + store_x a1, 0( sp ) /* Asynch so save unmodified exception return address. */ + +handle_asynchronous: + +#if( portasmHAS_CLINT != 0 ) + + test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */ + + addi t0, x0, 1 + + slli t0, t0, __riscv_xlen - 1 /* LSB is already set, shift into MSB. Shift 31 on 32-bit or 63 on 64-bit cores. */ + addi t1, t0, 7 /* 0x8000[]0007 == machine timer interrupt. */ + bne a0, t1, test_if_external_interrupt + + load_x t0, pullMachineTimerCompareRegister /* Load address of compare register into t0. */ + load_x t1, pullNextTime /* Load the address of ullNextTime into t1. */ + + #if( __riscv_xlen == 32 ) + + /* Update the 64-bit mtimer compare match value in two 32-bit writes. */ + li t4, -1 + lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */ + lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */ + sw t4, 0(t0) /* Low word no smaller than old value to start with - will be overwritten below. */ + sw t3, 4(t0) /* Store high word of ullNextTime into compare register. No smaller than new value. */ + sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */ + lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */ + add t4, t0, t2 /* Add the low word of ullNextTime to the timer increments for one tick (assumes timer increment for one tick fits in 32-bits). */ + sltu t5, t4, t2 /* See if the sum of low words overflowed (what about the zero case?). */ + add t6, t3, t5 /* Add overflow to high word of ullNextTime. */ + sw t4, 0(t1) /* Store new low word of ullNextTime. */ + sw t6, 4(t1) /* Store new high word of ullNextTime. */ + + #endif /* __riscv_xlen == 32 */ + + #if( __riscv_xlen == 64 ) + + /* Update the 64-bit mtimer compare match value. */ + ld t2, 0(t1) /* Load ullNextTime into t2. */ + sd t2, 0(t0) /* Store ullNextTime into compare register. */ + ld t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */ + add t4, t0, t2 /* Add ullNextTime to the timer increments for one tick. */ + sd t4, 0(t1) /* Store ullNextTime. */ + + #endif /* __riscv_xlen == 64 */ + + load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ + jal xTaskIncrementTick + beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */ + jal vTaskSwitchContext + j processed_source + + test_if_external_interrupt: /* If there is a CLINT and the mtimer interrupt is not pending then check to see if an external interrupt is pending. */ + //addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */ + //bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */ + +#endif /* portasmHAS_CLINT */ + + load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ + jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */ + j processed_source + +handle_synchronous: + addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */ + store_x a1, 0( sp ) /* Save updated exception return address. */ + +test_if_environment_call: + li t0, 11 /* 11 == environment call. */ + bne a0, t0, is_exception /* Not an M environment call, so some other exception. */ + load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ + jal vTaskSwitchContext + j processed_source + +is_exception: + csrr t0, mcause /* For viewing in the debugger only. */ + csrr t1, mepc /* For viewing in the debugger only */ + csrr t2, mstatus + load_x sp, xISRStackTop + jal Trap_Handler + j is_exception + +as_yet_unhandled: + csrr t0, mcause /* For viewing in the debugger only. */ + j as_yet_unhandled + +processed_source: + load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */ + load_x sp, 0( t1 ) /* Read sp from first TCB member. */ + + /* Load mret with the address of the next instruction in the task to run next. */ + load_x t0, 0( sp ) + csrw mepc, t0 + + portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */ + + /* Load mstatus with the interrupt enable bits used by the task. */ + load_x t0, 29 * portWORD_SIZE( sp ) + csrw mstatus, t0 /* Required for MPIE bit. */ + + load_x x1, 1 * portWORD_SIZE( sp ) + load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */ + load_x x6, 3 * portWORD_SIZE( sp ) /* t1 */ + load_x x7, 4 * portWORD_SIZE( sp ) /* t2 */ + load_x x8, 5 * portWORD_SIZE( sp ) /* s0/fp */ + load_x x9, 6 * portWORD_SIZE( sp ) /* s1 */ + load_x x10, 7 * portWORD_SIZE( sp ) /* a0 */ + load_x x11, 8 * portWORD_SIZE( sp ) /* a1 */ + load_x x12, 9 * portWORD_SIZE( sp ) /* a2 */ + load_x x13, 10 * portWORD_SIZE( sp ) /* a3 */ + load_x x14, 11 * portWORD_SIZE( sp ) /* a4 */ + load_x x15, 12 * portWORD_SIZE( sp ) /* a5 */ + load_x x16, 13 * portWORD_SIZE( sp ) /* a6 */ + load_x x17, 14 * portWORD_SIZE( sp ) /* a7 */ + load_x x18, 15 * portWORD_SIZE( sp ) /* s2 */ + load_x x19, 16 * portWORD_SIZE( sp ) /* s3 */ + load_x x20, 17 * portWORD_SIZE( sp ) /* s4 */ + load_x x21, 18 * portWORD_SIZE( sp ) /* s5 */ + load_x x22, 19 * portWORD_SIZE( sp ) /* s6 */ + load_x x23, 20 * portWORD_SIZE( sp ) /* s7 */ + load_x x24, 21 * portWORD_SIZE( sp ) /* s8 */ + load_x x25, 22 * portWORD_SIZE( sp ) /* s9 */ + load_x x26, 23 * portWORD_SIZE( sp ) /* s10 */ + load_x x27, 24 * portWORD_SIZE( sp ) /* s11 */ + load_x x28, 25 * portWORD_SIZE( sp ) /* t3 */ + load_x x29, 26 * portWORD_SIZE( sp ) /* t4 */ + load_x x30, 27 * portWORD_SIZE( sp ) /* t5 */ + load_x x31, 28 * portWORD_SIZE( sp ) /* t6 */ + addi sp, sp, portCONTEXT_SIZE + + mret + .endfunc +/*-----------------------------------------------------------*/ + +.align 8 +.func +xPortStartFirstTask: + +#if( portasmHAS_CLINT != 0 ) + /* If there is a clint then interrupts can branch directly to the FreeRTOS + trap handler. Otherwise the interrupt controller will need to be configured + outside of this file. */ + la t0, freertos_risc_v_trap_handler + ori t0, t0, 2 + csrw mtvec, t0 +#endif /* portasmHAS_CLILNT */ + + load_x sp, pxCurrentTCB /* Load pxCurrentTCB. */ + load_x sp, 0( sp ) /* Read sp from first TCB member. */ + + load_x x1, 0( sp ) /* Note for starting the scheduler the exception return address is used as the function return address. */ + + portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */ + + load_x t0, 29 * portWORD_SIZE( sp ) /* mstatus */ + addi t0, t0, 0x08 /* Set MIE bit so the first task starts with interrupts enabled - required as returns with ret not eret. */ + csrrw x0, mstatus, t0 /* Interrupts enabled from here! */ + + load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */ + load_x x6, 3 * portWORD_SIZE( sp ) /* t1 */ + load_x x7, 4 * portWORD_SIZE( sp ) /* t2 */ + load_x x8, 5 * portWORD_SIZE( sp ) /* s0/fp */ + load_x x9, 6 * portWORD_SIZE( sp ) /* s1 */ + load_x x10, 7 * portWORD_SIZE( sp ) /* a0 */ + load_x x11, 8 * portWORD_SIZE( sp ) /* a1 */ + load_x x12, 9 * portWORD_SIZE( sp ) /* a2 */ + load_x x13, 10 * portWORD_SIZE( sp ) /* a3 */ + load_x x14, 11 * portWORD_SIZE( sp ) /* a4 */ + load_x x15, 12 * portWORD_SIZE( sp ) /* a5 */ + load_x x16, 13 * portWORD_SIZE( sp ) /* a6 */ + load_x x17, 14 * portWORD_SIZE( sp ) /* a7 */ + load_x x18, 15 * portWORD_SIZE( sp ) /* s2 */ + load_x x19, 16 * portWORD_SIZE( sp ) /* s3 */ + load_x x20, 17 * portWORD_SIZE( sp ) /* s4 */ + load_x x21, 18 * portWORD_SIZE( sp ) /* s5 */ + load_x x22, 19 * portWORD_SIZE( sp ) /* s6 */ + load_x x23, 20 * portWORD_SIZE( sp ) /* s7 */ + load_x x24, 21 * portWORD_SIZE( sp ) /* s8 */ + load_x x25, 22 * portWORD_SIZE( sp ) /* s9 */ + load_x x26, 23 * portWORD_SIZE( sp ) /* s10 */ + load_x x27, 24 * portWORD_SIZE( sp ) /* s11 */ + load_x x28, 25 * portWORD_SIZE( sp ) /* t3 */ + load_x x29, 26 * portWORD_SIZE( sp ) /* t4 */ + load_x x30, 27 * portWORD_SIZE( sp ) /* t5 */ + load_x x31, 28 * portWORD_SIZE( sp ) /* t6 */ + addi sp, sp, portCONTEXT_SIZE + ret + .endfunc +/*-----------------------------------------------------------*/ + +/* + * Unlike other ports pxPortInitialiseStack() is written in assembly code as it + * needs access to the portasmADDITIONAL_CONTEXT_SIZE constant. The prototype + * for the function is as per the other ports: + * StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ); + * + * As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in + * a1, and pvParameters in a2. The new top of stack is passed out in a0. + * + * RISC-V maps registers to ABI names as follows (X1 to X31 integer registers + * for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed). + * + * Register ABI Name Description Saver + * x0 zero Hard-wired zero - + * x1 ra Return address Caller + * x2 sp Stack pointer Callee + * x3 gp Global pointer - + * x4 tp Thread pointer - + * x5-7 t0-2 Temporaries Caller + * x8 s0/fp Saved register/Frame pointer Callee + * x9 s1 Saved register Callee + * x10-11 a0-1 Function Arguments/return values Caller + * x12-17 a2-7 Function arguments Caller + * x18-27 s2-11 Saved registers Callee + * x28-31 t3-6 Temporaries Caller + * + * The RISC-V context is saved t FreeRTOS tasks in the following stack frame, + * where the global and thread pointers are currently assumed to be constant so + * are not saved: + * + * mstatus + * x31 + * x30 + * x29 + * x28 + * x27 + * x26 + * x25 + * x24 + * x23 + * x22 + * x21 + * x20 + * x19 + * x18 + * x17 + * x16 + * x15 + * x14 + * x13 + * x12 + * x11 + * pvParameters + * x9 + * x8 + * x7 + * x6 + * x5 + * portTASK_RETURN_ADDRESS + * [chip specific registers go here] + * pxCode + */ +.align 8 +.func +pxPortInitialiseStack: + + csrr t0, mstatus /* Obtain current mstatus value. */ + +#if 1 + li t1, 0x1880 + or t0, t0, t1 /* MPP = 0b11, MPIE = 1 */ + andi t0, t0, 0xFFFFFFF7 /* !!! MIE = 0 !!! */ +#else + addi t1, x0, 0x188 /* Generate the value 0x1888, which are the MIE, MPIE and privilege bits to set in mstatus. */ + slli t1, t1, 4 + or t0, t0, t1 /* Set MPIE and MPP bits in mstatus value. */ +#endif + + addi a0, a0, -portWORD_SIZE + store_x t0, 0(a0) /* mstatus onto the stack. */ + addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x11-x31. */ + store_x a2, 0(a0) /* Task parameters (pvParameters parameter) goes into register X10/a0 on the stack. */ + addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9. */ + store_x x0, 0(a0) /* Return address onto the stack, could be portTASK_RETURN_ADDRESS */ + addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */ +chip_specific_stack_frame: /* First add any chip specific registers to the stack frame being created. */ + beq t0, x0, 1f /* No more chip specific registers to save. */ + addi a0, a0, -portWORD_SIZE /* Make space for chip specific register. */ + store_x x0, 0(a0) /* Give the chip specific register an initial value of zero. */ + addi t0, t0, -1 /* Decrement the count of chip specific registers remaining. */ + j chip_specific_stack_frame /* Until no more chip specific registers. */ +1: + addi a0, a0, -portWORD_SIZE + store_x a1, 0(a0) /* mret value (pxCode parameter) onto the stack. */ + ret + .endfunc +/*-----------------------------------------------------------*/ diff --git a/components/freertos/portable/gcc/risc-v/bl702/portmacro.h b/components/freertos/portable/gcc/risc-v/bl702/portmacro.h new file mode 100644 index 00000000..d3ba1217 --- /dev/null +++ b/components/freertos/portable/gcc/risc-v/bl702/portmacro.h @@ -0,0 +1,163 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#if __riscv_xlen == 64 + #define portSTACK_TYPE uint64_t + #define portBASE_TYPE int64_t + #define portUBASE_TYPE uint64_t + #define portMAX_DELAY ( TickType_t ) 0xffffffffffffffffUL + #define portPOINTER_SIZE_TYPE uint64_t +#elif __riscv_xlen == 32 + #define portSTACK_TYPE uint32_t + #define portBASE_TYPE int /* int32_t */ + #define portUBASE_TYPE uint32_t + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL + #if __riscv_float_abi_single + /* better to use float replace double here, + * so that it will generates floating point instructions + */ + #define portDOUBLE float /* double */ + #else + #define portDOUBLE double + #endif +#else + #error Assembler did not define __riscv_xlen +#endif + + +typedef portSTACK_TYPE StackType_t; +typedef portBASE_TYPE BaseType_t; +typedef portUBASE_TYPE UBaseType_t; +typedef portUBASE_TYPE TickType_t; + +/* 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 +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#ifdef __riscv64 + #error This is the RV32 port that has not yet been adapted for 64. + #define portBYTE_ALIGNMENT 16 +#else + #define portBYTE_ALIGNMENT 16 +#endif +/*-----------------------------------------------------------*/ + + +/* Scheduler utilities. */ +extern void vTaskSwitchContext( void ); +#define portYIELD() __asm volatile( "ecall" ); +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vTaskSwitchContext() +#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) +/*-----------------------------------------------------------*/ + + +/* Critical section management. */ +#define portCRITICAL_NESTING_IN_TCB 1 +extern void vTaskEnterCritical( void ); +extern void vTaskExitCritical( void ); + +#define portSET_INTERRUPT_MASK_FROM_ISR() 0 +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#define portDISABLE_INTERRUPTS() __asm volatile( "csrc mstatus, 8" ) +#define portENABLE_INTERRUPTS() __asm volatile( "csrs mstatus, 8" ) +#define portENTER_CRITICAL() vTaskEnterCritical() +#define portEXIT_CRITICAL() vTaskExitCritical() + +/*-----------------------------------------------------------*/ + +/* Architecture specific optimisations. */ +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 ) + + /* Check the configuration. */ + #if( configMAX_PRIORITIES > 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* 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 - __builtin_clz( uxReadyPriorities ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + +/*-----------------------------------------------------------*/ + +/* 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 ) + +/*-----------------------------------------------------------*/ + +#define portNOP() __asm volatile ( " nop " ) + +#define portINLINE __inline + +#ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__(( always_inline)) +#endif + +#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ + diff --git a/examples/freertos/freertos_semaphore/CMakeLists.txt b/examples/freertos/freertos_semaphore/CMakeLists.txt new file mode 100644 index 00000000..5e9054d4 --- /dev/null +++ b/examples/freertos/freertos_semaphore/CMakeLists.txt @@ -0,0 +1,6 @@ +set(BSP_COMMON_DIR ${CMAKE_SOURCE_DIR}/bsp/bsp_common) +set(TARGET_REQUIRED_LIBS freertos) +set(mains main.c) +generate_bin() + + diff --git a/examples/freertos/freertos_semaphore/main.c b/examples/freertos/freertos_semaphore/main.c new file mode 100644 index 00000000..ffad5c54 --- /dev/null +++ b/examples/freertos/freertos_semaphore/main.c @@ -0,0 +1,186 @@ +/** + * @file main.c + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ +#include "hal_uart.h" +#include +#include "semphr.h" + +static uint8_t freertos_heap[4096]; + +static HeapRegion_t xHeapRegions[] = +{ + { (uint8_t *)freertos_heap, 0}, + { NULL, 0 }, /* Terminates the array. */ + { NULL, 0 } /* Terminates the array. */ +}; +static StackType_t consumer_stack[512]; +static StaticTask_t consumer_handle; +static StackType_t producer_stack[512]; +static StaticTask_t producer_handle; + +uint8_t sharedBuf[16]; +SemaphoreHandle_t sem_empty = NULL; +SemaphoreHandle_t sem_full = NULL; +SemaphoreHandle_t mtx_lock = NULL; + +void vAssertCalled(void) +{ + MSG("vAssertCalled\r\n"); + while( 1 ); +} + +void vApplicationTickHook(void) +{ + //MSG("vApplicationTickHook\r\n"); +} + +void vApplicationStackOverflowHook(void) +{ + MSG("vApplicationStackOverflowHook\r\n"); + while( 1 ); +} + +void vApplicationMallocFailedHook(void) +{ + MSG("vApplicationMallocFailedHook\r\n"); + while( 1 ); +} +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + +static void consumer_task(void *pvParameters) +{ + MSG("Consumer task enter \r\n"); + vTaskDelay(1000); + MSG("Consumer task start \r\n"); + MSG("begin to loop %s\n", __FILE__); + + while(1){ + if( xSemaphoreTake( sem_full, portMAX_DELAY ) == pdTRUE ){ + xSemaphoreTake(mtx_lock,portMAX_DELAY); + MSG("Consumer get:%s\r\n",sharedBuf); + xSemaphoreGive(mtx_lock); + xSemaphoreGive(sem_empty); + }else{ + MSG("Take sem_full fail\r\n"); + } + } + + vTaskDelete(NULL); +} + +static void producer_task(void *pvParameters) +{ + uint8_t buf = 100; + + MSG("Producer task enter \r\n"); + vTaskDelay(1000); + MSG("Producer task start \r\n"); + + while(1){ + if( xSemaphoreTake(sem_empty, portMAX_DELAY) == pdTRUE ){ + xSemaphoreTake(mtx_lock,portMAX_DELAY); + buf++; + sprintf((char *)sharedBuf,"%d",buf); + MSG("Producer generates:%s\r\n",sharedBuf); + xSemaphoreGive(mtx_lock); + xSemaphoreGive(sem_full); + vTaskDelay(buf); + }else{ + MSG("Take sem_empty fail\r\n"); + } + } + + vTaskDelete(NULL); +} + + +int main(void) +{ + bflb_platform_init(0); + + xHeapRegions[0].xSizeInBytes=4096; + vPortDefineHeapRegions(xHeapRegions); + + /* Create semaphore */ + vSemaphoreCreateBinary(sem_empty); + vSemaphoreCreateBinary(sem_full); + vSemaphoreCreateBinary(mtx_lock); + if(sem_empty==NULL||sem_full==NULL||mtx_lock==NULL){ + MSG("Create sem fail\r\n"); + BL_CASE_FAIL; + } + + MSG("[OS] Starting consumer task...\r\n"); + xTaskCreateStatic(consumer_task, (char*)"consumer_task", sizeof(consumer_stack)/4, NULL, 16, consumer_stack, &consumer_handle); + MSG("[OS] Starting producer task...\r\n"); + xTaskCreateStatic(producer_task, (char*)"producer_task", sizeof(producer_stack)/4, NULL, 15, producer_stack, &producer_handle); + + vTaskStartScheduler(); + + while (1) + { + + } +}