diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile index 9070114b..d3068511 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile @@ -99,6 +99,11 @@ ifeq ($(WATERSV2_DEMO), 1) CFLAGS := -DmainCREATE_WATERS_DEMO=1 else +ifeq ($(MAN_DEMO), 1) + SOURCE_FILES += main_manual.c + + CFLAGS := -DmainCREATE_WATERS_DEMO=1 +else ifeq ($(BRANCHLESS_DEMO), 1) SOURCE_FILES += main_micro_branchless.c @@ -129,6 +134,7 @@ endif endif endif endif +endif ifeq ($(INTERRUPT_ACTIVATION), 1) CFLAGS += -D INTERRUPT_ACTIVATION=1 diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_manual.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_manual.c new file mode 100644 index 00000000..47567dd7 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_manual.c @@ -0,0 +1,524 @@ +/* + * FreeRTOS V202111.00 + * Copyright (C) 2020 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#include +#include +#include +#include +/* +TMR Demo with retry +prvSamplerTask will read 4 Bytes of Input into a buffer, unlocks xMutexInput +prvReplicateA and prvReplicateB wait on xMutexInput to average the Inputs and +sum up all numbers up to the Input. +ReplicateA will fail if mod 11 = 0, but only once +ReplicateB will fail if mod 12 = 0 +ReplicateC also exists and will never fail, does not run by default +Each Replicate outputs to it's own queue +prvVoterTask will wait on ReplicateA&B +If they disagree ReplicateC will be started by mutex. +If all the Replicates disagree now the sampler will be engaged once more +*/ + +#define GLOBAL_WCET_MULT 16 // Multiplier to increase all waiting periods to make the schedule more tight an force preemptions +#include "arbitrary_loads.c" + +__attribute__((noinline)) static void trigger_Qemu_break( void ) +{ + puts("Trigger"); + while (1) { + } +} +// if this macro is set, the code will be modified to produce the worst case +// #define DEBUG_WCET(A) {A} + +// #define WCET_END(A) +#define WCET_END(A) {A} + +#ifdef DEBUG_WCET + #define DEBUG_VAL(X,D) (D) + // #define WCET_CLAMP(X, LB, UB, LABEL) PRINT_TIME(UB,LABEL) + #define WCET_CLAMP(X, LB, UB, LABEL) PRINT_TIME(CLAMP(X,LB,UB),LABEL) +#else + #define DEBUG_VAL(X,D) (X) + #define WCET_CLAMP(X, LB, UB, LABEL) PRINT_TIME(CLAMP(X,LB,UB),LABEL) + #define DEBUG_WCET(A) +#endif + +// Begin Input Stuff +volatile unsigned char FUZZ_INPUT[4096] = {0xa,0xb,0xc,0xd,0xe,0xf}; +volatile uint32_t FUZZ_LENGTH = 4096; +volatile uint32_t FUZZ_POINTER = 0; +// Read the Byte of Input, if the Input is exausted trigger the breakpoint instead +static unsigned char fuzz_char_next(void) { + // printf("Get next Input from %lx \n",FUZZ_INPUT); + if (1 || FUZZ_POINTER < FUZZ_LENGTH) { + FUZZ_POINTER++; + // printf("Input no. %d %x\n",FUZZ_POINTER-1,FUZZ_INPUT[FUZZ_POINTER-1]); + return FUZZ_INPUT[FUZZ_POINTER-1]; + } else { + // puts("End of Input"); + // Exausted inputs early + trigger_Qemu_break(); + } +} +static uint16_t fuzz_short_next(void) { + unsigned char field[2]; + field[0]=fuzz_char_next(); + field[1]=fuzz_char_next(); + uint16_t* sf = (uint16_t*) field; + return *sf; +} +static uint32_t fuzz_long_next(void) { + unsigned char field[4]; + field[0]=fuzz_char_next(); + field[1]=fuzz_char_next(); + field[2]=fuzz_char_next(); + field[3]=fuzz_char_next(); + uint32_t* sf = (uint32_t*) field; + return *sf; +} +// End Input Stuff +static void prvC1T1( void * pvParameters ); +static void prvC1T2( void * pvParameters ); +static void prvC1T3( void * pvParameters ); +static void prvC1T4( void * pvParameters ); + +static void prvC2T1( void * pvParameters ); +static void prvC2T2( void * pvParameters ); +static void prvC2T3( void * pvParameters ); + +static void prvC3T1( void * pvParameters ); +static void prvC3T2( void * pvParameters ); +static void prvC3T3( void * pvParameters ); + +// Priorities using rate-monotonic scheduling +// ties are decided favoring short wcets +// Chain1: 579 -> 1009 -> 1129 -> 416 +// 10ms 10ms 10ms 10ms +// Chain2: 31 -> 78 -> 400 +// 100ms 10ms 2ms +// Chain3: 397 -> 90 -> 1107 +// spor 2ms 50ms +// cross-chain effect ideas: + +// RM + sort by chains +#define mainTASK_C1T1_PRIO ( tskIDLE_PRIORITY + 5 ) +#define mainTASK_C1T2_PRIO ( tskIDLE_PRIORITY + 5 ) +#define mainTASK_C1T3_PRIO ( tskIDLE_PRIORITY + 5 ) +#define mainTASK_C1T4_PRIO ( tskIDLE_PRIORITY + 5 ) + +#define mainTASK_C2T1_PRIO ( tskIDLE_PRIORITY + 1 ) +#define mainTASK_C2T2_PRIO ( tskIDLE_PRIORITY + 5 ) +#define mainTASK_C2T3_PRIO ( tskIDLE_PRIORITY + 9 ) + +#define mainTASK_C3T1_PRIO ( tskIDLE_PRIORITY + 10 ) +#define mainTASK_C3T2_PRIO ( tskIDLE_PRIORITY + 8 ) +#define mainTASK_C3T3_PRIO ( tskIDLE_PRIORITY + 2 ) + +// RM with pref for short +// #define mainTASK_C2T1_PRIO ( tskIDLE_PRIORITY + 1 ) +// #define mainTASK_C2T2_PRIO ( tskIDLE_PRIORITY + 5 ) +// #define mainTASK_C3T2_PRIO ( tskIDLE_PRIORITY + 8 ) +// #define mainTASK_C3T1_PRIO ( tskIDLE_PRIORITY + 10 ) +// #define mainTASK_C2T3_PRIO ( tskIDLE_PRIORITY + 9 ) +// #define mainTASK_C1T4_PRIO ( tskIDLE_PRIORITY + 4 ) +// #define mainTASK_C1T1_PRIO ( tskIDLE_PRIORITY + 7 ) +// #define mainTASK_C1T2_PRIO ( tskIDLE_PRIORITY + 6 ) +// #define mainTASK_C3T3_PRIO ( tskIDLE_PRIORITY + 2 ) +// #define mainTASK_C1T3_PRIO ( tskIDLE_PRIORITY + 3 ) + +// Same Prio +// #define mainTASK_C2T1_PRIO ( tskIDLE_PRIORITY + 1 ) +// #define mainTASK_C2T2_PRIO ( tskIDLE_PRIORITY + 7 ) +// #define mainTASK_C3T2_PRIO ( tskIDLE_PRIORITY + 8 ) +// #define mainTASK_C3T1_PRIO ( tskIDLE_PRIORITY + 10 ) +// #define mainTASK_C2T3_PRIO ( tskIDLE_PRIORITY + 9 ) +// #define mainTASK_C1T4_PRIO ( tskIDLE_PRIORITY + 7 ) +// #define mainTASK_C1T1_PRIO ( tskIDLE_PRIORITY + 7 ) +// #define mainTASK_C1T2_PRIO ( tskIDLE_PRIORITY + 7 ) +// #define mainTASK_C3T3_PRIO ( tskIDLE_PRIORITY + 2 ) +// #define mainTASK_C1T3_PRIO ( tskIDLE_PRIORITY + 7 ) + +#define TASK_C1T1_MESSAGE "11" +#define TASK_C1T2_MESSAGE "12" +#define TASK_C1T3_MESSAGE "13" +#define TASK_C1T4_MESSAGE "14" +#define TASK_C2T1_MESSAGE "21" +#define TASK_C2T2_MESSAGE "22" +#define TASK_C2T3_MESSAGE "23" +#define TASK_C3T1_MESSAGE "31" +#define TASK_C3T2_MESSAGE "32" +#define TASK_C3T3_MESSAGE "33" + +// Handles for direct messages +static TaskHandle_t xC2T1 = NULL; +static TaskHandle_t xC2T2 = NULL; +static TaskHandle_t xC3T2 = NULL; +static TaskHandle_t xC3T1 = NULL; +static TaskHandle_t xC2T3 = NULL; +static TaskHandle_t xC1T4 = NULL; +static TaskHandle_t xC1T1 = NULL; +static TaskHandle_t xC1T2 = NULL; +static TaskHandle_t xC3T3 = NULL; +static TaskHandle_t xC1T3 = NULL; + +void main_waters( void ) +{ + // puts("Main function"); + /* Start the two tasks as described in the comments at the top of this + * file. */ + xTaskCreate( prvC2T1, /* The function that implements the task. */ + "2-1", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainTASK_C2T1_PRIO, /* The priority assigned to the task. */ + &xC2T1 ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvC2T2, /* The function that implements the task. */ + "2-2", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainTASK_C2T2_PRIO, /* The priority assigned to the task. */ + &xC2T2 ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvC3T2, + "3-2", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C3T2_PRIO, + &xC3T2 ); + + // This task is supposed to be sporadic + xTaskCreate( prvC3T1, + "async_3-1", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C3T1_PRIO, + &xC3T1 ); + + xTaskCreate( prvC2T3, + "2-3", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C2T3_PRIO, + &xC2T3 ); + + xTaskCreate( prvC1T4, + "1-4", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C1T4_PRIO, + &xC1T4 ); + + xTaskCreate( prvC1T1, + "1-1", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C1T1_PRIO, + &xC1T1 ); + + xTaskCreate( prvC1T2, + "1-2", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C1T2_PRIO, + &xC1T2 ); + + xTaskCreate( prvC3T3, + "3-3", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C3T3_PRIO, + &xC3T3 ); + + xTaskCreate( prvC1T3, + "1-3", + configMINIMAL_STACK_SIZE, + NULL, + mainTASK_C1T3_PRIO, + &xC1T3 ); + + + /* Start the tasks and timer running. */ + // puts("Start scheduler"); + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + * line will never be reached. If the following line does execute, then + * there was insufficient FreeRTOS heap memory available for the Idle and/or + * timer tasks to be created. See the memory management section on the + * FreeRTOS web site for more details on the FreeRTOS heap + * http://www.freertos.org/a00111.html. */ + for( ; ; ) + { + } +} + +// Chain2: 31 -> 78 -> 400 +static void prvC2T1( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 100 / portTICK_PERIOD_MS; + int period_counter = 2; + for( ;; ){ + WCET_END({if (--period_counter==0) {puts("End");}}) // Debugging + // Actions -------------------------------------- + // Exectime: f(x) = x + // Output: g(x) = x % 2 + volatile uint16_t x = fuzz_short_next(); + DEBUG_WCET(x=48940;) + WCET_CLAMP(x, 0, 48940, TASK_C2T1_MESSAGE) + WCET_END({trigger_Qemu_break();}) + xTaskNotify(xC2T2, DEBUG_VAL(x % 2, 1), eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );}// Wait for the next cycle. +} + +// Chain2: 31 -> 78 -> 400 +static void prvC2T2( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; + for( ;; ){ + // Actions -------------------------------------- + // Exectime: f(x,y) = c + y*20000 + rng(x)*50000 + // Output: g(x,y) = y * (x % 4) + uint16_t x = fuzz_short_next(); + int y = ulTaskNotifyTake(pdTRUE, 0); + volatile int torun = 6035; + if (y > 0) { + torun += 20000; + } + if (DEBUG_VAL(CHANCE_1_IN_POWOF2(x, 5), 1)) { + torun += 50000; + } + WCET_CLAMP(torun, 0, 76035, TASK_C2T2_MESSAGE) + xTaskNotify(xC2T3, DEBUG_VAL(y * (x % 4), 2), eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +// Chain2: 31 -> 78 -> 400 +static void prvC2T3( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 2 / portTICK_PERIOD_MS; + for( ;; ){ + // Actions -------------------------------------- + // Exectime: f(x,y) = rng(x)*y*c or (rng(x) % 1000) + uint32_t x = fuzz_long_next(); + int y = ulTaskNotifyTake(pdTRUE, 0); + volatile int torun = 0; + if (y == 2 && DEBUG_VAL(CHANCE_1_IN_POWOF2(x, 2), 1)) { + torun = 1765; + } else { + torun = RNG_FROM(x) % 1000; + DEBUG_WCET(torun=999;) + } + WCET_CLAMP(torun, 0, 1765, TASK_C2T3_MESSAGE) + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +//================================================================== + +// Chain3: 397 -> 90 -> 1107 +static void prvC3T1( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 1 / portTICK_PERIOD_MS; + for( ;; ){ + // Exectime: f(x) = x + // Output: g(x) = x % 2 + volatile uint16_t x = fuzz_short_next(); + DEBUG_WCET(x=5830;) + WCET_CLAMP(x, 0, 5830, TASK_C3T1_MESSAGE); + xTaskNotify(xC3T2, DEBUG_VAL(x & 0x1, 0), eSetValueWithOverwrite); + // 3 different activation strategies ------------- + // activate sporadically from interrupts +#ifdef INTERRUPT_ACTIVATION + ulTaskNotifyTake(pdTRUE,portMAX_DELAY); +#else + // activate with worst possible frequency (700us, but tick resolution is too low) + vTaskDelayUntil( &xLastWakeTime, xFrequency ); +#endif + // wait pseudo random many ticks + // vTaskDelayUntil( &xLastWakeTime, CLAMP(RNG, 1, 100) / portTICK_PERIOD_MS ); + } +} + +// Chain3: 397 -> 90 -> 1107 +static void prvC3T2( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 2 / portTICK_PERIOD_MS; + for( ;; ){ + // char buf[400]; + // vTaskList(buf); + // puts(buf); + // Actions -------------------------------------- + // Exectime: f(x) = c + x + // Output: g(x) = x % 4 + int y = ulTaskNotifyTake(pdTRUE, 0); + volatile uint16_t x = fuzz_short_next(); + DEBUG_WCET(x=20048;) + int torun = 0; + if (y) { + torun = CLAMP(x, 5000, 10000); + } else { + torun = CLAMP(x, 0, 20045); + } + WCET_CLAMP(torun, 0, 20045, TASK_C3T2_MESSAGE) + xTaskNotify(xC3T3, DEBUG_VAL(x % 4, 0), eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +// Chain3: 397 -> 90 -> 1107 +static void prvC3T3( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 50 / portTICK_PERIOD_MS; + for( ;; ){ + // Actions -------------------------------------- + // Exectime: f(x) = c - x*y + volatile uint16_t x = fuzz_short_next(); + DEBUG_WCET(x=0;) + int y = ulTaskNotifyTake(pdTRUE, 0); + int torun = 76865-((int)x)*y; + WCET_CLAMP(torun, 10000, 76865, TASK_C3T3_MESSAGE) + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +//================================================================== + +// Chain1: 579 -> 1009 -> 1129 -> 416 +static void prvC1T1( void * pvParameters ) { + // int period = 5; + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; + for( ;; ){ + // if (--period==0) {puts("End");} // Debugging Marker + // Actions -------------------------------------- + // Exectime: f(x) = x>>8 & 0x0fff + // Output: g(x) = x % 8 + uint32_t x = fuzz_long_next(); + volatile int torun = (x>>8) & 0x0fff; + DEBUG_WCET(torun = 0x0fff;) + WCET_CLAMP(torun, 500, 2460, TASK_C1T1_MESSAGE) + xTaskNotify(xC1T2, DEBUG_VAL(x % 8, 0), eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +// Chain1: 579 -> 1009 -> 1129 -> 416 +static void prvC1T2( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; + for( ;; ){ + // Actions -------------------------------------- + // Exectime: f(x,y) = if x%8 == y ? 40000+x : x (<40k) + // Output: g(x) = x % 8 == y + uint16_t x = fuzz_short_next(); + int y = ulTaskNotifyTake(pdTRUE, 0); + volatile int torun = 0; + if (x % 8 == y) { + torun = 40000 + x; + } else { + torun = CLAMP(x, 0, 40000); + } + DEBUG_WCET(torun = 51485;) + WCET_CLAMP(torun, 0, 51485, TASK_C1T2_MESSAGE) + xTaskNotify(xC1T3, DEBUG_VAL(x % 8 == y, 1), eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +// Chain1: 579 -> 1009 -> 1129 -> 416 +static void prvC1T3( void * pvParameters ) { + int period_counter = 2; + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; + for( ;; ){ + // if (--period_counter==0) {puts("End");} + // Actions -------------------------------------- + // Exectime: f(x,y) = if y && rng(x) ? c1+x : c2+x + // Output: g(x) = y && rng(x) + // longmax - shortmax: 39505 + // most likely long case, which causes a short case in next task + volatile uint32_t x = (uint32_t)fuzz_short_next(); + int y = ulTaskNotifyTake(pdTRUE, 0); + DEBUG_WCET( + static char flag=0; + if (flag++ == 0 | flag == 5 | flag == 8 | flag == 9) {x = 65529;} + else {x = 0xffff;} + ) + volatile int do_short_run = (y + CHANCE_1_IN_POWOF2(x, 5)) == 1; // XOR + int torun = 0; + if (do_short_run > 0) { + torun = 40000 + x; + } else { + torun = 80000 + x; + } + WCET_CLAMP(torun, 0, 145040, TASK_C1T3_MESSAGE) + xTaskNotify(xC1T4, do_short_run, eSetValueWithOverwrite); + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +// Chain1: 579 -> 1009 -> 1129 -> 416 +static void prvC1T4( void * pvParameters ) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; + for( ;; ){ + // Actions -------------------------------------- + // Exectime: f(x,y) = if y ? c1+2*x : c2-x + // longmax - shortmax: 76955 + volatile uint32_t x = (uint32_t)fuzz_short_next(); + int y = ulTaskNotifyTake(pdTRUE, 0); + volatile int torun = 0; + if (y) { + DEBUG_WCET(x=0xffff;) + torun = x*3; + } else { + DEBUG_WCET(x=0;) + torun = 50000 - CLAMP_CEILING(x, 50000); + } + WCET_CLAMP(torun, 10000, 126955, TASK_C1T4_MESSAGE) + // --------------------------------------------- + vTaskDelayUntil( &xLastWakeTime, xFrequency );} +} + +void vWatersIdleFunction() { + for (int i; i<1000; i++) { + puts("0 "); + } +} + +void isr_starter( void ) +{ + puts("Interrupt"); + if (prvC3T1) { + vTaskNotifyGiveFromISR(xC3T1, NULL); + } +} + +/*-----------------------------------------------------------*/